From e21d2fd63d42c644289c70065b4d305042e6447a Mon Sep 17 00:00:00 2001 From: Hawkynt Date: Sat, 29 Aug 2026 09:25:34 +0200 Subject: [PATCH 1/3] + one CI run per pull request at a time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pushing again while checks are running now supersedes them. Without it the superseded run kept a runner busy: a handful of quick force-pushes left a dozen doomed runs queued ahead of the one that mattered, and every other branch starved behind them. Pushes to main keep their own run — each commit there deserves a verdict. --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71333055a..7f6536f08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,15 @@ on: # releases run the exact same test matrix as per-PR CI. workflow_call: {} +# One run per pull request at a time. Pushing again while checks are running +# supersedes them, and without this the old run keeps a runner busy: a handful +# of quick force-pushes left a dozen doomed runs queued ahead of the one that +# mattered, and everything behind them starved. Pushes to main are left alone — +# each commit there deserves its own verdict. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + # Force JavaScript-based actions to run on Node 24 instead of the deprecated Node 20 ahead of # the 2026-06-16 hard cutover, until we bump each action to a Node-24-native major version. env: From 71708c1877d711389ccd0c6b688c6e4d448cd7b8 Mon Sep 17 00:00:00 2001 From: Hawkynt Date: Sat, 29 Aug 2026 09:36:01 +0200 Subject: [PATCH 2/3] # main's package API references matched no assembly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merging two writers whose references had been generated against an older main left the four package READMEs describing a main that no longer existed. The check runs on every pull request, so every pull request failed it, whatever it changed — this branch touches one workflow file and still failed. --- Compression.Core/README.md | 7474 +--------- Hawkynt.FileFormats.Archives/README.md | 14286 +------------------- Hawkynt.FileFormats.Audio/README.md | 1667 +-- Hawkynt.FileFormats.FileSystems/README.md | 10066 +------------- 4 files changed, 4 insertions(+), 33489 deletions(-) diff --git a/Compression.Core/README.md b/Compression.Core/README.md index 0133799ca..17ae6fbcd 100644 --- a/Compression.Core/README.md +++ b/Compression.Core/README.md @@ -204,7479 +204,7 @@ Use the concrete version you intend to consume; this document does not predict a -### Namespace `Compression.Core.BitIO` - -[`BitBuffer`](#bitbuffer) · [`BitBuffer`](#bitbuffertorder) · [`BitOrder`](#bitorder) · [`BitReader`](#bitreader) · [`BitReader`](#bitreadertorder) · [`BitWriter`](#bitwriter) · [`BitWriter`](#bitwritertorder) · [`IBitOrder`](#ibitorder) · [`LsbBitOrder`](#lsbbitorder) · [`MsbBitOrder`](#msbbitorder) - -#### `BitBuffer` - -Non-generic `BitBuffer` for callers that select bit order at runtime. Delegates to a `BitBuffer` internally. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitBuffer` | `BitBuffer(Stream stream, BitOrder bitOrder = 0)` | Initializes a new `BitBuffer` over the specified stream. | -| `BitsAvailable` | `int BitsAvailable { get; }` | Gets the number of bits currently available. | -| `AlignToByte` | `void AlignToByte()` | Aligns to the next byte boundary. | -| `DropBits` | `void DropBits(int count)` | Drops `count` bits. | -| `EnsureBits` | `bool EnsureBits(int count)` | Ensures at least `count` bits are available. | -| `PeekBits` | `uint PeekBits(int count)` | Peeks at `count` bits without consuming. | -| `ReadBits` | `uint ReadBits(int count)` | Reads `count` bits, consuming them. | - -#### `BitBuffer` - -Buffered bit reader with lookahead (peek/drop) capability. Uses a ulong accumulator for fast multi-bit operations with up to 56 bits of lookahead. Generic on `TOrder` so the JIT monomorphizes each bit-order path — zero branch overhead in hot loops. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitBuffer` | `BitBuffer(Stream stream)` | Initializes a new `BitBuffer` over the specified stream. | -| `BitsAvailable` | `int BitsAvailable { get; }` | Gets the number of bits currently available in the buffer. | -| `AlignToByte` | `void AlignToByte()` | Aligns to the next byte boundary by dropping remaining bits in the current byte. | -| `DropBits` | `void DropBits(int count)` | Drops (consumes) `count` bits from the buffer. | -| `EnsureBits` | `bool EnsureBits(int count)` | Ensures at least `count` bits are available in the buffer. | -| `PeekBits` | `uint PeekBits(int count)` | Peeks at `count` bits without consuming them. | -| `ReadBits` | `uint ReadBits(int count)` | Reads `count` bits from the buffer, consuming them. | - -#### `BitOrder` - -Specifies the order in which bits are read from or written to a byte. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `LsbFirst` | `0` | Least significant bit first. Used by Deflate, ZIP, GZIP, PNG. | -| `MsbFirst` | `1` | Most significant bit first. Used by JPEG, bzip2, many legacy formats. | - -#### `BitReader` - -Non-generic `BitReader` for callers that select bit order at runtime. Delegates to a `BitReader` internally. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitReader` | `BitReader(Stream stream, BitOrder bitOrder = 0)` | Initializes a new `BitReader` over the specified stream. | -| `BitsInBuffer` | `int BitsInBuffer { get; }` | Gets the number of bits remaining in the current byte buffer. | -| `AlignToByte` | `void AlignToByte()` | Aligns to the next byte boundary. | -| `ReadBit` | `int ReadBit()` | Reads a single bit from the stream. | -| `ReadBits` | `uint ReadBits(int count)` | Reads multiple bits from the stream. | - -#### `BitReader` - -Reads individual bits and multi-bit values from a stream. Generic on `TOrder` so the JIT monomorphizes each bit-order path — zero branch overhead in hot loops. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitReader` | `BitReader(Stream stream)` | Initializes a new `BitReader` over the specified stream. | -| `BitsInBuffer` | `int BitsInBuffer { get; }` | Gets the number of bits remaining in the current byte buffer. | -| `AlignToByte` | `void AlignToByte()` | Discards any remaining bits in the current byte, aligning to the next byte boundary. | -| `ReadBit` | `int ReadBit()` | Reads a single bit from the stream. | -| `ReadBits` | `uint ReadBits(int count)` | Reads multiple bits from the stream. | - -#### `BitWriter` - -Non-generic `BitWriter` for callers that select bit order at runtime. Delegates to a `BitWriter` internally. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitWriter` | `BitWriter(Stream stream, BitOrder bitOrder = 0)` | Initializes a new `BitWriter` over the specified stream. | -| `BitsInBuffer` | `int BitsInBuffer { get; }` | Gets the number of bits currently buffered. | -| `FlushBits` | `void FlushBits()` | Flushes any remaining buffered bits. | -| `WriteBit` | `void WriteBit(int bit)` | Writes a single bit. | -| `WriteBits` | `void WriteBits(uint value, int count)` | Writes multiple bits. | - -#### `BitWriter` - -Writes individual bits and multi-bit values to a stream. Generic on `TOrder` so the JIT monomorphizes each bit-order path — zero branch overhead in hot loops. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitWriter` | `BitWriter(Stream stream)` | Initializes a new `BitWriter` over the specified stream. | -| `BitsInBuffer` | `int BitsInBuffer { get; }` | Gets the number of bits currently buffered. | -| `FlushBits` | `void FlushBits()` | Flushes any remaining buffered bits to the stream, padding with zero bits if needed. | -| `WriteBit` | `void WriteBit(int bit)` | Writes a single bit to the stream. | -| `WriteBits` | `void WriteBits(uint value, int count)` | Writes multiple bits to the stream. | - -#### `IBitOrder` - -Static-abstract strategy for bit ordering. Implement as a zero-size struct so generic specialization eliminates all branching at JIT time. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AccumulateBits` | `static uint AccumulateBits(uint result, int bit, int index)` | Accumulates a decoded bit into `result` at position `index`. | -| `Drop` | `static ulong Drop(ulong buffer, int bitsInBuffer, int count)` | Drops `count` bits from the accumulator. | -| `ExtractBit` | `static ValueTuple ExtractBit(int buffer)` | Extracts a single bit from the read byte-buffer and advances. | -| `InsertByte` | `static ulong InsertByte(ulong buffer, int bitsInBuffer, int b)` | Inserts a byte into the read accumulator. | -| `Peek` | `static uint Peek(ulong buffer, int bitsInBuffer, int count)` | Peeks `count` bits from the accumulator without consuming. | -| `PlaceBit` | `static int PlaceBit(int buffer, int bitsInBuffer, int bit)` | Places a single bit into the write byte-buffer. | -| `WriteBitIndex` | `static int WriteBitIndex(int count, int index)` | Returns the bit shift for the `index`-th bit during multi-bit write of `count` bits. | - -#### `LsbBitOrder` - -LSB-first bit ordering. Used by Deflate, ZIP, GZIP, PNG. Zero-size struct — no runtime cost. - -Implements `IBitOrder`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AccumulateBits` | `static uint AccumulateBits(uint result, int bit, int index)` | | -| `Drop` | `static ulong Drop(ulong buffer, int bitsInBuffer, int count)` | | -| `ExtractBit` | `static ValueTuple ExtractBit(int buffer)` | | -| `InsertByte` | `static ulong InsertByte(ulong buffer, int bitsInBuffer, int b)` | | -| `Peek` | `static uint Peek(ulong buffer, int bitsInBuffer, int count)` | | -| `PlaceBit` | `static int PlaceBit(int buffer, int bitsInBuffer, int bit)` | | -| `WriteBitIndex` | `static int WriteBitIndex(int count, int index)` | | - -#### `MsbBitOrder` - -MSB-first bit ordering. Used by JPEG, bzip2, many legacy formats. Zero-size struct — no runtime cost. - -Implements `IBitOrder`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AccumulateBits` | `static uint AccumulateBits(uint result, int bit, int index)` | | -| `Drop` | `static ulong Drop(ulong buffer, int bitsInBuffer, int count)` | | -| `ExtractBit` | `static ValueTuple ExtractBit(int buffer)` | | -| `InsertByte` | `static ulong InsertByte(ulong buffer, int bitsInBuffer, int b)` | | -| `Peek` | `static uint Peek(ulong buffer, int bitsInBuffer, int count)` | | -| `PlaceBit` | `static int PlaceBit(int buffer, int bitsInBuffer, int bit)` | | -| `WriteBitIndex` | `static int WriteBitIndex(int count, int index)` | | - -### Namespace `Compression.Core.BuildingBlocks` - -[`DoubleSpaceCompressor`](#doublespacecompressor) · [`DriveSpaceCompressor`](#drivespacecompressor) - -#### `DoubleSpaceCompressor` - -Clean-room port of the Microsoft DoubleSpace (MS-DOS 6.0 / 6.2) "JM" LZ77 compression algorithm used by the DBLS CVF format. The algorithm is an LSB-first variable-bit-length LZ77 with these tokens: Literal — 1-bit flag `0` followed by 8 bits of raw byte value.Match — 1-bit flag `1` followed by: Length — 2-bit code: `00`=2, `01`=3, `10`=4, `11`=extended. Extended reads 6 more bits — if all ones (63) then 8 further bits are added to a base of 68, giving a maximum length of `MaxMatchLength`.Distance — 2-bit class selector followed by class-width bits: class 0 = 6 bits (1..64), class 1 = 8 bits (65..320), class 2 = 12 bits (321..4416), class 3 = 13 bits (4417..12608). DoubleSpace caps at 4096 so class 3 is never emitted. The stream is prefixed with a 4-byte little-endian original-size header so the decoder knows exactly how many bytes to emit (no end-of-block marker is required). Although the on-disk DoubleSpace CVF format uses a separate 2-byte sector header to carry the stored/compressed flag and compressed size, that header is NOT this building block's concern — the CVF writer wraps the output with its own framing. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceCompressor` | `DoubleSpaceCompressor()` | Creates a compressor using the default DBLS window (4 KiB). | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `CompressWithWindow` | `static byte[] CompressWithWindow(ReadOnlySpan data, int maxDistance)` | Compresses `data` with an explicit sliding-window cap. Shared entry point used by both `DoubleSpaceCompressor` and `DriveSpaceCompressor`, and by the DoubleSpace CVF writer when it needs direct access to a specific window size. | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressStream` | `static byte[] DecompressStream(ReadOnlySpan data)` | Decompresses a complete DoubleSpace/DriveSpace BB stream (4-byte LE original-size header followed by the LSB-first token bit stream). The same decoder handles both variants since they share the token grammar. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DriveSpaceCompressor` - -Clean-room port of the Microsoft DriveSpace (MS-DOS 6.22) "LZ" compression algorithm used by the DVRS CVF format. DriveSpace uses the same token grammar as `DoubleSpaceCompressor` but doubles the sliding-window size to 8 KiB, enabling the class-3 distance code (4417..8192 effective range). See `DoubleSpaceCompressor` for the detailed bit-stream layout. The MS-DOS 7 (Win 95 OSR2) DriveSpace 3.0 variant uses a different block-level compression engine and is NOT produced by this building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DriveSpaceCompressor` | `DriveSpaceCompressor()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Checksums` - -[`Adler32`](#adler32) · [`Blake2b`](#blake2b) · [`Crc16`](#crc16) · [`Crc16Ccitt`](#crc16ccitt) · [`Crc32`](#crc32) · [`Crc64`](#crc64) · [`IChecksum`](#ichecksum) · [`Md5`](#md5) · [`ReedSolomon`](#reedsolomon) · [`Sha1`](#sha1) · [`Sha256`](#sha256) · [`XxHash32`](#xxhash32) · [`XxHash64`](#xxhash64) - -#### `Adler32` - -Adler-32 checksum as used by zlib, with Nmax optimization and SIMD vectorization. - -Implements `IChecksum`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Adler32` | `Adler32()` | | -| `Value` | `uint Value { get; }` | | -| `Compute` | `static uint Compute(ReadOnlySpan data)` | Computes the Adler-32 of the given data in a single call. | -| `Reset` | `void Reset()` | | -| `Update` | `void Update(ReadOnlySpan data)` | | -| `Update` | `void Update(byte b)` | | - -#### `Blake2b` - -BLAKE2b cryptographic hash function (RFC 7693). Produces digests of 1–64 bytes (default 32). Operates on 64-bit words and is optimised for 64-bit platforms. Provides both batch (`Compute`) and incremental (`Update`/`Finish`) modes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Blake2b` | `Blake2b(int hashSize = 32)` | Initializes a new `Blake2b` instance. | -| `DefaultHashSize` | `const int DefaultHashSize` | Default hash size in bytes (256 bits). | -| `MaxHashSize` | `const int MaxHashSize` | Maximum hash size in bytes (512 bits). | -| `Compute` | `static byte[] Compute(ReadOnlySpan data, int hashSize = 32)` | Computes a BLAKE2b hash over the given data in one shot. | -| `Finish` | `byte[] Finish()` | Finalises the hash and returns the digest. | -| `Reset` | `void Reset()` | Resets the hash state for reuse. | -| `Update` | `void Update(ReadOnlySpan data)` | Feeds data into the hash. | - -#### `Crc16` - -Table-driven CRC-16 implementation with configurable polynomial. - -Implements `IChecksum`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Crc16` | `Crc16(ushort polynomial = 40961, ushort initialValue = 0)` | Initializes a new `Crc16` with the specified polynomial. | -| `Arc` | `const ushort Arc` | CRC-16/ARC polynomial (reflected form). | -| `Value` | `uint Value { get; }` | | -| `Compute` | `static ushort Compute(ReadOnlySpan data)` | Computes the CRC-16 of the given data using the ARC polynomial. | -| `Reset` | `void Reset()` | | -| `Update` | `void Update(ReadOnlySpan data)` | | -| `Update` | `void Update(byte b)` | | - -#### `Crc16Ccitt` - -Table-driven CRC-16/CCITT implementation (non-reflected form). Polynomial 0x1021, MSB-first. Used by ECMA-167 / UDF descriptor tags, XMODEM (init=0x0000) and CCITT-FALSE (init=0xFFFF) variants. - -Implements `IChecksum`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Crc16Ccitt` | `Crc16Ccitt(ushort initialValue = 0)` | Initializes a new `Crc16Ccitt` with the specified initial value. | -| `Polynomial` | `const ushort Polynomial` | CRC-16/CCITT polynomial (non-reflected form). | -| `Value` | `uint Value { get; }` | | -| `Compute` | `static ushort Compute(ReadOnlySpan data, ushort initial = 0)` | Computes the CRC-16/CCITT of the given data. | -| `Reset` | `void Reset()` | | -| `Update` | `void Update(ReadOnlySpan data)` | | -| `Update` | `void Update(byte b)` | | - -#### `Crc32` - -Table-driven CRC-32 implementation with configurable polynomial, slicing-by-4 acceleration, and hardware intrinsics for SSE4.2 (CRC-32C), PCLMULQDQ (IEEE), and ARM CRC32 when available. - -Implements `IChecksum`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Crc32` | `Crc32(uint polynomial = 3988292384)` | Initializes a new `Crc32` with the specified polynomial. | -| `Castagnoli` | `const uint Castagnoli` | Castagnoli (CRC-32C) polynomial. | -| `Ieee` | `const uint Ieee` | Standard IEEE 802.3 polynomial (used by ZIP, GZIP, PNG, etc.). | -| `Value` | `uint Value { get; }` | | -| `Compute` | `static uint Compute(ReadOnlySpan data)` | Computes the CRC-32 of the given data in a single call using the IEEE polynomial. | -| `Compute` | `static uint Compute(ReadOnlySpan data, uint polynomial)` | Computes the CRC-32 of the given data with the specified polynomial. | -| `Reset` | `void Reset()` | | -| `Update` | `void Update(ReadOnlySpan data)` | | -| `Update` | `void Update(byte b)` | | - -#### `Crc64` - -Table-driven CRC-64 implementation with configurable polynomial and slicing-by-4 acceleration. - -Implements `IChecksum`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Crc64` | `Crc64(ulong polynomial = 14514072000185962306)` | Initializes a new `Crc64` with the specified polynomial. | -| `Ecma182` | `const ulong Ecma182` | ECMA-182 polynomial used by the XZ format. | -| `Value64` | `ulong Value64 { get; }` | Gets the full 64-bit CRC value. | -| `Compute` | `static ulong Compute(ReadOnlySpan data)` | Computes the CRC-64 of the given data in a single call using the ECMA-182 polynomial. | -| `Reset` | `void Reset()` | | -| `Update` | `void Update(ReadOnlySpan data)` | | -| `Update` | `void Update(byte b)` | | - -#### `IChecksum` - -Common interface for checksum algorithms. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Value` | `uint Value { get; }` | Gets the current checksum value. | -| `Reset` | `void Reset()` | Resets the checksum to its initial state. | -| `Update` | `void Update(ReadOnlySpan data)` | Updates the checksum with a span of bytes. | -| `Update` | `void Update(byte b)` | Updates the checksum with a single byte. | - -#### `Md5` - -MD5 hash function (RFC 1321). Produces 16-byte (128-bit) message digests. Used for legacy key derivation in formats like SQX. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compute` | `static byte[] Compute(ReadOnlySpan data)` | Computes the MD5 hash of the given data. | - -#### `ReedSolomon` - -Reed-Solomon encoder/decoder over GF(2^8) using primitive polynomial 0x11D (x^8 + x^4 + x^3 + x^2 + 1). Used for recovery records in archive formats. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ReedSolomon` | `ReedSolomon(int dataShards, int parityShards)` | Creates a Reed-Solomon codec with the specified number of data and parity shards. | -| `Encode` | `byte[][] Encode(byte[][] data)` | Encodes data shards to produce parity shards. | -| `Reconstruct` | `bool Reconstruct(byte[][] shards)` | Reconstructs missing data shards using surviving data and parity shards. | - -#### `Sha1` - -FIPS 180-4 SHA-1 cryptographic hash function. Provides both batch (`Compute`) and incremental (`Update`/`Finish`) modes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Sha1` | `Sha1()` | Initializes a new `Sha1` instance. | -| `HashSize` | `const int HashSize` | The size of the SHA-1 hash output in bytes (20 bytes / 160 bits). | -| `Hash` | `byte[] Hash { get; }` | Gets the computed hash. Available after `Finish` has been called. | -| `Clone` | `Sha1 Clone()` | Creates a copy of the current hasher state, allowing independent continuation. | -| `Compute` | `static byte[] Compute(ReadOnlySpan data)` | Computes the SHA-1 hash of the given data in a single call. | -| `Finish` | `void Finish()` | Finalizes the hash computation. | -| `Reset` | `void Reset()` | Resets the hasher to its initial state. | -| `Update` | `void Update(ReadOnlySpan data)` | Updates the hash with additional data. | - -#### `Sha256` - -FIPS 180-4 SHA-256 cryptographic hash function. Provides both batch (`Compute`) and incremental (`Update`/`Finish`) modes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Sha256` | `Sha256()` | Initializes a new `Sha256` instance. | -| `HashSize` | `const int HashSize` | The size of the SHA-256 hash output in bytes (32 bytes / 256 bits). | -| `Hash` | `byte[] Hash { get; }` | Gets the computed hash. Available after `Finish` has been called. Returns an empty array before finalization. | -| `Compute` | `static byte[] Compute(ReadOnlySpan data)` | Computes the SHA-256 hash of the given data in a single call. | -| `Finish` | `void Finish()` | Finalizes the hash computation. After calling this method, the `Hash` property contains the 32-byte SHA-256 digest. | -| `Reset` | `void Reset()` | Resets the hasher to its initial state. | -| `Update` | `void Update(ReadOnlySpan data)` | Updates the hash with additional data. | - -#### `XxHash32` - -xxHash 32-bit non-cryptographic hash function. Provides both batch (`Compute`) and incremental (`Update`/`Value`) modes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XxHash32` | `XxHash32(uint seed = 0)` | Initializes a new `XxHash32` with the specified seed. | -| `Value` | `uint Value { get; }` | Gets the current hash value. This finalizes the accumulated state without modifying it. | -| `Compute` | `static uint Compute(ReadOnlySpan data, uint seed = 0)` | Computes the xxHash32 of the given data in a single call. | -| `Reset` | `void Reset()` | Resets the hasher to its initial state. | -| `Update` | `void Update(ReadOnlySpan data)` | Updates the hash with additional data. | - -#### `XxHash64` - -xxHash 64-bit non-cryptographic hash function. Provides both batch (`Compute`) and incremental (`Update`/`Value`) modes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XxHash64` | `XxHash64(ulong seed = 0)` | Initializes a new `XxHash64` with the specified seed. | -| `Value` | `ulong Value { get; }` | Gets the current hash value. This finalizes the accumulated state without modifying it. | -| `Compute` | `static ulong Compute(ReadOnlySpan data, ulong seed = 0)` | Computes the xxHash64 of the given data in a single call. | -| `Reset` | `void Reset()` | Resets the hasher to its initial state. | -| `Update` | `void Update(ReadOnlySpan data)` | Updates the hash with additional data. | - -### Namespace `Compression.Core.Crypto` - -[`AesCryptor`](#aescryptor) · [`Blowfish`](#blowfish) · [`KeyDerivation`](#keyderivation) - -#### `AesCryptor` - -AES-256 encryption and decryption wrapper supporting CBC and CTR modes. Uses the system-provided AES implementation. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecryptCbcNoPaddingAny` | `static byte[] DecryptCbcNoPaddingAny(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Decrypts data using AES-CBC with no padding. Accepts 16-byte (AES-128) or 32-byte (AES-256) keys. | -| `DecryptCbcNoPadding` | `static byte[] DecryptCbcNoPadding(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Decrypts data using AES-256-CBC with no padding. Input length must be a multiple of 16 bytes. | -| `DecryptCbc` | `static byte[] DecryptCbc(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Decrypts data using AES-256-CBC with PKCS7 padding. | -| `EncryptCbcNoPaddingAny` | `static byte[] EncryptCbcNoPaddingAny(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Encrypts data using AES-CBC with no padding. Accepts 16-byte (AES-128) or 32-byte (AES-256) keys. | -| `EncryptCbcNoPadding` | `static byte[] EncryptCbcNoPadding(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Encrypts data using AES-256-CBC with no padding. Input length must be a multiple of 16 bytes. | -| `EncryptCbc` | `static byte[] EncryptCbc(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan iv)` | Encrypts data using AES-256-CBC with PKCS7 padding. | -| `TransformCtr` | `static byte[] TransformCtr(ReadOnlySpan data, ReadOnlySpan key, ReadOnlySpan nonce)` | Encrypts or decrypts data using AES-256-CTR mode. CTR mode is symmetric — the same operation encrypts and decrypts. | - -#### `Blowfish` - -Blowfish symmetric block cipher. 64-bit block size, 1–56 byte key, 16-round Feistel network. Initial P-array and S-box values are the hexadecimal digits of pi. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Blowfish` | `Blowfish(ReadOnlySpan key)` | Initializes a new `Blowfish` instance with the given key. | -| `DecryptCbc` | `byte[] DecryptCbc(ReadOnlySpan data, ReadOnlySpan iv)` | Decrypts data using Blowfish-CBC with PKCS7 unpadding. | -| `Decrypt` | `void Decrypt(Span block)` | Decrypts an 8-byte block in-place (big-endian). | -| `EncryptCbc` | `byte[] EncryptCbc(ReadOnlySpan data, ReadOnlySpan iv)` | Encrypts data using Blowfish-CBC with PKCS7 padding. | -| `Encrypt` | `void Encrypt(Span block)` | Encrypts an 8-byte block in-place (big-endian). | - -#### `KeyDerivation` - -Key derivation functions for password-based encryption. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pbkdf2Sha1` | `static byte[] Pbkdf2Sha1(string password, ReadOnlySpan salt, int iterations, int keyLength)` | Derives a key using PBKDF2 with HMAC-SHA1. Used by older ZIP encryption and WinZip AE-1. | -| `Pbkdf2Sha256` | `static byte[] Pbkdf2Sha256(string password, ReadOnlySpan salt, int iterations, int keyLength)` | Derives a key using PBKDF2 with HMAC-SHA256. Used by ZIP AES encryption (WinZip AE-1/AE-2). | -| `Rar3DeriveKey` | `static ValueTuple Rar3DeriveKey(string password, ReadOnlySpan salt)` | Derives a 16-byte AES-128 key and 16-byte IV for RAR3/4 decryption. RAR3 iterates SHA-1 262144 times over (salt + password_utf16le + counter). | -| `Rar5DeriveKey` | `static byte[] Rar5DeriveKey(string password, ReadOnlySpan salt, int iterations)` | Derives a key using the RAR5 key derivation (PBKDF2-HMAC-SHA256 with specific parameters). | -| `SevenZipDeriveKey` | `static byte[] SevenZipDeriveKey(string password, ReadOnlySpan salt, int numCyclesPower)` | Derives a key using the 7z AES key derivation (SHA-256 iterated). 7z uses: key = SHA256^(2^numCyclesPower)(salt + password_utf16le) | - -### Namespace `Compression.Core.DataStructures` - -[`MinHeap`](#minheapt) · [`SlidingWindow`](#slidingwindow) - -#### `MinHeap` - -A binary min-heap for use in Huffman tree construction and similar algorithms. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MinHeap` | `MinHeap()` | | -| `Count` | `int Count { get; }` | Gets the number of elements in the heap. | -| `ExtractMin` | `T ExtractMin()` | Removes and returns the minimum element. | -| `Insert` | `void Insert(T item)` | Inserts an item into the heap. | -| `Peek` | `T Peek()` | Returns the minimum element without removing it. | - -#### `SlidingWindow` - -Circular buffer that supports byte-by-byte writing and distance/length copying (including overlapping copies where distance < length). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SlidingWindow` | `SlidingWindow(int windowSize)` | Initializes a new `SlidingWindow` with the specified capacity. | -| `Count` | `int Count { get; }` | Gets the number of bytes currently stored in the window. | -| `WindowSize` | `int WindowSize { get; }` | Gets the window capacity. | -| `CopyFromWindow` | `void CopyFromWindow(int distance, int length, Span output)` | Copies `length` bytes from a position `distance` bytes back in the window, writing each byte into the window as it is copied. Handles overlapping copies correctly (e.g., distance=1, length=10 repeats one byte 10 times). | -| `GetByte` | `byte GetByte(int distance)` | Gets the byte at the specified distance back from the current position. | -| `WriteByte` | `void WriteByte(byte value)` | Writes a single byte into the window. | -| `WriteBytes` | `void WriteBytes(ReadOnlySpan data)` | Writes a span of bytes into the window. | - -### Namespace `Compression.Core.Deflate` - -[`Deflate64BuildingBlock`](#deflate64buildingblock) · [`Deflate64Compressor`](#deflate64compressor) · [`Deflate64Constants`](#deflate64constants) · [`Deflate64Decompressor`](#deflate64decompressor) · [`DeflateBuildingBlock`](#deflatebuildingblock) · [`DeflateCompressionLevel`](#deflatecompressionlevel) · [`DeflateCompressor`](#deflatecompressor) · [`DeflateConstants`](#deflateconstants) · [`DeflateDecompressor`](#deflatedecompressor) · [`DeflateHuffmanTable`](#deflatehuffmantable) · [`DeflateLevelOption`](#deflateleveloption) · [`MsZipCompressor`](#mszipcompressor) · [`MsZipDecompressor`](#mszipdecompressor) · [`ZopfliBuildingBlock`](#zopflibuildingblock) - -#### `Deflate64BuildingBlock` - -Exposes the Deflate64 (Enhanced Deflate) algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Deflate64BuildingBlock` | `Deflate64BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Deflate64Compressor` - -Compresses data in the Deflate64 (Enhanced Deflate) format. Deflate64 extends DEFLATE with a 64 KB sliding window, distance codes 30-31 (up to 65536), and length code 285 representing lengths 3–65538 via 16 extra bits. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Deflate64Compressor` | `Deflate64Compressor(Stream output, DeflateCompressionLevel level = 6)` | Initializes a new `Deflate64Compressor` for streaming compression. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, DeflateCompressionLevel level = 6)` | Compresses data in one shot. | -| `Finish` | `void Finish()` | Writes the final block and flushes all remaining data. | -| `Write` | `void Write(ReadOnlySpan data)` | Buffers input data for compression. Emits blocks when the buffer is full. | - -#### `Deflate64Constants` - -Constants for Deflate64 (Enhanced Deflate) as used by ZIP method 9. Extends standard Deflate with a 64KB window and larger distance/length ranges. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DistanceAlphabetSize` | `const int DistanceAlphabetSize` | Number of distance symbols (0-31). | -| `LiteralLengthAlphabetSize` | `const int LiteralLengthAlphabetSize` | Number of literal/length symbols (0–285). | -| `MaxMatchLength` | `const int MaxMatchLength` | Maximum match length in Deflate64. | -| `WindowSize` | `const int WindowSize` | Sliding window size in bytes (64 KB). | -| `DistanceBase` | `static ReadOnlySpan DistanceBase { get; }` | Base distances for distance codes 0-31. Extends standard Deflate with codes 30-31 for distances up to 65536. | -| `DistanceExtraBits` | `static ReadOnlySpan DistanceExtraBits { get; }` | Extra bits for distance codes 0-31. | -| `LengthBase` | `static ReadOnlySpan LengthBase { get; }` | Base lengths for length codes 257-285. In Deflate64, code 285 has base 3 with 16 extra bits (range 3-65538). | -| `LengthExtraBits` | `static ReadOnlySpan LengthExtraBits { get; }` | Extra bits for length codes 257-285. In Deflate64, code 285 has 16 extra bits. | -| `GetDistanceCode` | `static int GetDistanceCode(int distance)` | Maps a match distance (1-65536) to the corresponding distance code (0-31). | -| `GetLengthCode` | `static int GetLengthCode(int length)` | Maps a match length (3–65538) to the corresponding literal/length code (257–285). Lengths 3–258 use codes 257–284 (same as standard Deflate). Lengths 259–65538 use code 285 (base 3 + 16 extra bits). | - -#### `Deflate64Decompressor` - -Decompresses data in the Deflate64 (Enhanced Deflate) format. Deflate64 extends DEFLATE with a 64 KB sliding window, two additional distance codes (30 and 31 with 14 extra bits each), and length code 285 representing lengths 3..65538 via 16 extra bits (instead of the fixed value 258 in standard Deflate). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Deflate64Decompressor` | `Deflate64Decompressor(Stream input)` | Initializes a new `Deflate64Decompressor` for streaming decompression. | -| `DecompressAll` | `byte[] DecompressAll()` | Decompresses all data from the stream. | -| `Decompress` | `int Decompress(byte[] output, int offset, int count)` | Decompresses data from the input stream into the provided buffer. Returns the number of bytes written. Returns 0 when decompression is complete. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressedData)` | Decompresses Deflate64 data in one shot. | - -#### `DeflateBuildingBlock` - -Exposes the raw DEFLATE algorithm (RFC 1951) as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeflateBuildingBlock` | `DeflateBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DeflateCompressionLevel` - -Specifies the compression level for the Deflate compressor. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No compression — emit uncompressed blocks. | -| `Fast` | `1` | Fast compression — static Huffman with shallow match finding. | -| `Default` | `6` | Default compression — dynamic Huffman with moderate match finding. | -| `Best` | `9` | Best compression — dynamic Huffman with deep match finding and lazy matching. | -| `Maximum` | `11` | Maximum compression — Zopfli-style iterative optimal parsing and block splitting. | - -#### `DeflateCompressor` - -Compresses data in the DEFLATE format (RFC 1951). - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeflateCompressor` | `DeflateCompressor(Stream output, DeflateCompressionLevel level = 6)` | Initializes a new `DeflateCompressor` for streaming compression. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, DeflateCompressionLevel level = 6)` | Compresses data in one shot. | -| `Finish` | `void Finish()` | Writes the final block and flushes all remaining data. | -| `Write` | `void Write(ReadOnlySpan data)` | Buffers input data for compression. Emits blocks when the buffer is full. | - -#### `DeflateConstants` - -Constants defined by RFC 1951 (DEFLATE Compressed Data Format). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockTypeDynamicHuffman` | `const int BlockTypeDynamicHuffman` | Block type: compressed with dynamic Huffman codes. | -| `BlockTypeStaticHuffman` | `const int BlockTypeStaticHuffman` | Block type: compressed with fixed Huffman codes. | -| `BlockTypeUncompressed` | `const int BlockTypeUncompressed` | Block type: uncompressed (no compression). | -| `CodeLengthAlphabetSize` | `const int CodeLengthAlphabetSize` | Number of code-length symbols (0–18). | -| `DistanceAlphabetSize` | `const int DistanceAlphabetSize` | Number of distance symbols (0–29). | -| `EndOfBlock` | `const int EndOfBlock` | Symbol for end of block in the literal/length alphabet. | -| `LiteralLengthAlphabetSize` | `const int LiteralLengthAlphabetSize` | Number of literal/length symbols (0–285). | -| `MaxBits` | `const int MaxBits` | Maximum bit length for literal/length and distance Huffman codes. | -| `MaxCodeLengthBits` | `const int MaxCodeLengthBits` | Maximum bit length for code-length Huffman codes. | -| `WindowSize` | `const int WindowSize` | Sliding window size in bytes (32 KB). | -| `CodeLengthOrder` | `static ReadOnlySpan CodeLengthOrder { get; }` | Permuted order for code-length code lengths in dynamic Huffman block headers. | -| `DistanceBase` | `static ReadOnlySpan DistanceBase { get; }` | Base distances for distance codes 0–29. | -| `DistanceExtraBits` | `static ReadOnlySpan DistanceExtraBits { get; }` | Extra bits for distance codes 0–29. | -| `LengthBase` | `static ReadOnlySpan LengthBase { get; }` | Base lengths for length codes 257–285. Index i corresponds to length code (257 + i). | -| `LengthExtraBits` | `static ReadOnlySpan LengthExtraBits { get; }` | Extra bits for length codes 257–285. Index i corresponds to length code (257 + i). | -| `GetDistanceCode` | `static int GetDistanceCode(int distance)` | Maps a match distance (1–32768) to the corresponding distance code (0–29). | -| `GetLengthCode` | `static int GetLengthCode(int length)` | Maps a match length (3–258) to the corresponding literal/length code (257–285). | -| `GetStaticDistanceLengths` | `static int[] GetStaticDistanceLengths()` | Returns the fixed distance code lengths as defined in RFC 1951 section 3.2.6. | -| `GetStaticLiteralLengths` | `static int[] GetStaticLiteralLengths()` | Returns the fixed literal/length code lengths as defined in RFC 1951 section 3.2.6. | - -#### `DeflateDecompressor` - -Decompresses data in the DEFLATE format (RFC 1951). - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeflateDecompressor` | `DeflateDecompressor(Stream input)` | Initializes a new `DeflateDecompressor` for streaming decompression. | -| `UnconsumedBytes` | `int UnconsumedBytes { get; }` | Gets the number of whole bytes buffered by the bit reader but not consumed by the decompressor. This is needed by container formats (e.g. gzip) to rewind the stream before reading a trailer. | -| `DecompressAll` | `byte[] DecompressAll()` | Decompresses all data from the stream. | -| `Decompress` | `int Decompress(byte[] output, int offset, int count)` | Decompresses data from the input stream into the provided buffer. Returns the number of bytes written. Returns 0 when decompression is complete. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressedData)` | Decompresses DEFLATE data in one shot. | - -#### `DeflateHuffmanTable` - -Huffman table for Deflate using bit-reversed (LSB-first) canonical codes. Supports single-level lookup-table decoding and encoding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeflateHuffmanTable` | `DeflateHuffmanTable(int[] codeLengths)` | Builds a Deflate Huffman table from code lengths. | -| `MaxCodeLength` | `int MaxCodeLength { get; }` | Gets the maximum code length in bits. | -| `CreateStaticDistanceTable` | `static DeflateHuffmanTable CreateStaticDistanceTable()` | Creates the static distance Huffman table for Deflate (BTYPE=1). | -| `CreateStaticLiteralTable` | `static DeflateHuffmanTable CreateStaticLiteralTable()` | Creates the static literal/length Huffman table for Deflate (BTYPE=1). | -| `DecodeSymbol` | `int DecodeSymbol(BitBuffer bitBuffer)` | Decodes a symbol from the bit buffer using lookup-table decoding. The bit buffer must be in LSB-first mode. | -| `GetCode` | `ValueTuple GetCode(int symbol)` | Gets the bit-reversed code and length for encoding a symbol. | - -#### `DeflateLevelOption` - -Resolves a `DeflateCompressionLevel` from a format's `FormatCreateOptions`. Shared by the Deflate-based stream formats (GZIP, Zlib) so their `Level` option is parsed identically. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Parse` | `static DeflateCompressionLevel Parse(FormatCreateOptions options)` | Resolves the requested level: the named `Level` string in `FormatSpecific` wins (matched case-insensitively against the enum names); otherwise a numeric `Level` (0–11) is mapped onto the nearest tier; failing both, `Default`. | - -#### `MsZipCompressor` - -Compresses data using the MSZIP format: 32 KB Deflate blocks each preceded by a two-byte "CK" signature (0x43, 0x4B). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | The uncompressed block size limit: 32 768 bytes. | -| `SignatureByte0` | `const byte SignatureByte0` | MSZIP block signature byte 0 ('C'). | -| `SignatureByte1` | `const byte SignatureByte1` | MSZIP block signature byte 1 ('K'). | -| `CompressBlocks` | `static List> CompressBlocks(ReadOnlySpan data, DeflateCompressionLevel level = 6)` | Splits `data` into raw (uncompressed) MSZIP blocks and returns the compressed byte counts for each block together with the full compressed output. Useful for CAB CFDATA record construction. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, DeflateCompressionLevel level = 6)` | Compresses `data` into MSZIP format. | - -#### `MsZipDecompressor` - -Decompresses data in the MSZIP format: a sequence of "CK"-prefixed Deflate blocks, each covering at most 32 768 uncompressed bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | The uncompressed block size limit: 32 768 bytes. | -| `DecompressBlock` | `static byte[] DecompressBlock(ReadOnlySpan block)` | Decompresses a single MSZIP block (including its "CK" prefix) and returns the uncompressed bytes. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int uncompressedSize = -1)` | Decompresses an MSZIP byte stream. | - -#### `ZopfliBuildingBlock` - -Exposes Zopfli-style compression as a benchmarkable building block. Drives `DeflateCompressor` at `Maximum`, which runs the iterative optimal-parsing/block-splitting search implemented in `ZopfliDeflate`. The output is standard RFC 1951 DEFLATE — smaller than the regular greedy/lazy DEFLATE building block on typical inputs, but decodable by any conforming DEFLATE reader, including `DeflateDecompressor`. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZopfliBuildingBlock` | `ZopfliBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Ace` - -[`AceBuildingBlock`](#acebuildingblock) · [`AceConstants`](#aceconstants) · [`AceDecoder`](#acedecoder) · [`AceEncoder`](#aceencoder) · [`AcePicFilter`](#acepicfilter) · [`AceSoundFilter`](#acesoundfilter) - -#### `AceBuildingBlock` - -Exposes the ACE compression algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceBuildingBlock` | `AceBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `AceConstants` - -Constants for the ACE compression algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompAce10` | `const int CompAce10` | Compression type: ACE 1.0 (LZ77 + Huffman). | -| `CompAce20` | `const int CompAce20` | Compression type: ACE 2.0 (blocked, multiple sub-modes). | -| `CompStore` | `const int CompStore` | Compression type: stored (no compression). | -| `DefaultDictBits` | `const int DefaultDictBits` | Default dictionary bits. | -| `LenSymbols` | `const int LenSymbols` | Length tree: 255 symbols for extended match lengths. | -| `LengthBase` | `static readonly int[] LengthBase` | Match length bases for symbols 257-283. | -| `LengthExtra` | `static readonly int[] LengthExtra` | Extra bits for match length symbols 257-283. | -| `MainSymbols` | `const int MainSymbols` | Main Huffman tree: 284 symbols (256 literals + 28 length codes). | -| `MaxDictBits` | `const int MaxDictBits` | Maximum dictionary bits. | -| `MinDictBits` | `const int MinDictBits` | Minimum dictionary bits. | -| `NumRepOffsets` | `const int NumRepOffsets` | Number of repeated offsets maintained. | -| `SymbolEndOfBlock` | `const int SymbolEndOfBlock` | Symbol 256: end of block marker. | -| `SymbolMatchBase` | `const int SymbolMatchBase` | Symbol range 257-282: match length base codes (length 2..28+). | -| `SymbolModeSwitch` | `const int SymbolModeSwitch` | Symbol 283: ACE 2.0 mode switch marker. | - -#### `AceDecoder` - -Decodes ACE 1.0 and 2.0 compressed data (LZ77 + dual Huffman trees). Instance-based: the sliding window and repeat offsets persist across calls for solid archive support. ACE 2.0 adds blocked sub-modes: LZ77, EXE (E8/E9), DELTA, SOUND, PIC. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceDecoder` | `AceDecoder(int dictBits = 15)` | Initializes a new `AceDecoder` with the specified dictionary size. | -| `DecodeBlock` | `static byte[] DecodeBlock(ReadOnlySpan compressed, int originalSize, int dictBits = 15, int compressionType = 1)` | Static convenience method for non-solid decoding (creates a fresh decoder). | -| `DecodeBlock` | `static byte[] DecodeBlock(byte[] compressed, int originalSize, int dictBits = 15, int compressionType = 1)` | Static convenience method for non-solid decoding (creates a fresh decoder). | -| `Decode` | `byte[] Decode(byte[] compressed, int originalSize, int compressionType = 1)` | Decompresses ACE data, preserving window state for subsequent solid calls. | - -#### `AceEncoder` - -Encodes data using ACE 1.0 or 2.0 compression (LZ77 + dual Huffman trees). Instance-based: the sliding window persists across calls for solid archive support. ACE 2.0 adds sub-mode switching: LZ77, EXE, DELTA, SOUND, PIC. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceEncoder` | `AceEncoder(int dictBits = 15)` | Initializes a new `AceEncoder` with the specified dictionary size. | -| `Encode20` | `byte[] Encode20(ReadOnlySpan data, int subMode = 0, int soundChannels = 1, int picWidth = 0, int picBytesPerPixel = 3)` | Compresses data using ACE 2.0 with a specified sub-mode applied as a preprocessing transform. | -| `EncodeBlock20` | `static byte[] EncodeBlock20(ReadOnlySpan data, int dictBits = 15, int subMode = 0, int soundChannels = 1, int picWidth = 0, int picBytesPerPixel = 3)` | Static convenience method for non-solid ACE 2.0 encoding. | -| `EncodeBlock` | `static byte[] EncodeBlock(ReadOnlySpan data, int dictBits = 15)` | Static convenience method for non-solid encoding (creates a fresh encoder). | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using the ACE 1.0 algorithm, preserving window state for subsequent solid calls. | - -#### `AcePicFilter` - -ACE 2.0 PIC sub-mode filter. Decorrelates image data using Paeth-style prediction based on left and above neighbor bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data, int stride = 0)` | Inverse transform: reconstructs pixels from prediction residuals. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int stride = 0)` | Forward transform: converts pixels to prediction residuals. | - -#### `AceSoundFilter` - -ACE 2.0 SOUND sub-mode filter. Decorrelates audio data using adaptive linear prediction with LMS weight updates. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data, int channels = 1)` | Inverse transform: reconstructs audio samples from prediction residuals. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int channels = 1)` | Forward transform: converts audio samples to prediction residuals. | - -### Namespace `Compression.Core.Dictionary.Aplib` - -[`AplibBuildingBlock`](#aplibbuildingblock) · [`AplibDialect`](#aplibdialect) - -#### `AplibBuildingBlock` - -aPLib — Jørgen Ibsen's byte-oriented LZ77 with an interleaved single-bit tag stream, used as the compression core of numerous Win32 PE packers (FSG 2.0, PECompact 2, RLPack, and others; ASPack is commonly listed here too but uses a Huffman-coded stream of its own). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AplibBuildingBlock` | `AplibBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int maxOutputSize)` | Decodes a bare aPLib stream (no size prefix) into at most `maxOutputSize` bytes, stopping at the end-of-stream marker. Exposed for packer handlers that carve an aPLib payload out of a PE/ELF image and know the original size (or an upper bound) from the packer header. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int maxOutputSize, AplibDialect dialect, out bool endMarkerHit, out int inputConsumed)` | As `DecompressRaw`, decoding the requested `dialect`. Packers that embed a hand-written aPLib depacker sometimes ship a simplified one; see `AplibDialect`. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int maxOutputSize, out bool endMarkerHit, out int inputConsumed)` | As `DecompressRaw`, additionally reporting whether decoding stopped at a genuine end-of-stream marker (`endMarkerHit`) versus running into the `maxOutputSize` cap, and how many input bytes were consumed (`inputConsumed`). Packer handlers that carve a payload at a guessed offset use the end-marker flag to reject false positives: a bare aPLib stream that terminates cleanly and consumes most of its input is far more likely to be a real payload than random section bytes that happen to decode without throwing. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `AplibDialect` - -Which aPLib bit-stream dialect a decoder should expect. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Standard` | `0` | Ibsen's aPLib as documented: the "10" token's γ-coded offset is biased by the last-was-match flag (−3 after a literal, −2 after a match) and the previous offset is reused only when the flag is clear and the γ value is exactly 2. | -| `NoLastWasMatch` | `1` | The simplified dialect emitted by packers whose in-stub depacker never tracks last-was-match: the γ offset is always biased by −3 and the reuse case always triggers at γ = 2. Streams differ from `Standard` the moment a normal match directly follows another match, so the two are not interchangeable. Observed in JDPack 1.x stubs (bit layout read off the packed samples' own depacker; see `JdpackExecutablePackerHandler`). | - -### Namespace `Compression.Core.Dictionary.Arj` - -[`ArjBuildingBlock`](#arjbuildingblock) · [`ArjDecoder`](#arjdecoder) · [`ArjEncoder`](#arjencoder) - -#### `ArjBuildingBlock` - -Exposes the ARJ compression algorithm as a benchmarkable building block. Uses method 1 (LZ77+Huffman with 26 KB window). Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjBuildingBlock` | `ArjBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ArjDecoder` - -Decodes ARJ-compressed data (methods 1-3). Uses LZSS with Huffman-coded literals/lengths and positions. Matches the real ARJ bitstream format (MSB-first bit packing, three-level tree encoding compatible with 7-Zip and original ARJ). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjDecoder` | `ArjDecoder(Stream input, int method = 1)` | Initializes a new `ArjDecoder`. | -| `Decode` | `byte[] Decode(int originalSize)` | Decodes the compressed data. | - -#### `ArjEncoder` - -Encodes data using ARJ compression (methods 1-3). Uses LZSS with Huffman-coded literals/lengths and positions. Matches the real ARJ bitstream format (MSB-first bit packing, three-level tree encoding compatible with 7-Zip and original ARJ). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjEncoder` | `ArjEncoder(int method = 1)` | Initializes a new `ArjEncoder`. | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using ARJ encoding. | - -### Namespace `Compression.Core.Dictionary.Balz` - -[`BalzBuildingBlock`](#balzbuildingblock) - -#### `BalzBuildingBlock` - -BALZ — Ilya Muravyov's ROLZ (reduced-offset LZ) compressor: matches are looked up in a small per-context table instead of the full sliding window, and every symbol is entropy-coded with a binary adaptive arithmetic coder. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BalzBuildingBlock` | `BalzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.BriefLz` - -[`BriefLzBuildingBlock`](#brieflzbuildingblock) - -#### `BriefLzBuildingBlock` - -BriefLZ — Jørgen Ibsen's byte-oriented LZ77 compressor with an interleaved single-bit-per-token tag stream and Elias-gamma coded match parameters. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BriefLzBuildingBlock` | `BriefLzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Brotli` - -[`BrotliBuildingBlock`](#brotlibuildingblock) · [`BrotliCompressionLevel`](#brotlicompressionlevel) · [`BrotliCompressor`](#brotlicompressor) · [`BrotliConstants`](#brotliconstants) · [`BrotliDecompressor`](#brotlidecompressor) - -#### `BrotliBuildingBlock` - -Exposes the Brotli algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BrotliBuildingBlock` | `BrotliBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BrotliCompressionLevel` - -Compression level for Brotli. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Uncompressed` | `0` | Uncompressed meta-blocks only (fastest, no compression). | -| `Fast` | `1` | Fast LZ77 compression. | -| `Default` | `2` | Default LZ77 compression. | -| `Best` | `3` | Best LZ77 compression with deeper search. | - -#### `BrotliCompressor` - -Compresses data in the Brotli format (RFC 7932). - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressLz77` | `static byte[] CompressLz77(ReadOnlySpan data)` | Compresses data to the Brotli format using entropy-coded meta-blocks. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data to the Brotli format using uncompressed meta-blocks. Fast encoding with no compression ratio improvement. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, BrotliCompressionLevel level)` | Compresses data to the Brotli format at the specified compression level. | - -#### `BrotliConstants` - -Constants for the Brotli compressed data format (RFC 7932). - -| Member | Signature | Summary | -| --- | --- | --- | -| `LiteralAlphabetSize` | `const int LiteralAlphabetSize` | Alphabet size for literal prefix codes. | -| `MaxBlockTypeSymbols` | `const int MaxBlockTypeSymbols` | Maximum number of block-type symbols. | -| `MaxBlockTypes` | `const int MaxBlockTypes` | Maximum number of block types per category. | -| `MaxDirectDistanceCodes` | `const int MaxDirectDistanceCodes` | Maximum number of direct distance codes. | -| `MaxDistancePostfixBits` | `const int MaxDistancePostfixBits` | Maximum distance postfix bits. | -| `MaxHuffmanCodeLength` | `const int MaxHuffmanCodeLength` | Maximum Huffman code length in bits. | -| `MaxWindowBits` | `const int MaxWindowBits` | Maximum window size in bits (16 MB). | -| `MinWindowBits` | `const int MinWindowBits` | Minimum window size in bits (1 KB). | -| `NumCodeLengthCodes` | `const int NumCodeLengthCodes` | Number of code length code symbols. | -| `NumDistanceContextValues` | `const int NumDistanceContextValues` | Number of distance context values. | -| `NumInsertAndCopyLengthCodes` | `const int NumInsertAndCopyLengthCodes` | Number of insert-and-copy length code symbols. | -| `NumLiteralContextModes` | `const int NumLiteralContextModes` | Number of literal context modes. | -| `CodeLengthCodeOrder` | `static ReadOnlySpan CodeLengthCodeOrder { get; }` | Order of code length code lengths (RFC 7932 Section 3.5). | - -#### `BrotliDecompressor` - -Decompresses data in the Brotli format (RFC 7932). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses Brotli-encoded data. | - -### Namespace `Compression.Core.Dictionary.Crush` - -[`CrushBuildingBlock`](#crushbuildingblock) - -#### `CrushBuildingBlock` - -Crush — Ilya Muravyov's fast LZ77 compressor, distinguished from simpler LZ77 variants (such as BriefLZ) by parsing the input with a bounded dynamic-program instead of a purely greedy longest-match choice. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrushBuildingBlock` | `CrushBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Ctw` - -[`CtwBuildingBlock`](#ctwbuildingblock) - -#### `CtwBuildingBlock` - -Exposes a most-frequent-symbol context predictor as a benchmarkable building block. Uses a byte-level context model with depth 2 (previous 2 bytes). For each byte, it predicts the most frequently observed byte in a context hierarchy (order 2, then 1, then 0) and records a hit/miss bitmap plus literal miss bytes. Header: 4-byte LE original size, 1-byte max depth, then bit-packed hit/miss flags followed by miss literal bytes. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CtwBuildingBlock` | `CtwBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Density` - -[`DensityBuildingBlock`](#densitybuildingblock) · [`DensityChameleonCompressor`](#densitychameleoncompressor) · [`DensityChameleonDecompressor`](#densitychameleondecompressor) · [`DensityConstants`](#densityconstants) - -#### `DensityBuildingBlock` - -Exposes the Density "Chameleon" algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DensityBuildingBlock` | `DensityBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DensityChameleonCompressor` - -Compresses data using the Density "Chameleon" predictive-dictionary format (see `DensityConstants`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data using Chameleon. | - -#### `DensityChameleonDecompressor` - -Decompresses data produced by `DensityChameleonCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses Chameleon-compressed data. | - -#### `DensityConstants` - -Constants for the Density "Chameleon" block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChunkSize` | `const int ChunkSize` | Size, in bytes, of one dictionary unit (chunk). | -| `ChunksPerBlock` | `const int ChunksPerBlock` | Number of chunks covered by a single 32-bit signature word. | -| `HashBits` | `const int HashBits` | Log2 of the prediction dictionary size. | -| `HashMultiplier` | `const uint HashMultiplier` | Multiplicative hash constant (Knuth's 32-bit golden-ratio constant). | -| `HashSize` | `const int HashSize` | Number of entries in the prediction dictionary. | - -### Namespace `Compression.Core.Dictionary.Dna` - -[`DnaBuildingBlock`](#dnabuildingblock) - -#### `DnaBuildingBlock` - -Exposes 2-bit DNA sequence packing as a benchmarkable building block. Each of the four canonical nucleotide symbols (A, C, G, T) is packed into 2 bits, four symbols per byte. Any byte that is not one of the four symbols is recorded as an "exception" (its position and original value) and a placeholder code is packed in its place; exceptions are spliced back in on decode. This lets the codec round-trip arbitrary byte streams while still compressing pure ACGT sequences 4:1, the standard technique used by FASTA/2bit-style DNA packers. Reference: W. J. Kent, "2bit sequence format", https://genome.ucsc.edu/FAQ/FAQformat.html#format7; see also https://en.wikipedia.org/wiki/FASTA_format for the nucleotide alphabet. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DnaBuildingBlock` | `DnaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.DsLz77` - -[`BB_DsLz77`](#bb_dslz77) · [`DsLz77Compressor`](#dslz77compressor) · [`DsLz77Decompressor`](#dslz77decompressor) - -#### `BB_DsLz77` - -Benchmarkable building block for the DoubleSpace/DriveSpace LZ77 grammar. Uses effort level 0 (greedy parse, 4 KiB window) so benchmark numbers are the apples-to-apples baseline; CVF writers reach for the effort-1 / -2 variants directly via `Compress`. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BB_DsLz77` | `BB_DsLz77()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DsLz77Compressor` - -DoubleSpace/DriveSpace LZ77 compressor exposed as a tunable, effort-aware algorithm primitive. The on-the-wire bit-stream grammar is identical to `DoubleSpaceCompressor` — a 4-byte little-endian original-size header followed by LSB-first literal / match tokens — so a stream produced by this class round-trips through the existing DoubleSpace decoder and through `DsLz77Decompressor`. What this class adds on top of the fixed-effort `DoubleSpaceCompressor` implementation is a parse-effort knob (`effort`): 0 — Greedy: take the first sufficiently long match. Bounded hash-chain depth (128). Matches the existing `DoubleSpaceCompressor` behaviour. Fast.1 — Lazy: emit a literal when the next position has a strictly longer match. Deeper hash chain (1024). Roughly 10× slower, typically a few percent smaller for compressible inputs.2+ — Iterated: run multiple lazy passes with progressively deeper chains and keep the best result. Roughly 100× slower at effort 2; effort 3 only marginally improves further. This is a pragmatic stand-in for full Zopfli-style optimal parsing. Sliding-window size defaults to the DoubleSpace 4 KiB cap and may be overridden up to the format-defined maximum of 12 608 bytes — useful for the DriveSpace (DVRS) 8 KiB variant. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DsLz77Compressor` | `DsLz77Compressor()` | | -| `DefaultMaxDistance` | `const int DefaultMaxDistance` | Default sliding-window size (matches DoubleSpace 4 KiB). | -| `DriveSpaceMaxDistance` | `const int DriveSpaceMaxDistance` | DriveSpace sliding-window size (8 KiB). | -| `Compress` | `static byte[] Compress(ReadOnlySpan input, int effort = 0)` | Compresses `input` at the requested `effort` level (clamped to `[0, 3]`). The output is the standard DoubleSpace/DriveSpace BB stream (4-byte LE uncompressed-size header followed by the LSB-first token bit stream). | -| `Compress` | `static byte[] Compress(ReadOnlySpan input, int maxDistance, int effort)` | Compresses with an explicit sliding-window cap. `maxDistance` must lie in `[1, 12608]`; pass `DriveSpaceMaxDistance` for DVRS. | - -#### `DsLz77Decompressor` - -DoubleSpace/DriveSpace LZ77 decompressor. Sister of `DsLz77Compressor`; thin pass-through to the canonical DoubleSpace decoder so the token grammar stays single-sourced. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decodes a complete DoubleSpace/DriveSpace bit stream (4-byte LE uncompressed-size header + LSB-first literal/match tokens) into the original byte sequence. | - -### Namespace `Compression.Core.Dictionary.FastLz` - -[`FastLzBuildingBlock`](#fastlzbuildingblock) · [`FastLzCompressor`](#fastlzcompressor) · [`FastLzDecompressor`](#fastlzdecompressor) - -#### `FastLzBuildingBlock` - -Exposes FastLZ level-1 compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Ariya Hidayat, "FastLZ", https://ariya.github.io/FastLZ/. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FastLzBuildingBlock` | `FastLzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `FastLzCompressor` - -Implements FastLZ Level 1 compression from the public block-format specification: Ariya Hidayat, "FastLZ — free, open-source, portable real-time compression library", https://ariya.github.io/FastLZ/ (block format section) and https://github.com/ariya/FastLZ. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the FastLZ level-1 block format. | - -#### `FastLzDecompressor` - -Decodes the FastLZ level-1 block format produced by `FastLzCompressor`. Format reference: https://ariya.github.io/FastLZ/ (block format section). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses a FastLZ level-1 stream. | - -### Namespace `Compression.Core.Dictionary.GbaLz77` - -[`GbaLz77BuildingBlock`](#gbalz77buildingblock) - -#### `GbaLz77BuildingBlock` - -Nintendo GBA/NDS BIOS LZ77 — the "type 0x10" LZSS variant decoded by the Game Boy Advance BIOS call SWI 0x11 (`LZ77UnCompReadNormalWrite8bit`) and reused unchanged by the Nintendo DS BIOS. It is the standard container for compressed assets inside commercial GBA and NDS ROMs. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GbaLz77BuildingBlock` | `GbaLz77BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Ibm842` - -[`Ibm842BuildingBlock`](#ibm842buildingblock) - -#### `Ibm842BuildingBlock` - -Exposes IBM 842 hardware compression as a benchmarkable building block. A fixed-dictionary LZ scheme that encodes data using templates of 2, 4, and 8-byte patterns. Each group of 8 bytes is encoded as a template index followed by a mix of literals and references to a recent-history dictionary. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ibm842BuildingBlock` | `Ibm842BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lizard` - -[`LizardBuildingBlock`](#lizardbuildingblock) - -#### `LizardBuildingBlock` - -Lizard (formerly LZ5) — Przemysław Skibiński's LZ4 derivative. The reference codec offers several parsers ranging from an LZ4-compatible fast mode up to full-search modes with a Huffman/FSE entropy stage for maximum ratio; this building block implements the baseline LZ4-compatible block parser (the fastest of Lizard's modes) — the entropy-coded high-ratio modes are out of scope for a single building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LizardBuildingBlock` | `LizardBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lz4` - -[`Lz4BlockCompressor`](#lz4blockcompressor) · [`Lz4BlockDecompressor`](#lz4blockdecompressor) · [`Lz4BuildingBlock`](#lz4buildingblock) · [`Lz4CompressionLevel`](#lz4compressionlevel) · [`Lz4Constants`](#lz4constants) · [`Lz4FrameBuildingBlock`](#lz4framebuildingblock) - -#### `Lz4BlockCompressor` - -Compresses data using the LZ4 block format. LZ4 is a fast LZ77 variant that uses a simple hash table for match finding and a compact token format with no entropy coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source, Lz4CompressionLevel level = 0)` | Compresses the input data using LZ4 block format. | -| `Compress` | `static int Compress(ReadOnlySpan source, Span dest)` | Compresses into a destination buffer, returning bytes written. | - -#### `Lz4BlockDecompressor` - -Decompresses data in the LZ4 block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan source, int originalSize)` | Decompresses an LZ4-compressed block. | -| `Decompress` | `static int Decompress(ReadOnlySpan source, Span dest)` | Decompresses into a destination buffer, returning bytes written. | - -#### `Lz4BuildingBlock` - -Exposes the LZ4 block compression algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz4BuildingBlock` | `Lz4BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Lz4CompressionLevel` - -Compression level for LZ4. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fast` | `0` | Fast compression using single-slot hash table. | -| `Hc` | `1` | High compression using hash chains with moderate search depth (16). | -| `Max` | `2` | Maximum compression using hash chains with deep search (64). | - -#### `Lz4Constants` - -Constants for the LZ4 block compression format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FrameMagic` | `const uint FrameMagic` | LZ4 frame magic number. | -| `HashTableBits` | `const int HashTableBits` | Size of the hash table (64KB, keyed on 4-byte sequences). | -| `HashTableSize` | `const int HashTableSize` | Hash table size. | -| `LastLiterals` | `const int LastLiterals` | Number of bytes always kept as literals at end of input. | -| `LegacyMagic` | `const uint LegacyMagic` | LZ4 legacy frame magic number. | -| `MaxBlockSize` | `const int MaxBlockSize` | Maximum block size for the default (4MB) setting. | -| `MaxDistance` | `const int MaxDistance` | Maximum distance for a match (64KB - 1). | -| `MfLimit` | `const int MfLimit` | Distance from end of input within which no match may start. The LZ4 block specification fixes this at 12 (the reference encoder's MFLIMIT); the last match must end at least `LastLiterals` bytes before the end and the final sequence is always literals only. | -| `MinMatch` | `const int MinMatch` | Minimum match length. | -| `RunMask` | `const int RunMask` | Token high nibble limit before overflow encoding. | - -#### `Lz4FrameBuildingBlock` - -Exposes the LZ4 frame format (with content size, checksums, and multi-block support) as a benchmarkable building block. Unlike `Lz4BuildingBlock` which wraps raw blocks with a custom size prefix, this produces spec-compliant LZ4 frames (magic 0x184D2204) that any LZ4 tool can read. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz4FrameBuildingBlock` | `Lz4FrameBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lz77` - -[`Lz77BuildingBlock`](#lz77buildingblock) · [`Lz77Compressor`](#lz77compressor) · [`Lz77Decompressor`](#lz77decompressor) · [`Lz77OptimalBuildingBlock`](#lz77optimalbuildingblock) · [`Lz77Token`](#lz77token) - -#### `Lz77BuildingBlock` - -Exposes the LZ77 algorithm as a benchmarkable building block. Serializes tokens to a compact binary format for round-trip benchmarking. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz77BuildingBlock` | `Lz77BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Lz77Compressor` - -Produces a sequence of LZ77 tokens from input data using a match finder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz77Compressor` | `Lz77Compressor(IMatchFinder matchFinder, int windowSize = 32768, int maxMatchLength = 258, int minMatchLength = 3)` | Initializes a new `Lz77Compressor`. | -| `Compress` | `List Compress(ReadOnlySpan data)` | Compresses the input data into a list of LZ77 tokens. | - -#### `Lz77Decompressor` - -Reconstructs data from a sequence of LZ77 tokens. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(IReadOnlyList tokens)` | Decompresses a sequence of LZ77 tokens back into the original data. | - -#### `Lz77OptimalBuildingBlock` - -LZ77 driven by the reusable `Lz77OptimalParser` primitive instead of a greedy match walk. It uses the same compact token serialization (and decoder) as `Lz77BuildingBlock`, so the two differ only in how the parse is chosen — making the optimal parser's benefit directly observable in benchmarks. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz77OptimalBuildingBlock` | `Lz77OptimalBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | -| `Parse` | `static List Parse(ReadOnlySpan data)` | Produces the optimal LZ77 parse of `data` using a hash-chain match finder and the default cost model. Exposed so tests can compare it against a greedy parse. | - -#### `Lz77Token` - -Represents an LZ77 token: either a literal byte or a (distance, length) match reference. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz77Token` | `Lz77Token(bool IsLiteral, byte Literal, int Distance, int Length)` | Represents an LZ77 token: either a literal byte or a (distance, length) match reference. | -| `Distance` | `int Distance { get; init; }` | The match distance (valid when `IsLiteral` is `false`). | -| `IsLiteral` | `bool IsLiteral { get; init; }` | `true` if this is a literal byte; `false` if it is a match reference. | -| `Length` | `int Length { get; init; }` | The match length (valid when `IsLiteral` is `false`). | -| `Literal` | `byte Literal { get; init; }` | The literal byte value (valid when `IsLiteral` is `true`). | -| `CreateLiteral` | `static Lz77Token CreateLiteral(byte value)` | Creates a literal token. | -| `CreateMatch` | `static Lz77Token CreateMatch(int distance, int length)` | Creates a match token. | - -### Namespace `Compression.Core.Dictionary.Lz78` - -[`Lz78BuildingBlock`](#lz78buildingblock) · [`Lz78Compressor`](#lz78compressor) · [`Lz78Decompressor`](#lz78decompressor) · [`Lz78Token`](#lz78token) - -#### `Lz78BuildingBlock` - -Exposes the LZ78 algorithm as a benchmarkable building block. Serializes tokens to a compact binary format for round-trip benchmarking. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz78BuildingBlock` | `Lz78BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Lz78Compressor` - -Compresses data using the LZ78 algorithm with a trie-based dictionary. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz78Compressor` | `Lz78Compressor(int maxBits = 12)` | Initializes a new instance of the `Lz78Compressor` class. | -| `Compress` | `List Compress(ReadOnlySpan data)` | Compresses the input data into a sequence of LZ78 tokens. | - -#### `Lz78Decompressor` - -Decompresses data that was compressed using the LZ78 algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(IReadOnlyList tokens, int maxBits = 12)` | Decompresses a sequence of LZ78 tokens back into the original data. | - -#### `Lz78Token` - -Represents a single LZ78 output token. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz78Token` | `Lz78Token(int DictionaryIndex, byte? NextByte)` | Represents a single LZ78 output token. | -| `DictionaryIndex` | `int DictionaryIndex { get; init; }` | Index of the matching dictionary entry (0 = empty string). | -| `NextByte` | `byte? NextByte { get; init; }` | The next byte after the match, or null for the terminal token. | - -### Namespace `Compression.Core.Dictionary.Lzap` - -[`LzapBuildingBlock`](#lzapbuildingblock) · [`LzapDecoder`](#lzapdecoder) · [`LzapEncoder`](#lzapencoder) - -#### `LzapBuildingBlock` - -Exposes the LZAP algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzapBuildingBlock` | `LzapBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzapDecoder` - -Decodes LZAP-compressed data from a stream using variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzapDecoder` | `LzapDecoder(Stream input, int minBits = 9, int maxBits = 12, BitOrder bitOrder = 0)` | Initializes a new `LzapDecoder`. | -| `Decode` | `byte[] Decode(int expectedLength = -1)` | Decodes LZAP-compressed data from the input stream. | - -#### `LzapEncoder` - -Encodes data using the LZAP (Lempel-Ziv-All-Prefixes) algorithm with variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzapEncoder` | `LzapEncoder(Stream output, int minBits = 9, int maxBits = 12, BitOrder bitOrder = 0)` | Initializes a new `LzapEncoder`. | -| `ClearCode` | `int ClearCode { get; }` | Gets the clear code value (2^(minBits-1)), emitted whenever the dictionary fills and is reset. | -| `FirstUsableCode` | `int FirstUsableCode { get; }` | Gets the first code available for dictionary entries beyond the 256 single-byte codes. | -| `StopCode` | `int StopCode { get; }` | Gets the stop code value (ClearCode + 1), emitted once at end of stream. | -| `Encode` | `void Encode(ReadOnlySpan data)` | Encodes the input data and writes compressed LZAP codes to the output stream. | - -### Namespace `Compression.Core.Dictionary.Lzav` - -[`LzavBuildingBlock`](#lzavbuildingblock) - -#### `LzavBuildingBlock` - -LZAV — Aleksey Vaneev's modern, byte-oriented (no bit-level packing) LZ77 compressor, tuned for very high throughput at a better ratio than LZ4. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzavBuildingBlock` | `LzavBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lzf` - -[`LzfBuildingBlock`](#lzfbuildingblock) · [`LzfCompressor`](#lzfcompressor) · [`LzfDecompressor`](#lzfdecompressor) - -#### `LzfBuildingBlock` - -Exposes LZF compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Marc Lehmann, "liblzf", http://software.schmorp.de/pkg/liblzf.html. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzfBuildingBlock` | `LzfBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzfCompressor` - -Implements LZF compression from the public liblzf wire-format specification: Marc Lehmann, "LZF: a very small data compression library", http://software.schmorp.de/pkg/liblzf.html. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the LZF wire format. | - -#### `LzfDecompressor` - -Decodes the LZF wire format produced by `LzfCompressor`. Format reference: http://software.schmorp.de/pkg/liblzf.html. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses an LZF stream. | - -### Namespace `Compression.Core.Dictionary.Lzfse` - -[`LzfseBuildingBlock`](#lzfsebuildingblock) · [`LzfseCompressor`](#lzfsecompressor) · [`LzfseConstants`](#lzfseconstants) · [`LzfseDecompressor`](#lzfsedecompressor) - -#### `LzfseBuildingBlock` - -Exposes an LZFSE-inspired codec as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzfseBuildingBlock` | `LzfseBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzfseCompressor` - -Compresses data using the LZFSE-inspired block format (see `LzfseConstants`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data. | - -#### `LzfseConstants` - -Constants for the LZFSE-inspired block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MinMatch` | `const int MinMatch` | Minimum length of a dictionary match worth encoding. | - -#### `LzfseDecompressor` - -Decompresses data produced by `LzfseCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses an LZFSE-inspired block. | - -### Namespace `Compression.Core.Dictionary.Lzfx` - -[`LzfxBuildingBlock`](#lzfxbuildingblock) · [`LzfxCompressor`](#lzfxcompressor) · [`LzfxDecompressor`](#lzfxdecompressor) - -#### `LzfxBuildingBlock` - -Exposes LZFX compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Andrew Collette, "LZFX", https://code.google.com/archive/p/lzfx/. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzfxBuildingBlock` | `LzfxBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzfxCompressor` - -Implements LZFX compression from its public compressed-format specification: Andrew Collette, "LZFX" (LZF-derived codec with a simplified block format), https://code.google.com/archive/p/lzfx/wikis/CompressedFormat.wiki. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the LZFX block format. | - -#### `LzfxDecompressor` - -Decodes the LZFX block format produced by `LzfxCompressor`. Format reference: https://code.google.com/archive/p/lzfx/wikis/CompressedFormat.wiki. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses an LZFX stream. | - -### Namespace `Compression.Core.Dictionary.Lzg` - -[`LzgBuildingBlock`](#lzgbuildingblock) - -#### `LzgBuildingBlock` - -LZG — Marcus Geelnard's liblzg LZ77 codec: an escape-byte (0xFF) token stream over a small 2 KiB sliding window, tuned for a simple, fast, dependency-free decoder rather than maximal ratio. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzgBuildingBlock` | `LzgBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lzh` - -[`Lh1Decoder`](#lh1decoder) · [`Lh1Encoder`](#lh1encoder) · [`Lz5Decoder`](#lz5decoder) · [`Lz5Encoder`](#lz5encoder) · [`LzhBuildingBlock`](#lzhbuildingblock) · [`LzhConstants`](#lzhconstants) · [`LzhDecoder`](#lzhdecoder) · [`LzhEncoder`](#lzhencoder) · [`LzsDecoder`](#lzsdecoder) · [`LzsEncoder`](#lzsencoder) · [`PmaDecoder`](#pmadecoder) · [`PmaEncoder`](#pmaencoder) - -#### `Lh1Decoder` - -Decodes LHA -lh1- compressed data. Uses a 4KB sliding window with dynamic (adaptive) Huffman coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lh1Decoder` | `Lh1Decoder(Stream input)` | Initializes a new `Lh1Decoder`. | -| `Decode` | `byte[] Decode(int originalSize)` | Decodes the compressed data. | - -#### `Lh1Encoder` - -Encodes data using the LHA -lh1- adaptive Huffman method. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lh1Encoder` | `Lh1Encoder()` | | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Compresses data using the -lh1- algorithm. | - -#### `Lz5Decoder` - -Decodes -lz5- compressed data (LArc variant). Uses LZSS with a 4KB sliding window, no Huffman coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan compressed, int originalSize)` | Decodes -lz5- compressed data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize)` | Decodes -lz5- compressed data. | - -#### `Lz5Encoder` - -Encodes data using the -lz5- format (LArc variant). Plain LZSS with a 4KB sliding window, no Huffman coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data using the -lz5- format. | -| `Encode` | `static byte[] Encode(byte[] data)` | Encodes data using the -lz5- format. | - -#### `LzhBuildingBlock` - -Exposes the LZH (Lempel-Ziv-Huffman) algorithm as a benchmarkable building block. Uses the LH5 method (13-bit position, standard for LHA/LZH archives). Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhBuildingBlock` | `LzhBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzhConstants` - -Constants for LZH (LHA) compression methods. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | Block size for Huffman tree reset (number of codes per block). | -| `CodeLengthRepeatZero` | `const int CodeLengthRepeatZero` | Special code-length value meaning "next 9 zero-length codes" when encoding code lengths. | -| `Lh4PositionBits` | `const int Lh4PositionBits` | Maximum number of position (offset) bits for -lh4- (4KB window). | -| `Lh4WindowSize` | `const int Lh4WindowSize` | Window size for -lh4- (4096 bytes). | -| `Lh5PositionBits` | `const int Lh5PositionBits` | Maximum number of position (offset) bits for -lh5- (8KB window). | -| `Lh5PositionSlots` | `const int Lh5PositionSlots` | Number of position slots for -lh5-. | -| `Lh5WindowSize` | `const int Lh5WindowSize` | Window size for -lh5- (8192 bytes). | -| `Lh6PositionBits` | `const int Lh6PositionBits` | Maximum number of position (offset) bits for -lh6- (32KB window). | -| `Lh6PositionSlots` | `const int Lh6PositionSlots` | Number of position slots for -lh6-. | -| `Lh6WindowSize` | `const int Lh6WindowSize` | Window size for -lh6- (32768 bytes). | -| `Lh7PositionBits` | `const int Lh7PositionBits` | Maximum number of position (offset) bits for -lh7- (64KB window). | -| `Lh7PositionSlots` | `const int Lh7PositionSlots` | Number of position slots for -lh7-. | -| `Lh7WindowSize` | `const int Lh7WindowSize` | Window size for -lh7- (65536 bytes). | -| `MaxCodeBits` | `const int MaxCodeBits` | Maximum bits for literal/length Huffman codes. | -| `MaxMatch` | `const int MaxMatch` | Maximum match length for -lh5-/-lh6-/-lh7-. | -| `MaxPositionBits` | `const int MaxPositionBits` | Maximum bits for position Huffman codes. | -| `NChar` | `const int NChar` | Character code range: 0-255 literals + 256 match-length symbols (256..MaxMatch+253). | -| `NumCodeLengthSymbols` | `const int NumCodeLengthSymbols` | Number of code-length Huffman symbols (for encoding the main tree). | -| `NumCodes` | `const int NumCodes` | Number of literal/length symbols: 256 literals + (MaxMatch - Threshold + 1) length codes. | -| `Threshold` | `const int Threshold` | Threshold: matches shorter than this are not worth encoding. | - -#### `LzhDecoder` - -Decodes LZH-compressed data (methods -lh5-, -lh6-, -lh7-). Uses LZSS with Huffman-coded literals/lengths and positions. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhDecoder` | `LzhDecoder(Stream input, int positionBits = 13)` | Initializes a new `LzhDecoder`. | -| `Decode` | `byte[] Decode(int originalSize)` | Decodes the compressed data. | - -#### `LzhEncoder` - -Encodes data using LZH compression (methods -lh5-, -lh6-, -lh7-). Uses LZSS with Huffman-coded literals/lengths and positions. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhEncoder` | `LzhEncoder(int positionBits = 13)` | Initializes a new `LzhEncoder`. | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using LZH encoding. | - -#### `LzsDecoder` - -Decodes -lzs- compressed data (LArc format). Uses plain LZSS with a 2KB sliding window, no Huffman coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan compressed, int originalSize)` | Decodes -lzs- compressed data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize)` | Decodes -lzs- compressed data. | - -#### `LzsEncoder` - -Encodes data using the -lzs- format (LArc). Plain LZSS with a 2KB sliding window, no Huffman coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data using the -lzs- format. | -| `Encode` | `static byte[] Encode(byte[] data)` | Encodes data using the -lzs- format. | - -#### `PmaDecoder` - -Decodes data compressed with the PMA (Prediction by Matching of Algorithms) method used in LHA archives with methods -pm1- and -pm2-. PMA uses PPMd (Prediction by Partial Matching) context modeling with arithmetic coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize, int order)` | Decodes PMA-compressed data. | - -#### `PmaEncoder` - -Encodes data using the PMA (Prediction by Matching of Algorithms) method used in LHA archives with methods -pm1- and -pm2-. PMA uses PPMd (Prediction by Partial Matching) context modeling with arithmetic coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int order)` | Encodes data using PMA compression. | - -### Namespace `Compression.Core.Dictionary.Lzham` - -[`LzhamBuildingBlock`](#lzhambuildingblock) · [`LzhamDecoder`](#lzhamdecoder) · [`LzhamEncoder`](#lzhamencoder) - -#### `LzhamBuildingBlock` - -Exposes LZHAM (LZ + Huffman) as a benchmarkable building block. Inspired by Valve's open-source LZHAM codec used in Steam. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhamBuildingBlock` | `LzhamBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzhamDecoder` - -LZHAM decoder: reconstructs data from Huffman-coded LZ77 token stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhamDecoder` | `LzhamDecoder()` | | -| `Decode` | `byte[] Decode(byte[] compressed, int originalSize)` | Decompresses LZHAM-encoded data. | - -#### `LzhamEncoder` - -LZHAM encoder: LZ77 with Huffman-coded literals, lengths, and distances. Inspired by Valve's LZHAM codec. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhamEncoder` | `LzhamEncoder()` | | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using LZ77 + Huffman. Returns the serialized bitstream including embedded frequency tables. | - -### Namespace `Compression.Core.Dictionary.Lzjb` - -[`LzjbBuildingBlock`](#lzjbbuildingblock) · [`LzjbCompressor`](#lzjbcompressor) · [`LzjbDecompressor`](#lzjbdecompressor) - -#### `LzjbBuildingBlock` - -Exposes LZJB compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Jeff Bonwick, LZJB, https://en.wikipedia.org/wiki/LZJB. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzjbBuildingBlock` | `LzjbBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzjbCompressor` - -Implements LZJB compression from its public algorithm description: Jeff Bonwick, LZJB (ZFS metadata/small-block compressor), documented at https://en.wikipedia.org/wiki/LZJB and https://docs.oracle.com/cd/E19253-01/819-5461/gbchx/index.html — a 1KB-window LZ77 variant with an 8-flag copymap byte and a 3-byte minimum match. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the LZJB copymap format. | - -#### `LzjbDecompressor` - -Decodes the LZJB copymap format produced by `LzjbCompressor`. Reference: https://en.wikipedia.org/wiki/LZJB. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses an LZJB stream. | - -### Namespace `Compression.Core.Dictionary.Lzma` - -[`Lzma2Decoder`](#lzma2decoder) · [`Lzma2Encoder`](#lzma2encoder) · [`LzmaBuildingBlock`](#lzmabuildingblock) · [`LzmaCompressionLevel`](#lzmacompressionlevel) · [`LzmaDecoder`](#lzmadecoder) · [`LzmaEncoder`](#lzmaencoder) - -#### `Lzma2Decoder` - -LZMA2 decoder that reads chunked LZMA2 format data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lzma2Decoder` | `Lzma2Decoder(Stream input, int dictionarySize)` | Initializes a new LZMA2 decoder. | -| `IsFinished` | `bool IsFinished { get; }` | Gets whether the stream has been fully decoded. | -| `Decode` | `byte[] Decode()` | Decodes the entire LZMA2 stream. | - -#### `Lzma2Encoder` - -LZMA2 encoder that wraps LZMA data in chunked format with control bytes. Passes historical context to the LZMA encoder for cross-chunk back-references. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lzma2Encoder` | `Lzma2Encoder(int dictionarySize = 8388608, LzmaCompressionLevel level = 1)` | Initializes a new LZMA2 encoder. | -| `DictionarySizeByte` | `byte DictionarySizeByte { get; }` | Gets the encoded dictionary size byte for XZ headers. | -| `Encode` | `void Encode(Stream output, ReadOnlySpan data)` | Encodes data in LZMA2 format to the output stream. | -| `Encode` | `void Encode(Stream output, Stream input, long length = -1)` | Encodes data from a stream in LZMA2 format. | - -#### `LzmaBuildingBlock` - -Exposes the LZMA algorithm as a benchmarkable building block. Format: 5-byte properties + 4-byte LE uncompressed size + compressed data. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmaBuildingBlock` | `LzmaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan data, int literalContextBits, int literalPositionBits, int positionBits, int uncompressedSize, int dictionarySize = 0)` | Decodes a bare LZMA1 stream — no properties byte, no dictionary size, no length field, just the range-coded data — using coding parameters supplied by the caller. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzmaCompressionLevel` - -Compression level for LZMA/LZMA2. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fast` | `0` | Fast compression: chain depth 16. | -| `Normal` | `1` | Normal compression: chain depth 64. | -| `Best` | `2` | Best compression: chain depth 256, uses BinaryTree match finder. | - -#### `LzmaDecoder` - -LZMA decoder implementing the full LZMA1 decompression algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmaDecoder` | `LzmaDecoder(Stream input, byte[] properties, long uncompressedSize = -1)` | Initializes a new LZMA decoder. | -| `LzmaDecoder` | `LzmaDecoder(Stream input, int literalContextBits, int literalPositionBits, int positionBits, int dictionarySize, long uncompressedSize = -1)` | Initializes a new LZMA decoder for a raw stream whose coding parameters are known from the outside instead of from a properties header. | -| `Decode` | `byte[] Decode()` | Decodes the entire compressed stream and returns the decompressed data. | -| `Decode` | `void Decode(Stream output)` | Decodes the compressed stream writing to the specified output stream. | - -#### `LzmaEncoder` - -LZMA encoder implementing the full LZMA1 compression algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmaEncoder` | `LzmaEncoder(int dictionarySize = 8388608, int lc = 3, int lp = 0, int pb = 2, LzmaCompressionLevel level = 1)` | Initializes a new LZMA encoder. | -| `Properties` | `byte[] Properties { get; }` | Gets the 5-byte LZMA properties header (1 byte properties + 4 bytes dictionary size). | -| `Encode` | `void Encode(Stream output, ReadOnlySpan data, bool writeEndMarker = true)` | Encodes the given data to the output stream. Writes LZMA-compressed data (without the properties header or uncompressed size). | - -### Namespace `Compression.Core.Dictionary.Lzms` - -[`LzmsBuildingBlock`](#lzmsbuildingblock) · [`LzmsCompressor`](#lzmscompressor) · [`LzmsDecompressor`](#lzmsdecompressor) · [`LzmsX86Filter`](#lzmsx86filter) - -#### `LzmsBuildingBlock` - -Exposes the LZMS algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmsBuildingBlock` | `LzmsBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzmsCompressor` - -Produces one LZMS chunk. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmsCompressor` | `LzmsCompressor()` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compresses a chunk. | - -#### `LzmsDecompressor` - -Decodes one LZMS chunk. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmsDecompressor` | `LzmsDecompressor()` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan compressed, int uncompressedSize)` | Decodes a chunk that was compressed with `LzmsCompressor`. | - -#### `LzmsX86Filter` - -The x86 filter LZMS runs over every chunk. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Apply` | `static byte[] Apply(ReadOnlySpan data, bool forward)` | Runs the filter, forwards before compressing or backwards after. | - -### Namespace `Compression.Core.Dictionary.Lzmw` - -[`LzmwBuildingBlock`](#lzmwbuildingblock) · [`LzmwDecoder`](#lzmwdecoder) · [`LzmwEncoder`](#lzmwencoder) - -#### `LzmwBuildingBlock` - -Exposes the LZMW algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmwBuildingBlock` | `LzmwBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzmwDecoder` - -Decodes LZMW-compressed data from a stream using variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmwDecoder` | `LzmwDecoder(Stream input, int minBits = 9, int maxBits = 16, BitOrder bitOrder = 0)` | Initializes a new `LzmwDecoder`. | -| `Decode` | `byte[] Decode(int expectedLength = -1)` | Decodes LZMW-compressed data from the input stream. | - -#### `LzmwEncoder` - -Encodes data using the LZMW (Lempel-Ziv-Miller-Wegman) algorithm with variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmwEncoder` | `LzmwEncoder(Stream output, int minBits = 9, int maxBits = 16, BitOrder bitOrder = 0)` | Initializes a new `LzmwEncoder`. | -| `ClearCode` | `int ClearCode { get; }` | Gets the clear code value (2^(minBits-1)), emitted whenever the dictionary fills and is reset. | -| `FirstUsableCode` | `int FirstUsableCode { get; }` | Gets the first code available for dictionary entries beyond the 256 single-byte codes. | -| `StopCode` | `int StopCode { get; }` | Gets the stop code value (ClearCode + 1), emitted once at end of stream. | -| `Encode` | `void Encode(ReadOnlySpan data)` | Encodes the input data and writes compressed LZMW codes to the output stream. | - -### Namespace `Compression.Core.Dictionary.Lzo` - -[`Lzo1xCompressor`](#lzo1xcompressor) · [`Lzo1xDecompressor`](#lzo1xdecompressor) · [`Lzo1xEncoder`](#lzo1xencoder) · [`LzoBuildingBlock`](#lzobuildingblock) · [`LzoCompressionLevel`](#lzocompressionlevel) - -#### `Lzo1xCompressor` - -LZO1X-1 style compressor using a hash table for fast match finding. Uses an LZ4-style token format: token byte (high nibble = literal length 0–15, low nibble = match extra length 0–15), optional literal-length extension bytes, literal bytes, 2-byte LE offset, optional match-length extension bytes. Minimum match length is 4; maximum distance is 65535 (fits in u16 LE field). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses the given data using the LZO1X-1 algorithm. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, LzoCompressionLevel level)` | Compresses the given data using LZO1X at the specified level. | - -#### `Lzo1xDecompressor` - -Decompresses a genuine LZO1X stream — the one lzop, the kernel and squashfs all write. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecompressUpTo` | `static byte[] DecompressUpTo(ReadOnlySpan data, int maxOutput)` | Decompresses a stream whose exact length is not known in advance, only a ceiling. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int uncompressedSize)` | Decompresses an LZO1X stream into a buffer of the size the container declared. | - -#### `Lzo1xEncoder` - -Writes a genuine LZO1X stream — one lzop, the kernel and squashfs all read. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses into the LZO1X stream format. | - -#### `LzoBuildingBlock` - -Exposes the LZO1X algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzoBuildingBlock` | `LzoBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzoCompressionLevel` - -Compression level for LZO1X. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fast` | `0` | Fast compression (LZO1X-1 style, single-slot hash). | -| `Best` | `1` | Best compression (LZO1X-999 style, hash chains + optimal parsing). | - -### Namespace `Compression.Core.Dictionary.Lzp` - -[`LzpBuildingBlock`](#lzpbuildingblock) · [`LzpCompressor`](#lzpcompressor) · [`LzpDecompressor`](#lzpdecompressor) - -#### `LzpBuildingBlock` - -Exposes the LZP (Lempel-Ziv Prediction) algorithm as a benchmarkable building block. LZP's format is self-describing (5-byte header with order and original size). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzpBuildingBlock` | `LzpBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzpCompressor` - -LZP (Lempel-Ziv Prediction) compressor. Predicts the next byte from a context hash; if the prediction matches, emits a match bit; if it misses, emits a literal byte. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan input, int order = 3)` | Compresses data using LZP with the specified context order. | -| `Compress` | `static byte[] Compress(byte[] input, int order = 3)` | Compresses data using LZP with the specified context order. | - -#### `LzpDecompressor` - -LZP (Lempel-Ziv Prediction) decompressor. Rebuilds the original data from a compressed stream produced by `LzpCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses data that was compressed with `LzpCompressor`. | -| `Decompress` | `static byte[] Decompress(byte[] compressed)` | Decompresses data that was compressed with `LzpCompressor`. | - -### Namespace `Compression.Core.Dictionary.Lzrle` - -[`LzrleBuildingBlock`](#lzrlebuildingblock) · [`LzrleCompressor`](#lzrlecompressor) · [`LzrleConstants`](#lzrleconstants) · [`LzrleDecompressor`](#lzrledecompressor) - -#### `LzrleBuildingBlock` - -Exposes LZRLE (run-length-augmented LZ) as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzrleBuildingBlock` | `LzrleBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzrleCompressor` - -Compresses data using the LZRLE block format (see `LzrleConstants`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data using LZRLE. | - -#### `LzrleConstants` - -Constants for the LZRLE (run-length-augmented LZ) block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LengthFieldBits` | `const int LengthFieldBits` | Number of bits reserved for the token length field. | -| `LengthFieldMax` | `const int LengthFieldMax` | Sentinel length-field value meaning "read extended continuation bytes". | -| `MinMatch` | `const int MinMatch` | Minimum length of a dictionary match worth encoding. | -| `MinRun` | `const int MinRun` | Minimum length of a repeated-byte run worth encoding. | -| `TypeLiteral` | `const int TypeLiteral` | Token type: literal run follows. | -| `TypeMatch` | `const int TypeMatch` | Token type: dictionary match (4-byte little-endian distance follows). | -| `TypeRun` | `const int TypeRun` | Token type: repeated-byte run (single value byte follows). | - -#### `LzrleDecompressor` - -Decompresses data produced by `LzrleCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses LZRLE-compressed data. | - -### Namespace `Compression.Core.Dictionary.Lzrw1` - -[`Lzrw1BuildingBlock`](#lzrw1buildingblock) · [`Lzrw1Compressor`](#lzrw1compressor) · [`Lzrw1Decompressor`](#lzrw1decompressor) - -#### `Lzrw1BuildingBlock` - -Exposes LZRW1 compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Ross N. Williams, "LZRW1", http://ross.net/compression/lzrw1.html. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lzrw1BuildingBlock` | `Lzrw1BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Lzrw1Compressor` - -Implements LZRW1 compression from its public algorithm description: Ross N. Williams, "An Extremely Fast Ziv-Lempel Data Compression Algorithm", Data Compression Conference 1991, http://ross.net/compression/lzrw1.html — a hash-matched LZ77 variant grouping 16 items behind a control word, with a 4096-entry single-probe hash table and matches of length 3-18. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the LZRW1 control-word format. | - -#### `Lzrw1Decompressor` - -Decodes the LZRW1 control-word format produced by `Lzrw1Compressor`. Reference: Ross N. Williams, http://ross.net/compression/lzrw1.html. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses an LZRW1 stream. | - -### Namespace `Compression.Core.Dictionary.Lzrw3` - -[`Lzrw3BuildingBlock`](#lzrw3buildingblock) · [`Lzrw3Compressor`](#lzrw3compressor) · [`Lzrw3Decompressor`](#lzrw3decompressor) - -#### `Lzrw3BuildingBlock` - -Exposes LZRW3 compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Ross N. Williams, "LZRW3", http://ross.net/compression/lzrw3.html. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lzrw3BuildingBlock` | `Lzrw3BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Lzrw3Compressor` - -Implements LZRW3 compression from its public algorithm description: Ross N. Williams, "LZRW3: A Hash Table Index Variant of LZRW1", http://ross.net/compression/lzrw3.html — an LZRW1 derivative that transmits 4096-entry hash-table indices instead of raw offsets, so the decoder can resolve a match purely from a synchronized hash table (a "persistent phrase" table) rather than an explicit distance field. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the LZRW3 control-word format. | - -#### `Lzrw3Decompressor` - -Decodes the LZRW3 control-word format produced by `Lzrw3Compressor`. Reference: Ross N. Williams, http://ross.net/compression/lzrw3.html. Mirrors the compressor's queued hash-table synchronization exactly (see remarks there): a position's hash entry only becomes visible once its 3-byte window is fully decoded. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses an LZRW3 stream. | - -### Namespace `Compression.Core.Dictionary.Lzs` - -[`LzsBuildingBlock`](#lzsbuildingblock) - -#### `LzsBuildingBlock` - -Exposes Stac LZS (RFC 1967/1974) as a benchmarkable building block. An LZSS variant using 7-bit offsets (1-127) and 11-bit offsets (128-2047), with 2-bit or 8-bit match lengths. Used in Cisco IOS and Stac hardware compression. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzsBuildingBlock` | `LzsBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lzss` - -[`LzssBuildingBlock`](#lzssbuildingblock) · [`LzssDecoder`](#lzssdecoder) · [`LzssEncoder`](#lzssencoder) - -#### `LzssBuildingBlock` - -Exposes the LZSS algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzssBuildingBlock` | `LzssBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzssDecoder` - -Decodes LZSS flag-bit encoded data from a stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzssDecoder` | `LzssDecoder(Stream input, int distanceBits = 12, int lengthBits = 4, int minMatchLength = 3)` | Initializes a new `LzssDecoder`. | -| `Decode` | `byte[] Decode(int expectedLength = -1)` | Decodes data from the input stream. | - -#### `LzssEncoder` - -Encodes LZ77 tokens to a stream using LZSS flag-bit format. Each group of 8 tokens is preceded by a flag byte where each bit indicates whether the corresponding token is a literal (1) or a match (0). - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzssEncoder` | `LzssEncoder(Stream output, int distanceBits = 12, int lengthBits = 4, int minMatchLength = 3)` | Initializes a new `LzssEncoder`. | -| `MaxDistance` | `int MaxDistance { get; }` | Gets the maximum match distance supported by the current configuration. | -| `MaxLength` | `int MaxLength { get; }` | Gets the maximum match length supported by the current configuration. | -| `Encode` | `void Encode(ReadOnlySpan data, IMatchFinder matchFinder)` | Encodes input data to the output stream. | - -### Namespace `Compression.Core.Dictionary.Lzturbo` - -[`LzturboBuildingBlock`](#lzturbobuildingblock) · [`LzturboCompressor`](#lzturbocompressor) · [`LzturboConstants`](#lzturboconstants) · [`LzturboDecompressor`](#lzturbodecompressor) - -#### `LzturboBuildingBlock` - -Exposes an LZTURBO-inspired codec as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzturboBuildingBlock` | `LzturboBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzturboCompressor` - -Compresses data using the LZTURBO-inspired block format (see `LzturboConstants`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data. | - -#### `LzturboConstants` - -Constants for the LZTURBO-inspired block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DistanceBytes` | `const int DistanceBytes` | Width, in bytes, of the little-endian window offset following a match token. | -| `HeaderSize` | `const int HeaderSize` | Size, in bytes, of the block header (magic + method + original length + body length). | -| `LiteralExtended` | `const int LiteralExtended` | Literal-length nibble value meaning "read extended continuation bytes". | -| `Magic` | `static readonly byte[] Magic` | 4-byte block magic identifying this format. | -| `MatchExtended` | `const int MatchExtended` | Match-length nibble value meaning "read extended continuation bytes". | -| `MatchNone` | `const int MatchNone` | Match-length nibble value meaning "no match follows" (trailing literal-only token). | -| `MaxDirectLiteral` | `const int MaxDirectLiteral` | Maximum literal-length value directly encodable in the token nibble. | -| `MaxDirectMatch` | `const int MaxDirectMatch` | Maximum match-length field value (relative to `MinMatch`) directly encodable in the token nibble. | -| `Method` | `const byte Method` | Method byte for the only implemented variant: fast-LZ front end, no entropy back end. | -| `MinMatch` | `const int MinMatch` | Minimum length of a dictionary match worth encoding. | - -#### `LzturboDecompressor` - -Decompresses data produced by `LzturboCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses an LZTURBO-inspired block. | - -### Namespace `Compression.Core.Dictionary.Lzvn` - -[`LzvnBuildingBlock`](#lzvnbuildingblock) · [`LzvnCompressor`](#lzvncompressor) · [`LzvnConstants`](#lzvnconstants) · [`LzvnDecompressor`](#lzvndecompressor) - -#### `LzvnBuildingBlock` - -Exposes LZVN as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzvnBuildingBlock` | `LzvnBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzvnCompressor` - -Compresses data using the LZVN block format (see `LzvnConstants`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data using LZVN. | - -#### `LzvnConstants` - -Constants for the LZVN block format: a byte-oriented opcode LZ77 stream in the spirit of Apple's LZVN ("Lempel-Ziv Variable-length iNteger") codec shipped alongside LZFSE for fast, low-ratio compression of small buffers and Mach-O pages. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DistanceTier1Max` | `const int DistanceTier1Max` | Distance tier 1 (1-byte) upper bound: distances 1..128. | -| `DistanceTier2Max` | `const int DistanceTier2Max` | Distance tier 2 (2-byte) upper bound: distances 129..32640. | -| `DistanceTier3Marker` | `const byte DistanceTier3Marker` | First byte value marking the 5-byte (raw 32-bit) distance tier. | -| `LiteralExtended` | `const int LiteralExtended` | Literal-length nibble value meaning "read extended continuation bytes". | -| `MatchExtended` | `const int MatchExtended` | Match-length nibble value meaning "read extended continuation bytes". | -| `MatchNone` | `const int MatchNone` | Match-length nibble value meaning "no match follows" (trailing literal-only token). | -| `MaxDirectLiteral` | `const int MaxDirectLiteral` | Maximum literal-length value directly encodable in the token nibble. | -| `MaxDirectMatch` | `const int MaxDirectMatch` | Maximum match-length field value (relative to `MinMatch`) directly encodable in the token nibble. | -| `MinMatch` | `const int MinMatch` | Minimum length of a dictionary match worth encoding. | - -#### `LzvnDecompressor` - -Decompresses data produced by `LzvnCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses LZVN-compressed data. | - -### Namespace `Compression.Core.Dictionary.Lzw` - -[`LzwBuildingBlock`](#lzwbuildingblock) · [`LzwCompressionLevel`](#lzwcompressionlevel) · [`LzwDecoder`](#lzwdecoder) · [`LzwEncoder`](#lzwencoder) - -#### `LzwBuildingBlock` - -Exposes the LZW algorithm as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzwBuildingBlock` | `LzwBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzwCompressionLevel` - -Specifies the compression level for the LZW encoder. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Uncompressed` | `0` | Output raw byte codes only — no dictionary building. | -| `FirstMatch` | `1` | Standard greedy LZW — longest trie match at each step. | -| `Optimal` | `9` | Optimal DP-based LZW — minimizes total bit cost. | - -#### `LzwDecoder` - -Decodes LZW-compressed data from a stream using variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzwDecoder` | `LzwDecoder(Stream input, int minBits = 9, int maxBits = 12, bool useClearCode = true, bool useStopCode = true, BitOrder bitOrder = 0)` | Initializes a new `LzwDecoder`. | -| `Decode` | `byte[] Decode(int expectedLength = -1)` | Decodes LZW-compressed data from the input stream. | - -#### `LzwEncoder` - -Encodes data using the LZW (Lempel-Ziv-Welch) algorithm with variable-width codes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzwEncoder` | `LzwEncoder(Stream output, int minBits = 9, int maxBits = 12, bool useClearCode = true, bool useStopCode = true, BitOrder bitOrder = 0, LzwCompressionLevel level = 1)` | Initializes a new `LzwEncoder`. | -| `ClearCode` | `int ClearCode { get; }` | Gets the clear code value (2^(minBits-1)). | -| `StopCode` | `int StopCode { get; }` | Gets the stop code value, or -1 if stop codes are disabled. | -| `Encode` | `void Encode(ReadOnlySpan data)` | Encodes the input data and writes compressed LZW codes to the output stream. | - -### Namespace `Compression.Core.Dictionary.Lzwl` - -[`LzwlBuildingBlock`](#lzwlbuildingblock) - -#### `LzwlBuildingBlock` - -Exposes LZWL as a benchmarkable building block. LZW with variable-length alphabet symbols: the initial dictionary is extended with frequent digram pairs found via frequency analysis, allowing faster convergence. Uses a trie (parent,child) structure like standard LZW, with a stop code for clean end-of-stream signaling. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzwlBuildingBlock` | `LzwlBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Lzx` - -[`LzxBuildingBlock`](#lzxbuildingblock) · [`LzxCompressionLevel`](#lzxcompressionlevel) · [`LzxCompressor`](#lzxcompressor) · [`LzxConstants`](#lzxconstants) · [`LzxDecompressor`](#lzxdecompressor) · [`LzxStreamFormat`](#lzxstreamformat) · [`LzxWimE8Filter`](#lzxwime8filter) - -#### `LzxBuildingBlock` - -Exposes the LZX algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxBuildingBlock` | `LzxBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `LzxCompressionLevel` - -Compression level for LZX. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fast` | `0` | Fast compression: chain depth 16. | -| `Normal` | `1` | Normal compression: chain depth 64. | -| `Best` | `2` | Best compression: chain depth 256. | - -#### `LzxCompressor` - -Compresses data using the LZX algorithm (as used in Microsoft CAB and WIM formats). - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxCompressor` | `LzxCompressor(int windowBits = 15, int blockSize = 32768, LzxCompressionLevel level = 1, LzxStreamFormat format = 0)` | Initializes a new `LzxCompressor`. | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compresses the given data and returns the compressed bytes. | -| `Compress` | `byte[] Compress(ReadOnlySpan data, out List> blocks)` | Compresses the given data as one stream and reports where each block's output ends in the compressed bytes. | - -#### `LzxConstants` - -Constants for the LZX compression algorithm, as used in Microsoft CAB and WIM formats. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockTypeAligned` | `const int BlockTypeAligned` | Block type value: aligned offset block. | -| `BlockTypeUncompressed` | `const int BlockTypeUncompressed` | Block type value: uncompressed block. | -| `BlockTypeVerbatim` | `const int BlockTypeVerbatim` | Block type value: verbatim block. | -| `DefaultBlockSize` | `const int DefaultBlockSize` | Default block size in uncompressed bytes (32 KB). | -| `MaxHuffmanBits` | `const int MaxHuffmanBits` | Maximum Huffman code length for the main, length, and aligned trees. LZX uses at most 16-bit codes. | -| `MaxMatch` | `const int MaxMatch` | Maximum match length in bytes. | -| `MaxPreTreeBits` | `const int MaxPreTreeBits` | Maximum Huffman code length for the pre-tree (4 bits per pre-tree symbol in the stream, but the pre-tree itself has codes up to 16 bits). | -| `MaxWindowBits` | `const int MaxWindowBits` | Maximum window size exponent (2^21 = 2 MB). | -| `MinMatch` | `const int MinMatch` | Minimum match length in bytes. | -| `MinNonRepeatDistance` | `const int MinNonRepeatDistance` | The smallest distance a non-repeat position slot can name, which is one: every distance is expressible. | -| `MinWindowBits` | `const int MinWindowBits` | Minimum window size exponent (2^15 = 32 KB). | -| `NumAlignedSymbols` | `const int NumAlignedSymbols` | Number of aligned offset tree symbols. | -| `NumChars` | `const int NumChars` | Number of literal symbols (0–255). | -| `NumLengthHeaders` | `const int NumLengthHeaders` | Number of length header slots encoded in the main tree symbol (0–7). | -| `NumLengthSymbols` | `const int NumLengthSymbols` | Number of length tree symbols (secondary lengths 0–248). | -| `NumPreTreeSymbols` | `const int NumPreTreeSymbols` | Number of pre-tree symbols (used to encode Huffman code lengths). | -| `OffsetBias` | `const int OffsetBias` | Minimum match distance that can be encoded as a new (non-repeated) offset. The formatted offset a position slot names is the distance plus this much. Slots 0 to 2 are spoken for by the three remembered offsets, so the smallest slot that can name a distance is slot 3, whose base is 3 — which is a distance of 1 once the bias is taken off again. | -| `PositionSlots15` | `const int PositionSlots15` | Number of position slots for a 32 KB (2^15) window. | -| `PositionSlots16` | `const int PositionSlots16` | Number of position slots for a 64 KB (2^16) window. | -| `PositionSlots17` | `const int PositionSlots17` | Number of position slots for a 128 KB (2^17) window. | -| `PositionSlots18` | `const int PositionSlots18` | Number of position slots for a 256 KB (2^18) window. | -| `PositionSlots19` | `const int PositionSlots19` | Number of position slots for a 512 KB (2^19) window. | -| `PositionSlots20` | `const int PositionSlots20` | Number of position slots for a 1 MB (2^20) window. | -| `PositionSlots21` | `const int PositionSlots21` | Number of position slots for a 2 MB (2^21) window. | -| `PreTreeBits` | `const int PreTreeBits` | Bits per pre-tree entry in the block header. | -| `BuildPositionSlotTable` | `static int[] BuildPositionSlotTable()` | Builds and returns the pre-computed position slot lookup table. Index is the offset value; value is the slot number. Valid for offsets 0 to 65535 (covers all window sizes up to 2 MB via the split approach). | -| `GetPositionSlotCount` | `static int GetPositionSlotCount(int windowBits)` | Returns the number of position slots for a given window size exponent. | -| `GetSlotInfo` | `static void GetSlotInfo(int slot, out int baseOffset, out int footerBits)` | Returns the base offset and footer bits for a given position slot. For slots 0–3 the footer is 0. For each subsequent pair the footer grows by 1. | -| `MaxDistance` | `static int MaxDistance(int windowSize)` | The largest distance the position slots of a window of this size can name. | -| `OffsetToSlot` | `static int OffsetToSlot(int offset)` | Computes the position slot for a given offset (0-based distance into the window). Slot 0 = offset 0, slot 1 = offset 1, slots 2–3 = offsets 2–3, then slot k covers the range [base_k, base_{k+1}). | - -#### `LzxDecompressor` - -Decompresses data encoded with the LZX algorithm (as used in Microsoft CAB and WIM formats). - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxDecompressor` | `LzxDecompressor(Stream input, int windowBits = 15, bool e8Translation = false, LzxStreamFormat format = 0)` | Initializes a new `LzxDecompressor`. | -| `Decompress` | `byte[] Decompress(int uncompressedSize)` | Decompresses the next `uncompressedSize` bytes from the input stream. | - -#### `LzxStreamFormat` - -Which of the two arrangements of an LZX stream is in use. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Wim` | `0` | The arrangement a WIM uses: no header ahead of the first block, and a block size given as a single bit meaning "the usual 32 768" or sixteen bits otherwise. Each chunk is a stream of its own. | -| `Cab` | `1` | The arrangement a cabinet uses: the stream opens with a bit saying whether x86 call targets were rewritten (and a 32-bit size if they were), and block sizes are twenty-four bits. One stream covers a whole folder, however many data records it is cut into. | - -#### `LzxWimE8Filter` - -The x86 call-target rewriting a WIM applies to every chunk it compresses with LZX, before compressing and again in reverse after decompressing. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Postprocess` | `static void Postprocess(byte[] data)` | Rewrites call targets from absolute back to relative, in place. | -| `Preprocess` | `static void Preprocess(byte[] data)` | Rewrites call targets from relative to absolute, in place. | - -### Namespace `Compression.Core.Dictionary.MatchFinders` - -[`BinaryTreeMatchFinder`](#binarytreematchfinder) · [`HashChainMatchFinder`](#hashchainmatchfinder) · [`IMatchFinder`](#imatchfinder) · [`Match`](#match) · [`SuffixArrayMatchFinder`](#suffixarraymatchfinder) - -#### `BinaryTreeMatchFinder` - -Binary-tree match finder for LZ77-style compression. Maintains a binary search tree of hash-indexed positions, providing better match quality than hash chains at higher computational cost. - -Implements `IMatchFinder`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinaryTreeMatchFinder` | `BinaryTreeMatchFinder(int windowSize)` | Initializes a new `BinaryTreeMatchFinder`. | -| `FindMatch` | `Match FindMatch(ReadOnlySpan data, int position, int maxDistance, int maxLength, int minLength = 3)` | | -| `InsertPosition` | `void InsertPosition(ReadOnlySpan data, int position)` | Inserts a position into the tree without searching for a match. | - -#### `HashChainMatchFinder` - -Hash-chain match finder using a 3-byte hash with configurable chain depth. - -Implements `IMatchFinder`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HashChainMatchFinder` | `HashChainMatchFinder(int windowSize, int maxChainDepth = 128)` | Initializes a new `HashChainMatchFinder`. | -| `FindMatch` | `Match FindMatch(ReadOnlySpan data, int position, int maxDistance, int maxLength, int minLength = 3)` | | -| `InsertPosition` | `void InsertPosition(ReadOnlySpan data, int position)` | Inserts a position into the hash chain without searching for a match. Call this for positions that are skipped (e.g., inside a matched region). | - -#### `IMatchFinder` - -Interface for LZ77-style match finders. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FindMatch` | `Match FindMatch(ReadOnlySpan data, int position, int maxDistance, int maxLength, int minLength = 3)` | Finds the best match for data at the specified position. | - -#### `Match` - -Represents a match found in the sliding window. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Match` | `Match(int Distance, int Length)` | Represents a match found in the sliding window. | -| `Distance` | `int Distance { get; init; }` | The distance back from the current position (1-based). | -| `Length` | `int Length { get; init; }` | The length of the match in bytes. | - -#### `SuffixArrayMatchFinder` - -Match finder based on a suffix array, providing optimal-quality matches for use in optimal parsers. Constructs the suffix array and LCP array once over the entire input, then answers match queries in O(log n) time. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SuffixArrayMatchFinder` | `SuffixArrayMatchFinder(ReadOnlySpan data)` | Initializes a new `SuffixArrayMatchFinder` over the given data. | -| `FindMatch` | `Match FindMatch(ReadOnlySpan data, int position, int maxDistance, int maxLength, int minLength)` | Finds the longest match for the position `position` in the original data, searching only within `maxDistance` bytes before it. | - -### Namespace `Compression.Core.Dictionary.MsLzh` - -[`MsLzhBuildingBlock`](#mslzhbuildingblock) · [`MsLzhCompressor`](#mslzhcompressor) · [`MsLzhDecompressor`](#mslzhdecompressor) - -#### `MsLzhBuildingBlock` - -Building block wrapper for the MS LZH codec used by Microsoft DriveSpace 3 (Windows 95 Plus! Pack, 1995). LZ77 with 4 KiB window plus canonical Huffman coding over a DEFLATE-shaped alphabet. Effort 0 only: static (fixed) Huffman + greedy match selection. Dynamic per-block Huffman trees and lazy/optimal matching are deferred — see `MsLzhCompressor`. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsLzhBuildingBlock` | `MsLzhBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `MsLzhCompressor` - -MS LZH compressor — DriveSpace 3 (Win95 Plus! Pack, 1995) family codec. LZ77 with 4 KiB window + canonical Huffman over a 286-symbol literal/length alphabet (DEFLATE-shaped) and a 30-symbol distance alphabet. Effort tiers (mirrors `DsLz77Compressor`): 0 — Greedy (default): bounded hash-chain depth (64), greedy match selection, fixed Huffman tables per RFC 1951 §3.2.6 shape — see `MsLzhFixedTables`. Fast. Matches the historical effort-0 behaviour bit-for-bit (modulo the new leading block-type bit).1 — Lazy (`+`): at each candidate match position, look ahead one byte; emit a literal when `(pos + 1)` would yield a strictly longer match. Hash chain deepened to 1024. Same fixed Huffman tables — encoder output stays self-consistent with the decoder. Roughly 5-10× slower, typically a few percent smaller on compressible inputs.2+ — Iterated + dynamic Huffman (`++`): runs the effort-1 lazy parse, then compares the cost of encoding the resulting token stream with the fixed tables vs. with per-block dynamic Huffman tables (RFC 1951 §3.2.7 layout — see `MsLzhDynamicHuffman`). The smaller of the two wins. Also sweeps the min-match floor (3, 4, 5) like the older effort-2 parse.Bit-stream format. Every block is prefixed by a single block-type bit: `0` = fixed Huffman tables (RFC 1951 §3.2.6 shape), `1` = dynamic per-block Huffman tables. Both paths share the same length / distance extra-bit conventions and the end-of-block marker (symbol 256). Termination invariant for iterated parsing: the candidate set has a fixed cap (4 passes max — baseline lazy plus three min-match sweeps), each pass produces a complete output, and we retain the smallest. This guarantees effort 2+ is monotone: `len(eff 2) ≤ len(eff 1) ≤ len(eff 0)` on compressible inputs, with strict equality possible for inputs where the effort-0 parse is already optimal. Not yet bit-compatible with Microsoft's reference decoder. The dynamic Huffman header layout matches RFC 1951 semantically but the MS LZH per-cluster framing (block-count bytes, dictionary-init values) has not been reverse-engineered from a real DRVSPACE.000 image. Self round-trip is the gating requirement; cross-tool compatibility remains a stretch goal. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsLzhCompressor` | `MsLzhCompressor()` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compresses `data` with the default effort 0 (greedy + fixed tables). | -| `Compress` | `byte[] Compress(ReadOnlySpan data, int effort)` | Compresses `data` at the requested `effort` level. Negative values are clamped to 0 (greedy). Values above 2 are treated as 2 (iterated + dynamic Huffman). | - -#### `MsLzhDecompressor` - -MS LZH decompressor — reads back the bit stream produced by `MsLzhCompressor`. Reads a 4-byte little-endian original-size header followed by a sequence of blocks. Each block is prefixed by a single block-type bit: `0` selects the RFC 1951 §3.2.6-shape fixed Huffman tables (see `MsLzhFixedTables`); `1` selects per-block dynamic Huffman tables whose header layout follows RFC 1951 §3.2.7 (HLIT / HDIST / HCLEN + code-length-code table + lit/len + distance code-length lists — see `MsLzhDynamicHuffman`). End-of-block (symbol 256) closes a block; the decoder stops once the original-size byte count has been emitted. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsLzhDecompressor` | `MsLzhDecompressor()` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | Decompresses an MS LZH bit stream. | - -### Namespace `Compression.Core.Dictionary.Nintendo` - -[`Yay0BuildingBlock`](#yay0buildingblock) · [`Yaz0BuildingBlock`](#yaz0buildingblock) - -#### `Yay0BuildingBlock` - -Exposes Nintendo Yay0 split-table LZ compression as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Yay0BuildingBlock` | `Yay0BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Yaz0BuildingBlock` - -Exposes Nintendo Yaz0 grouped-flag LZ compression as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Yaz0BuildingBlock` | `Yaz0BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Nrv2b` - -[`Nrv2bBuildingBlock`](#nrv2bbuildingblock) - -#### `Nrv2bBuildingBlock` - -NRV2B LE32 — Markus Oberhumer's UCL-family compression used at the core of UPX. LZ77-style back-references with an interleaved variable-length integer encoding for match offsets and lengths over a 32-bit little-endian bit stream. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Nrv2bBuildingBlock` | `Nrv2bBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressRawByte` | `static byte[] DecompressRawByte(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2B 8-bit stream (no 4-byte size prefix). UPX compression method 6 uses this width — bits are packed into single bytes and consumed MSB-first; the decoder cursor advances by 1 on each bit-word refill. | -| `DecompressRawLe16` | `static byte[] DecompressRawLe16(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2B LE16 stream (no 4-byte size prefix). UPX compression methods 4 and the LE16 variants use this width — bits are packed into 16-bit little-endian words and consumed MSB-first; the decoder cursor advances by 2 on each bit-word refill. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2B LE32 stream (no 4-byte size prefix) into a freshly-allocated buffer of exactly `exactOutputSize` bytes. Exposed for callers parsing UPX binaries or other embedded NRV2B streams. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Nrv2d` - -[`Nrv2dBuildingBlock`](#nrv2dbuildingblock) - -#### `Nrv2dBuildingBlock` - -UCL reference NRV2D LE32 — Markus Oberhumer's UCL-family compression as used at the core of UPX (compression methods 3 / 5 / 7 are the LE32 / LE16 / 8-bit variants of NRV2D respectively; this implementation is LE32). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Nrv2dBuildingBlock` | `Nrv2dBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressRawByte` | `static byte[] DecompressRawByte(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2D 8-bit stream (no 4-byte size prefix). UPX compression method 7 uses this width — bits are packed into single bytes and consumed MSB-first. | -| `DecompressRawLe16` | `static byte[] DecompressRawLe16(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2D LE16 stream (no 4-byte size prefix). UPX compression method 5 uses this width — bits are packed into 16-bit little-endian words and consumed MSB-first. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2D LE32 stream (no 4-byte size prefix) into a freshly-allocated buffer of exactly `exactOutputSize` bytes. Exposed for callers parsing UPX binaries or other embedded NRV2D streams. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Nrv2e` - -[`Nrv2eBuildingBlock`](#nrv2ebuildingblock) - -#### `Nrv2eBuildingBlock` - -UCL reference NRV2E LE32 — Markus Oberhumer's UCL-family compression as used at the core of UPX (compression methods 8 / 9 / 10 are the LE32 / LE16 / 8-bit variants of NRV2E respectively; this implementation is LE32). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Nrv2eBuildingBlock` | `Nrv2eBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `DecompressRawByte` | `static byte[] DecompressRawByte(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2E 8-bit stream (no 4-byte size prefix). UPX compression method 10 uses this width — bits are packed into single bytes and consumed MSB-first. | -| `DecompressRawLe16` | `static byte[] DecompressRawLe16(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2E LE16 stream (no 4-byte size prefix). UPX compression method 9 uses this width — bits are packed into 16-bit little-endian words and consumed MSB-first. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare NRV2E LE32 stream (no 4-byte size prefix) into a freshly-allocated buffer of exactly `exactOutputSize` bytes. Exposed for callers parsing UPX binaries or other embedded NRV2E streams. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Parsing` - -[`DefaultLzCostModel`](#defaultlzcostmodel) · [`FixedLzCostModel`](#fixedlzcostmodel) · [`ILzCostModel`](#ilzcostmodel) · [`Lz77OptimalParser`](#lz77optimalparser) · [`Lz77OptimalParser.MatchProvider`](#lz77optimalparsermatchprovider) · [`LzParseToken`](#lzparsetoken) - -#### `DefaultLzCostModel` - -A simple, codec-agnostic cost model for `Lz77OptimalParser`. - -Implements `ILzCostModel`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultLzCostModel` | `DefaultLzCostModel(double literalBits = 9, double matchTokenBits = 9)` | Creates a cost model. | -| `Instance` | `static DefaultLzCostModel Instance { get; }` | A shared instance using the default parameters. | -| `LiteralCost` | `double LiteralCost(byte value)` | | -| `MatchCost` | `double MatchCost(int length, int distance)` | | - -#### `FixedLzCostModel` - -A flat cost model for `Lz77OptimalParser`: every literal costs a fixed amount and every match costs a fixed amount, regardless of length or distance. This matches codecs whose token serialization is fixed-width (e.g. 2 bytes per literal, 5 bytes per match), so the optimal parser minimizes the exact serialized size. - -Implements `ILzCostModel`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FixedLzCostModel` | `FixedLzCostModel(double literalBits, double matchBits)` | Creates a flat cost model. | -| `LiteralCost` | `double LiteralCost(byte value)` | | -| `MatchCost` | `double MatchCost(int length, int distance)` | | - -#### `ILzCostModel` - -Pluggable cost model for `Lz77OptimalParser`. It reports the estimated bit-cost of encoding a literal or a (length, distance) match. The parser minimises the total reported cost, so any encoder-aware model (fixed, length/distance-bucketed, Huffman, or range-coder-aware) can be injected without changing the parser. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LiteralCost` | `double LiteralCost(byte value)` | Estimated bit-cost of emitting a single literal byte. | -| `MatchCost` | `double MatchCost(int length, int distance)` | Estimated bit-cost of emitting a (length, distance) match. | - -#### `Lz77OptimalParser` - -A reusable, codec-agnostic forward cost-based optimal LZ77 parser. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz77OptimalParser` | `Lz77OptimalParser(ILzCostModel costModel, int minMatch = 3, int maxMatch = 258, int niceLength = 128)` | Creates an optimal parser. | -| `Parse` | `List Parse(ReadOnlySpan data, MatchProvider matchProvider)` | Computes the minimum-cost LZ parse of `data`. | - -#### `Lz77OptimalParser.MatchProvider` - -Supplies the best match at a position, or a zero-length match if none exists. Decoupling this from the parser keeps the primitive reusable across match finders. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MatchProvider` | `Match Lz77OptimalParser.MatchProvider(ReadOnlySpan data, int position)` | Supplies the best match at a position, or a zero-length match if none exists. Decoupling this from the parser keeps the primitive reusable across match finders. | - -#### `LzParseToken` - -An abstract LZ token produced by `Lz77OptimalParser`. A token is either a single literal byte or a (distance, length) back-reference. The token deliberately carries no bitstream encoding — a codec turns tokens into bytes. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzParseToken` | `LzParseToken(bool IsLiteral, byte Literal, int Distance, int Length)` | An abstract LZ token produced by `Lz77OptimalParser`. A token is either a single literal byte or a (distance, length) back-reference. The token deliberately carries no bitstream encoding — a codec turns tokens into bytes. | -| `Distance` | `int Distance { get; init; }` | The back-reference distance (valid when `IsLiteral` is `false`). | -| `IsLiteral` | `bool IsLiteral { get; init; }` | `true` for a literal byte; `false` for a match. | -| `Length` | `int Length { get; init; }` | The match length (valid when `IsLiteral` is `false`). | -| `Literal` | `byte Literal { get; init; }` | The literal byte value (valid when `IsLiteral` is `true`). | -| `CreateLiteral` | `static LzParseToken CreateLiteral(byte value)` | Creates a literal token. | -| `CreateMatch` | `static LzParseToken CreateMatch(int distance, int length)` | Creates a match token. | - -### Namespace `Compression.Core.Dictionary.Pithy` - -[`PithyBuildingBlock`](#pithybuildingblock) - -#### `PithyBuildingBlock` - -Pithy — John Engelhart's fast LZ77 compressor, deliberately similar in shape to Google's Snappy but with an incompatible tag layout: a third copy tier with a 3-byte offset replaces Snappy's 4-byte-offset tier, trading maximum window size (16 MiB instead of 4 GiB) for a shorter encoding of large-window matches. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PithyBuildingBlock` | `PithyBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Ppm` - -[`PpmBuildingBlock`](#ppmbuildingblock) · [`PpmCompressor`](#ppmcompressor) - -#### `PpmBuildingBlock` - -Exposes PPM (Prediction by Partial Matching) as a benchmarkable building block: an order-3 finite-context model with escape method C and full exclusion, driving a Witten-Neal-Cleary arithmetic coder. See `PpmCompressor` for the full algorithm description and citations. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmBuildingBlock` | `PpmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `PpmCompressor` - -A clean-room implementation of PPM (Prediction by Partial Matching): a finite-context statistical model whose symbol predictions are driven into an adaptive arithmetic coder, so that a symbol which the model considers likely costs a fraction of a bit rather than a whole byte. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MaxOrder` | `const int MaxOrder` | The longest context the model keeps. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data with an order-`MaxOrder` PPM model driving an arithmetic coder. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses data previously produced by `Compress`. | - -### Namespace `Compression.Core.Dictionary.Quantum` - -[`QuantumBuildingBlock`](#quantumbuildingblock) · [`QuantumCompressor`](#quantumcompressor) · [`QuantumCompressor.Folder`](#quantumcompressorfolder) · [`QuantumDecompressor`](#quantumdecompressor) · [`QuantumDecompressor.FolderReader`](#quantumdecompressorfolderreader) - -#### `QuantumBuildingBlock` - -Exposes Quantum as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `QuantumBuildingBlock` | `QuantumBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `QuantumCompressor` - -Writes Quantum as a cabinet carries it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressBlocks` | `static IReadOnlyList CompressBlocks(ReadOnlySpan data, int windowBits)` | Compresses everything as one folder, as the run of data blocks a cabinet carries it in. | -| `CompressFolder` | `static Folder CompressFolder(ReadOnlySpan data, int offset, int windowBits)` | Compresses as much of `data` from `offset` as one folder may hold. | -| `Compress` | `static IReadOnlyList Compress(ReadOnlySpan data, int windowBits)` | Compresses everything, as the sequence of folders a cabinet should hold. | - -#### `QuantumCompressor.Folder` - -One folder's worth of compressed data. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Folder` | `Folder(byte[] Compressed, int Consumed)` | One folder's worth of compressed data. | -| `Compressed` | `byte[] Compressed { get; init; }` | The block a cabinet should carry. | -| `Consumed` | `int Consumed { get; init; }` | How many plain bytes it covers. | - -#### `QuantumDecompressor` - -Reads Quantum as a cabinet carries it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlyMemory compressed, int uncompressedSize, int windowBits)` | Decompresses one folder's block. | - -#### `QuantumDecompressor.FolderReader` - -Reads the data blocks of one folder, which share their models. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FolderReader` | `FolderReader(int windowBits)` | Starts a folder. | -| `ReadBlock` | `byte[] ReadBlock(ReadOnlyMemory compressed, int uncompressedSize)` | Reads the next block. | - -### Namespace `Compression.Core.Dictionary.QuickLz` - -[`QuickLzBuildingBlock`](#quicklzbuildingblock) · [`QuickLzCompressor`](#quicklzcompressor) · [`QuickLzDecompressor`](#quicklzdecompressor) - -#### `QuickLzBuildingBlock` - -Exposes QuickLZ level-1 style compression as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. Reference: Lasse Mikkel Reinhold, "QuickLZ", http://www.quicklz.com/. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `QuickLzBuildingBlock` | `QuickLzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `QuickLzCompressor` - -Implements a QuickLZ level-1 style compressor from the public algorithm description: Lasse Mikkel Reinhold, "QuickLZ — fast compression library", http://www.quicklz.com/ — a hash-matched LZ77 variant with a 32-bit control word (one bit per token) and matches that reference a 4096-entry hash table by bucket index rather than by raw distance. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses `data` using the QuickLZ level-1 control-word format. | - -#### `QuickLzDecompressor` - -Decodes the QuickLZ level-1 style control-word format produced by `QuickLzCompressor`. Reference: http://www.quicklz.com/. Mirrors the compressor's queued hash-table synchronization exactly (see remarks there): a position's hash entry only becomes visible once its 3-byte window is fully decoded. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, int originalLength)` | Decompresses a QuickLZ stream. | - -### Namespace `Compression.Core.Dictionary.Rar` - -[`Rar1Decoder`](#rar1decoder) · [`Rar2Decoder`](#rar2decoder) · [`Rar3BuildingBlock`](#rar3buildingblock) · [`Rar3Decoder`](#rar3decoder) · [`Rar3Encoder`](#rar3encoder) · [`Rar5Decoder`](#rar5decoder) · [`Rar5Encoder`](#rar5encoder) · [`RarBuildingBlock`](#rarbuildingblock) - -#### `Rar1Decoder` - -Decompressor for RAR v1.x archives (UnPack 1.5 algorithm). Uses static Huffman tables and a 64 KB sliding window. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar1Decoder` | `Rar1Decoder()` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan compressed, int unpackedSize)` | Decompresses RAR v1.x data. | - -#### `Rar2Decoder` - -Decompressor for RAR v2.x archives (UnPack 2.0 algorithm). Uses 3 adaptive Huffman tables (main, distance, length) and a sliding window. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar2Decoder` | `Rar2Decoder()` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan compressed, int unpackedSize)` | Decompresses RAR v2.x data. | - -#### `Rar3BuildingBlock` - -Exposes the classic RAR compression algorithm (the RAR3/RAR4-era method) as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar3BuildingBlock` | `Rar3BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Rar3Decoder` - -Decompressor for RAR v3.x/v4.x archives (UnPack 2.9 algorithm). Uses LZ77 + multi-table adaptive Huffman with repeated offsets and PPMd fallback. 4 Huffman tables: Main(299) + Dist(60) + LowDist(17) + RepLen(28). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar3Decoder` | `Rar3Decoder()` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan compressed, int unpackedSize, int windowBits = 22)` | Decompresses RAR v3.x/v4.x data. | - -#### `Rar3Encoder` - -RAR3 LZ+Huffman compression engine. Encodes data using adaptive multi-table Huffman coding with LZ77 match references, producing output compatible with `Rar3Decoder` and real WinRAR. 4 Huffman tables: Main(299) + Dist(60) + LowDist(17) + RepLen(28). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar3Encoder` | `Rar3Encoder(int windowBits = 22)` | Initializes a new `Rar3Encoder` with the specified window size. | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compresses data using the RAR3 algorithm. | - -#### `Rar5Decoder` - -RAR5 LZ+Huffman decompression engine. Decodes compressed data using adaptive multi-table Huffman coding with LZ77 match references and optional post-processing filters. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar5Decoder` | `Rar5Decoder(int dictionarySize)` | Initializes a new `Rar5Decoder` with the specified dictionary size. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan compressed, int uncompressedSize)` | Decompresses RAR5-compressed data. | - -#### `Rar5Encoder` - -RAR5 LZ+Huffman compression engine. Encodes data using adaptive multi-table Huffman coding with LZ77 match references, producing output compatible with `Rar5Decoder` and 7z. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar5Encoder` | `Rar5Encoder(int dictionarySize = 131072)` | Initializes a new `Rar5Encoder` with the specified dictionary size. | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compresses data using the RAR5 algorithm. | - -#### `RarBuildingBlock` - -Exposes the RAR5 compression algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RarBuildingBlock` | `RarBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.RePair` - -[`RePairBuildingBlock`](#repairbuildingblock) - -#### `RePairBuildingBlock` - -Exposes Re-Pair (Recursive Pairing) as a benchmarkable building block. An offline grammar-based compression algorithm that repeatedly replaces the most frequent pair of adjacent symbols with a new non-terminal, building a straight-line grammar. The grammar rules and final sequence are then serialized. The sequence lives in a doubly linked list over the original slot numbers, so a slot's number never changes and list order is always slot order. Pair frequencies are counted once and then maintained incrementally: a substitution only disturbs the two neighbouring positions, so a round costs work proportional to the substitutions it makes rather than to the sequence length. Reference: N. J. Larsson and A. Moffat, "Off-Line Dictionary-Based Compression", Proceedings of the IEEE 88(11), 2000, pp. 1722-1732. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RePairBuildingBlock` | `RePairBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Rolz` - -[`RolzBuildingBlock`](#rolzbuildingblock) - -#### `RolzBuildingBlock` - -Exposes ROLZ (Reduced-Offset LZ) as a benchmarkable building block. Uses context-based match tables to reduce offset encoding cost. The previous byte determines which of 256 offset tables to search for matches. Each context maintains a circular buffer of up to 256 recent positions. Header: 4-byte LE uncompressed size, then a bitstream of literals and matches. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RolzBuildingBlock` | `RolzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Rzip` - -[`RollingHashMatcher`](#rollinghashmatcher) · [`RzipToken`](#rziptoken) - -#### `RollingHashMatcher` - -Rolling hash block matcher (rsync-style) for long-distance deduplication. Finds matching blocks across large distances using a Rabin-like rolling hash. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RollingHashMatcher` | `RollingHashMatcher(int blockSize = 4096)` | Initializes a new `RollingHashMatcher` with the specified block size. | -| `BlockSize` | `int BlockSize { get; }` | Block size for hash computation. | -| `FindMatches` | `List FindMatches(byte[] input, byte[] reference)` | Find matching blocks in the input against the indexed reference. Returns list of tokens representing literal ranges and matches against the reference. | -| `Index` | `void Index(byte[] data)` | Index the reference data by computing rolling hashes at block boundaries. | - -#### `RzipToken` - -Token representing a literal range or a match against reference data. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RzipToken` | `RzipToken(int InputOffset, int Length, int ReferenceOffset, bool IsLiteral)` | Token representing a literal range or a match against reference data. | -| `InputOffset` | `int InputOffset { get; init; }` | Offset into the input array where this token starts. | -| `IsLiteral` | `bool IsLiteral { get; init; }` | `true` if this token represents literal bytes; `false` for a back-reference match. | -| `Length` | `int Length { get; init; }` | Length in bytes of the literal data or the match. | -| `ReferenceOffset` | `int ReferenceOffset { get; init; }` | Absolute offset into the reference/output data for matches, or -1 for literals. | - -### Namespace `Compression.Core.Dictionary.Salvador` - -[`SalvadorBuildingBlock`](#salvadorbuildingblock) - -#### `SalvadorBuildingBlock` - -Salvador — Emmanuel Marty's ZX0-based compressor with inverted Elias-gamma offset encoding, used by Amiga 4K/64K demoscene productions. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SalvadorBuildingBlock` | `SalvadorBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compress `data` with a 4-byte little-endian original-size prefix followed by a bare Salvador stream. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare Salvador / ZX0-inverted stream (no 4-byte size prefix) into a freshly-allocated buffer of exactly `exactOutputSize` bytes. Exposed for callers parsing embedded Salvador streams (Amiga intros/cruncher stubs). | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | Decompress a 4-byte-prefixed Salvador payload. | - -### Namespace `Compression.Core.Dictionary.Sequitur` - -[`SequiturBuildingBlock`](#sequiturbuildingblock) · [`SequiturCompressor`](#sequiturcompressor) - -#### `SequiturBuildingBlock` - -Exposes Sequitur as a benchmarkable building block: an online algorithm that infers a straight-line context-free grammar from the input by enforcing digram uniqueness and rule utility as each symbol is appended, so repeated phrases collapse into rules and repeated sequences of rules collapse in turn. See `SequiturCompressor` for the full algorithm description and citation. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SequiturBuildingBlock` | `SequiturBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `SequiturCompressor` - -A clean-room implementation of Sequitur: an online algorithm that infers a straight-line context-free grammar from a sequence in a single left-to-right pass by continuously enforcing two invariants as each symbol is appended. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data by inferring a Sequitur grammar and serialising its rules and start sequence. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses data previously produced by `Compress` by expanding the serialised grammar's start sequence. | - -### Namespace `Compression.Core.Dictionary.Shoco` - -[`ShocoBuildingBlock`](#shocobuildingblock) - -#### `ShocoBuildingBlock` - -Exposes a Shoco-style short-string compressor as a benchmarkable building block. Shoco (Christian Schramm / "Ed-von-Schleck", 2014) compresses short ASCII strings by keeping a small alphabet of the most common characters and, for runs of consecutive alphabet characters, encoding each character after the first as the rank of its predecessor's most likely successors rather than the character itself — most natural-language digraphs need only a few bits to identify. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShocoBuildingBlock` | `ShocoBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Snappy` - -[`SnappyBuildingBlock`](#snappybuildingblock) · [`SnappyCompressor`](#snappycompressor) · [`SnappyConstants`](#snappyconstants) · [`SnappyDecompressor`](#snappydecompressor) - -#### `SnappyBuildingBlock` - -Exposes the Snappy algorithm as a benchmarkable building block. Snappy's format is self-describing (varint size header), so no extra framing needed. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SnappyBuildingBlock` | `SnappyBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `SnappyCompressor` - -Compresses data using the Snappy block format. Snappy is a fast LZ77 variant with no entropy coding, designed for speed over ratio. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan source)` | Compresses the input data using Snappy block format. | - -#### `SnappyConstants` - -Constants for Snappy block compression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HashTableBits` | `const int HashTableBits` | Hash table bits. | -| `HashTableSize` | `const int HashTableSize` | Hash table size. | -| `MaxCopy1Offset` | `const int MaxCopy1Offset` | Maximum offset for copy-1 (11 bits). | -| `MaxCopy2Offset` | `const int MaxCopy2Offset` | Maximum offset for copy-2 (16 bits). | -| `MaxMatchLength` | `const int MaxMatchLength` | Maximum match length for copy-1/copy-2. | -| `MinMatch` | `const int MinMatch` | Minimum match length. | -| `StreamIdentifier` | `static readonly byte[] StreamIdentifier` | Snappy framing format magic chunk identifier. | -| `TagCopy1` | `const int TagCopy1` | Copy with 1-byte offset tag (bits 1:0 = 01). | -| `TagCopy2` | `const int TagCopy2` | Copy with 2-byte offset tag (bits 1:0 = 10). | -| `TagCopy4` | `const int TagCopy4` | Copy with 4-byte offset tag (bits 1:0 = 11). | -| `TagLiteral` | `const int TagLiteral` | Literal tag (bits 1:0 = 00). | - -#### `SnappyDecompressor` - -Decompresses data in the Snappy block format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan source)` | Decompresses Snappy-compressed data. | -| `Decompress` | `static int Decompress(ReadOnlySpan source, Span dest)` | Decompresses Snappy-compressed data into an output buffer. | - -### Namespace `Compression.Core.Dictionary.Sqx` - -[`SqxAudioCodec`](#sqxaudiocodec) · [`SqxBuildingBlock`](#sqxbuildingblock) · [`SqxConstants`](#sqxconstants) · [`SqxDecoder`](#sqxdecoder) · [`SqxEncoder`](#sqxencoder) · [`SqxMultimediaCodec`](#sqxmultimediacodec) - -#### `SqxAudioCodec` - -SQX audio compressor/decompressor using polynomial prediction and Golomb-Rice coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize)` | Decompresses 8-bit audio data. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Compresses 8-bit audio data using polynomial prediction + Golomb-Rice. | - -#### `SqxBuildingBlock` - -Exposes the SQX LZH compression algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxBuildingBlock` | `SqxBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `SqxConstants` - -Constants for the SQX compression algorithm (V11 and V20). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | Block size in symbols. | -| `CodeFlatTabs` | `const int CodeFlatTabs` | Huffman table encoding: use flat 4-bit lengths. | -| `CodeFourTrees` | `const int CodeFourTrees` | Four Huffman trees mode (V20 extended). | -| `CodeThreeTrees` | `const int CodeThreeTrees` | Three Huffman trees mode. | -| `CodeTreeTabs` | `const int CodeTreeTabs` | Huffman table encoding: use pre-tree for code lengths. | -| `DefaultDictSize` | `const int DefaultDictSize` | Default dictionary size (32KB). | -| `DistCodes1M` | `const int DistCodes1M` | Distance codes for 1MB dictionary. | -| `DistCodes2M` | `const int DistCodes2M` | Distance codes for 2MB dictionary. | -| `DistCodes4M` | `const int DistCodes4M` | Distance codes for 4MB dictionary. | -| `DupLastSymbol` | `const int DupLastSymbol` | Duplicate-last-match symbol (reuse last length + distance). | -| `Len2Codes` | `const int Len2Codes` | Number of length-2 match symbols (261-268). | -| `Len2ExtraBits` | `static readonly int[] Len2ExtraBits` | Extra bits for length-2 match distances. | -| `Len2Offsets` | `static readonly int[] Len2Offsets` | Distance base values for length-2 matches. | -| `Len2Start` | `const int Len2Start` | First length-2 match symbol (261). | -| `Len3Codes` | `const int Len3Codes` | Number of length-3 match symbols (269-283). | -| `Len3ExtraBits` | `static readonly int[] Len3ExtraBits` | Extra bits for length-3 match distances. | -| `Len3Offsets` | `static readonly int[] Len3Offsets` | Distance base values for length-3 matches. | -| `Len3Start` | `const int Len3Start` | First length-3 match symbol (269). | -| `LenCodes` | `const int LenCodes` | Number of length-4+ match symbols (284-308). | -| `LenExtraBits` | `static readonly int[] LenExtraBits` | Extra bits for length-4+ matches. | -| `LenOffsets` | `static readonly int[] LenOffsets` | Length base values for length-4+ matches. | -| `LenStart` | `const int LenStart` | First length-4+ match symbol (284). | -| `LitCodes` | `const int LitCodes` | Number of literal symbols (0-255). | -| `LzBlockType` | `const int LzBlockType` | Block type bit: 0 = LZ block, 1 = multimedia block. | -| `MainTreeMaxBits` | `const int MainTreeMaxBits` | Max code length in main/distance trees. | -| `MaxDictSize` | `const int MaxDictSize` | Maximum dictionary size (4MB). | -| `MaxDistCodes` | `const int MaxDistCodes` | Number of distance tree symbols (depends on dict size, max 56). | -| `MaxDistLen2` | `const int MaxDistLen2` | Maximum distance for a length-2 match (255). | -| `MaxDistLen3` | `const int MaxDistLen3` | Maximum distance for a length-3 match (16383). | -| `MaxDistLen4` | `const int MaxDistLen4` | Maximum distance for a length-4+ match (262143). | -| `MinMatch` | `const int MinMatch` | Minimum match length. | -| `NC` | `const int NC` | Total main Huffman tree symbols (310). | -| `PreTreeMaxBits` | `const int PreTreeMaxBits` | Max code length in pre-tree. | -| `PreTreeSymbols` | `const int PreTreeSymbols` | Pre-tree symbol count (codes 0-15 + RLE 16,17,18). | -| `RepCodes` | `const int RepCodes` | Number of repeated-offset symbols (257-260). | -| `RepStart` | `const int RepStart` | First repeated-offset symbol (257). | -| `GetDistSlots` | `static int GetDistSlots(int dictSize)` | Gets the number of distance tree symbols for a given dictionary size. | -| `GetLen2DistCode` | `static int GetLen2DistCode(int distance)` | Gets the length-2 distance code index. | -| `GetLen3DistCode` | `static int GetLen3DistCode(int distance)` | Gets the length-3 distance code index. | -| `GetLenCode` | `static int GetLenCode(int length)` | Gets the length-4+ symbol index for a given raw match length. | - -#### `SqxDecoder` - -Decodes SQX LZH compressed data using the real 310-symbol alphabet. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxDecoder` | `SqxDecoder(int dictSize = 32768)` | Initializes a new SQX decoder. | -| `Decode` | `byte[] Decode(byte[] compressed, int originalSize)` | Decompresses SQX LZH data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize, int dictSize)` | Static convenience method for non-solid single-file decoding. | -| `Reset` | `void Reset()` | Resets decoder state (for non-solid mode between files). | - -#### `SqxEncoder` - -Encodes data using the real SQX LZH compression (310-symbol alphabet). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxEncoder` | `SqxEncoder(int dictSize = 32768)` | Initializes a new SQX encoder. | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using the SQX LZH algorithm. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int dictSize)` | Static convenience method for non-solid single-file encoding. | -| `Reset` | `void Reset()` | Resets encoder state (for non-solid mode between files). | - -#### `SqxMultimediaCodec` - -SQX multimedia compressor/decompressor using delta coders (E0-E4) and arithmetic coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize)` | Decompresses multimedia data. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Compresses multimedia data using automatic delta order selection + arithmetic coding. | - -### Namespace `Compression.Core.Dictionary.SuffixTree` - -[`SuffixTreeBuildingBlock`](#suffixtreebuildingblock) - -#### `SuffixTreeBuildingBlock` - -Exposes suffix-tree-indexed dictionary compression as a benchmarkable building block. At every position the longest previously-started factor is emitted as a (length, offset) token and unmatched bytes are batched into literal-run tokens (a 1-byte count followed by the raw bytes), so that non-repetitive stretches only cost a small, amortized header instead of two bytes per literal. The dictionary is the set of positions the factorization has already visited. Written out as a suffix trie, each visited position `j` inserts the whole path `data[j .. j+min(255, n-j))` and stamps every node on it with `j`, which makes the query at position `i` exactly `length = min(255, n-i, max over visited j < i of LCP(j, i))` paired with the largest visited `j` reaching that length. Both are read off a suffix array instead: a longest common prefix is the minimum of the LCP array between two ranks, the maximum over a set of positions is attained at the nearest visited rank to either side, and the positions sharing at least that many characters form one contiguous rank interval whose most recent member answers the offset. That is the same factorization a trie yields, in O(n log n) time and O(n) memory rather than one heap object per distinct substring. Reference: P. Weiner, "Linear Pattern Matching Algorithms", 1973 (suffix trees); E. Ukkonen, "On-line construction of suffix trees", Algorithmica 14, 1995; T. Kasai & al., "Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Applications", CPM 2001; M. Crochemore & al., "Algorithms on Strings", Cambridge University Press, 2007 (suffix-array-driven LZ factorization). See also https://en.wikipedia.org/wiki/Suffix_tree - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SuffixTreeBuildingBlock` | `SuffixTreeBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Xpress` - -[`XpressBuildingBlock`](#xpressbuildingblock) · [`XpressCompressionLevel`](#xpresscompressionlevel) · [`XpressCompressor`](#xpresscompressor) · [`XpressConstants`](#xpressconstants) · [`XpressDecompressor`](#xpressdecompressor) · [`XpressHuffmanCompressor`](#xpresshuffmancompressor) · [`XpressHuffmanDecompressor`](#xpresshuffmandecompressor) - -#### `XpressBuildingBlock` - -Exposes the XPRESS Huffman algorithm as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XpressBuildingBlock` | `XpressBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `XpressCompressionLevel` - -Compression level for XPRESS (plain and Huffman variants). - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fast` | `0` | Fast compression: chain depth 16. | -| `Normal` | `1` | Normal compression: chain depth 128. | -| `Best` | `2` | Best compression: chain depth 512. | - -#### `XpressCompressor` - -Compresses data using the XPRESS (LZ Xpress plain) algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XpressCompressor` | `XpressCompressor(XpressCompressionLevel level)` | Initializes a new `XpressCompressor` with the specified compression level. | -| `XpressCompressor` | `XpressCompressor(int maxChainDepth = 128)` | Initializes a new `XpressCompressor`. | -| `Compress` | `byte[] Compress(ReadOnlySpan input)` | Compresses `input` and returns the compressed bytes. | -| `Compress` | `void Compress(ReadOnlySpan input, Stream output)` | Compresses `input` and writes the result to `output`. | - -#### `XpressConstants` - -Constants for the XPRESS (LZ Xpress) compression algorithm used in WIM images and NTFS compression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FlagGroupSize` | `const int FlagGroupSize` | Number of flag bits per flag group (one 32-bit flag word covers 32 items). | -| `HuffChunkSize` | `const int HuffChunkSize` | Uncompressed chunk size for the XPRESS Huffman variant (64 KiB). | -| `HuffMaxCodeLength` | `const int HuffMaxCodeLength` | Maximum Huffman code length for the XPRESS Huffman variant. | -| `HuffMaxMatch` | `const int HuffMaxMatch` | Longest match the XPRESS Huffman variant can name: a length past this has no room in the sixteen bits that carry it. | -| `HuffSymbolCount` | `const int HuffSymbolCount` | Number of symbols in the XPRESS Huffman alphabet (256 literals + 256 match symbols). | -| `HuffTableHeaderBytes` | `const int HuffTableHeaderBytes` | Size in bytes of the Huffman table header in each chunk (512 nibbles = 256 bytes). | -| `HuffWindowSize` | `const int HuffWindowSize` | Largest match offset the XPRESS Huffman variant can name. The symbol carries the offset's power of two in four bits, so an offset of 65 536 would need a seventeenth one and a symbol past the end of the alphabet. | -| `LengthSentinel16` | `const int LengthSentinel16` | The sentinel value in the 16-bit length field indicating a 32-bit length follows. | -| `LengthSentinel8` | `const int LengthSentinel8` | The sentinel value in the extended-length byte stream indicating a 16-bit length follows. | -| `MaxMatch` | `const int MaxMatch` | Maximum representable match length (limited by the multi-byte length encoding). | -| `MinMatch` | `const int MinMatch` | Minimum match length. | -| `WindowSize` | `const int WindowSize` | Maximum sliding window size (8192 bytes — 13-bit offset field). | - -#### `XpressDecompressor` - -Decompresses data compressed with the XPRESS (LZ Xpress plain) algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan input, int uncompressedSize)` | Decompresses XPRESS-encoded data from a byte span. | -| `Decompress` | `static byte[] Decompress(Stream input, int uncompressedSize)` | Decompresses XPRESS-encoded data from a stream. | - -#### `XpressHuffmanCompressor` - -Compresses data using the XPRESS Huffman variant, as used by WIM images and by Windows wherever "Xpress Huffman" is named. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XpressHuffmanCompressor` | `XpressHuffmanCompressor(int maxChainDepth = 128)` | Initializes a new `XpressHuffmanCompressor`. | -| `Compress` | `byte[] Compress(ReadOnlySpan input)` | Compresses `input` and returns the compressed bytes. | -| `Compress` | `void Compress(ReadOnlySpan input, Stream output)` | Compresses `input` and writes the result to `output`. | - -#### `XpressHuffmanDecompressor` - -Decompresses data compressed with the XPRESS Huffman variant. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan input, int uncompressedSize)` | Decompresses XPRESS Huffman-encoded data. | -| `Decompress` | `static byte[] Decompress(Stream input, int uncompressedSize)` | Decompresses XPRESS Huffman-encoded data from a stream. | - -### Namespace `Compression.Core.Dictionary.Zip` - -[`ImplodeBuildingBlock`](#implodebuildingblock) · [`ImplodeDecoder`](#implodedecoder) · [`ImplodeEncoder`](#implodeencoder) · [`ReduceBuildingBlock`](#reducebuildingblock) · [`ReduceDecoder`](#reducedecoder) · [`ReduceEncoder`](#reduceencoder) · [`ShrinkBuildingBlock`](#shrinkbuildingblock) · [`ShrinkDecoder`](#shrinkdecoder) · [`ShrinkEncoder`](#shrinkencoder) - -#### `ImplodeBuildingBlock` - -Exposes PKWARE ZIP Implode (method 6) as a benchmarkable building block. Implode is an LZ77 variant with a 4K or 8K sliding dictionary whose literals, lengths and distances are Shannon-Fano coded. The raw `ImplodeDecoder` needs the decompressed size and the two header flags (literal tree present, 8K dictionary), so the building block prepends a 4-byte little-endian length header followed by a single flags byte (bit 0 = literal tree, bit 1 = 8K dictionary). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ImplodeBuildingBlock` | `ImplodeBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ImplodeDecoder` - -Decodes ZIP Implode (method 6) compressed data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan compressed, int originalSize, bool hasLiteralTree, bool is8kDictionary)` | Decompresses ZIP Implode data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize, bool hasLiteralTree, bool is8kDictionary)` | Decompresses ZIP Implode data. | - -#### `ImplodeEncoder` - -Encodes data using the ZIP Implode (method 6) algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, bool useLiteralTree = true, bool use8kDictionary = true)` | Compresses data using the ZIP Implode algorithm. | - -#### `ReduceBuildingBlock` - -Exposes PKWARE ZIP Reduce (methods 2-5) as a benchmarkable building block. Reduce is a probabilistic byte predictor (the "compression factor" selects the follower-set width) followed by a run-length expansion stage. The raw `ReduceDecoder` needs both the decompressed size and the factor, so the building block prepends a 4-byte little-endian length header followed by a single factor byte. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ReduceBuildingBlock` | `ReduceBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ReduceDecoder` - -Decodes ZIP Reduce (methods 2-5) compressed data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan compressed, int originalSize, int factor)` | Decompresses ZIP Reduce data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize, int factor)` | Decompresses ZIP Reduce data. | - -#### `ReduceEncoder` - -Encodes data using the ZIP Reduce (methods 2-5) algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int factor = 4)` | Compresses data using the ZIP Reduce algorithm. | - -#### `ShrinkBuildingBlock` - -Exposes PKWARE ZIP Shrink (method 1) as a benchmarkable building block. Shrink is LZW with 9-13 bit variable-width codes plus a partial-clear mechanism (control code 256). The raw `ShrinkDecoder` needs the decompressed size, so the building block prepends a 4-byte little-endian length header (matching the convention used by the other size-bearing blocks). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinkBuildingBlock` | `ShrinkBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ShrinkDecoder` - -Decodes ZIP Shrink (method 1) compressed data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan compressed, int originalSize)` | Decompresses ZIP Shrink data. | -| `Decode` | `static byte[] Decode(byte[] compressed, int originalSize)` | Decompresses ZIP Shrink data. | - -#### `ShrinkEncoder` - -Encodes data using the ZIP Shrink (method 1) algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Compresses data using the ZIP Shrink algorithm. | - -### Namespace `Compression.Core.Dictionary.Zling` - -[`ZlingBuildingBlock`](#zlingbuildingblock) - -#### `ZlingBuildingBlock` - -Exposes a Zling-style LZ77 + Huffman hybrid as a benchmarkable building block. Zling (libzling, by Zhang Li / "richox") pairs an order-1 ROLZ dictionary stage with Huffman entropy coding to get most of LZMA's ratio at a fraction of its cost. This building block follows the same two-stage shape — a windowed LZ77 dictionary pass (see `ZlingLz`) followed by canonical Huffman coding of the resulting token stream — using plain LZ77 in place of ROLZ as a clean-room simplification of the offset-reduction scheme. Reference: https://github.com/richox/libzling (algorithm description); D. A. Huffman, "A Method for the Construction of Minimum-Redundancy Codes", 1952. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZlingBuildingBlock` | `ZlingBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Dictionary.Zstd` - -[`ZstdDictionary`](#zstddictionary) - -#### `ZstdDictionary` - -Represents a parsed Zstandard dictionary (RFC 8878 Section 5) that can be used to initialize decompression/compression state for dictionary-compressed frames. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DictionaryMagic` | `const uint DictionaryMagic` | Magic number identifying a Zstd dictionary (0xEC30A437). | -| `Content` | `byte[] Content { get; }` | Gets the dictionary content that prepopulates the sliding window. | -| `DictionaryId` | `uint DictionaryId { get; }` | Gets the dictionary identifier. | -| `RawPayload` | `byte[] RawPayload { get; }` | Gets the raw entropy tables and content payload (everything after the 8-byte header). When entropy table parsing is wired into the decompressor, this provides the complete payload for on-demand decoding of Huffman and FSE tables. | -| `RepeatOffsets` | `int[] RepeatOffsets { get; }` | Gets the initial repeat offsets derived from the dictionary content. Per the specification, these are initialized from the last bytes of the content. | -| `CreateRaw` | `static ZstdDictionary CreateRaw(uint dictionaryId, byte[] content)` | Creates a raw (content-only) dictionary without entropy tables. This is used when the dictionary is just history data to prepopulate the window. | -| `GetContentForWindow` | `ReadOnlySpan GetContentForWindow()` | Returns the content bytes suitable for prepopulating a sliding window. | -| `Parse` | `static ZstdDictionary Parse(ReadOnlySpan data)` | Parses a Zstd dictionary from raw bytes. | -| `ToBytes` | `byte[] ToBytes()` | Serializes this dictionary to the standard Zstd dictionary format. | - -### Namespace `Compression.Core.Dictionary.Zx0` - -[`Zx0BuildingBlock`](#zx0buildingblock) - -#### `Zx0BuildingBlock` - -ZX0 — Einar Saukas's LZ77-family compressor for the ZX Spectrum and modern demoscene productions. Encodes literal runs and back-references with an interlaced Elias-gamma bit stream packed alongside raw literal/offset bytes. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Zx0BuildingBlock` | `Zx0BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compress `data` with a 4-byte little-endian original-size prefix followed by a bare ZX0 stream. | -| `DecompressRaw` | `static byte[] DecompressRaw(ReadOnlySpan compressed, int exactOutputSize)` | Decompresses a bare ZX0 stream (no 4-byte size prefix) into a freshly-allocated buffer of exactly `exactOutputSize` bytes. Exposed for callers parsing ZX0-wrapped binaries (crunched ZX Spectrum TAPs, demoscene 4K/64K intros). | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | Decompress a 4-byte-prefixed ZX0 payload. | - -### Namespace `Compression.Core.DiskImage` - -[`ApmParser`](#apmparser) · [`BsdDisklabelParser`](#bsddisklabelparser) · [`ClusterAllocator`](#clusterallocator) · [`DeferredPayloads`](#deferredpayloads) · [`ExtBlockGroupGeometry`](#extblockgroupgeometry) · [`ExtBlockGroupGeometry.ExtGeometry`](#extblockgroupgeometryextgeometry) · [`ExtentCopy`](#extentcopy) · [`FilePayload`](#filepayload) · [`GptParser`](#gptparser) · [`ImageAccessor`](#imageaccessor) · [`MbrParser`](#mbrparser) · [`MbrWrapper`](#mbrwrapper) · [`MbrWrapper.PartitionType`](#mbrwrapperpartitiontype) · [`PartitionEditor`](#partitioneditor) · [`PartitionEntry`](#partitionentry) · [`PartitionScheme`](#partitionscheme) · [`PartitionTableDetector`](#partitiontabledetector) · [`PartitionTableDetector.DetectionResult`](#partitiontabledetectordetectionresult) · [`PartitionTableVerification`](#partitiontableverification) · [`PartitionType`](#partitiontype) · [`PartitionTypeDatabase`](#partitiontypedatabase) · [`PartitionTypeMapping`](#partitiontypemapping) · [`PartitionWindowStream`](#partitionwindowstream) · [`PartitionedDiskLister`](#partitioneddisklister) · [`SparseBlockImage`](#sparseblockimage) - -#### `ApmParser` - -Parses the Apple Partition Map (APM) as used on classic Mac OS 68k/PowerPC media and early Intel-Mac install images. The scheme is big-endian throughout. Block 0 optionally holds a Driver Descriptor Record (DDR) whose signature is `ER` (`0x4552`); its `sbBlkSize` field names the media block size (512 or 2048). The partition map itself begins at block 1: every entry is one block, tagged with the `PM` (`0x504D`) signature, and its `pmMapBlkCnt` field states how many entries the map contains.Only real partitions are enumerated; the map's self-descriptor (`Apple_partition_map`) and free-space runs (`Apple_Free`) are skipped. Partition types are surfaced verbatim (e.g. `Apple_HFS`, `Apple_HFSX`, `Apple_UFS`). References: Apple, "Inside Macintosh: Devices" — chapter 3, "SCSI Manager", partition-map layout (DDR + `Partition` structure).`https://en.wikipedia.org/wiki/Apple_Partition_Map` — field-level overview. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IsApm` | `static bool IsApm(ReadOnlySpan data)` | Checks whether the given header carries an Apple Partition Map. The check looks for the `PM` entry signature at block 1 for both supported block sizes, honouring a DDR block size where one is present. | -| `Parse` | `static List Parse(Stream diskData)` | Parses every real partition from an APM disk image. | - -#### `BsdDisklabelParser` - -Parses the 4.4BSD `disklabel` that FreeBSD/NetBSD/OpenBSD write into a BSD slice (an MBR partition of type `0xA5`/`0xA6`/`0xA9`, or a GPT FreeBSD partition). The label is a native little-endian structure — the on-disk byte order on the overwhelmingly common x86/amd64 media. The label is located at a fixed offset inside the slice: sector 1 (byte offset 512) on i386/amd64, or byte offset 64 within sector 0 on some other ports. It opens with `d_magic` (`0x82564557`), repeats the magic at `d_magic2`, records `d_npartitions`, and carries an array of 16-byte partition records (`p_size`, `p_offset` in sectors, `p_fsize`, `p_fstype`, …).Partition offsets follow the convention the Linux kernel BSD parser relies on: when the whole-slice `'c'` partition (slot 2) has `p_offset == 0` the offsets are slice-relative and the slice's own start sector is added; otherwise they are absolute disk sectors. The `'c'` whole-slice slot and zero-length slots are not enumerated. References: 4.4BSD, `sys/sys/disklabel.h` — `struct disklabel` / `struct partition` layout and `FS_*` filesystem-type constants.Linux kernel, `block/partitions/bsd.c` — the slice-relative-vs-absolute offset heuristic keyed on the `'c'` partition. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IsDisklabel` | `static bool IsDisklabel(Stream slice)` | Reports whether a BSD disklabel magic is present at either candidate offset within the given slice stream. | -| `Parse` | `static List Parse(Stream slice, long sliceStartByteOffset = 0)` | Parses the BSD disklabel contained in `slice` and returns its filesystem partitions. | - -#### `ClusterAllocator` - -Bitmap-backed cluster allocator for filesystem writers. Allocates contiguous cluster runs (first-fit); falls back to an automatic fast-defrag when no contiguous hole is big enough but the total free space suffices. Tracks freed clusters so they can be reused on subsequent allocations. Writers keep their own on-disk bitmap representation — this helper manages an in-memory view that's flushed to that bitmap by the writer. Decoupling means the allocator doesn't need to understand per-filesystem bitmap formats; it just exposes Allocate / Free / FastConsolidate over an opaque cluster index space `[0..clusterCount)`. Fast defrag notes: when `AllocateRun` can't find a contiguous run of the requested size but the total free count is sufficient, it invokes `FastConsolidate`, which asks the caller (via the `relocateCluster` callback) to move allocated clusters out of the way. The allocator never touches on-disk bytes itself — the caller does the byte-level copy and then reports success by returning the new cluster index. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ClusterAllocator` | `ClusterAllocator(int clusterCount)` | Builds an allocator managing `clusterCount` clusters, all initially free. | -| `ClusterCount` | `int ClusterCount { get; }` | Total cluster count under management. | -| `FreeCount` | `int FreeCount { get; }` | Count of free clusters remaining. | -| `AllocateRun` | `int AllocateRun(int count, Func relocateCluster = null)` | Allocates a contiguous run of `count` free clusters. Returns the starting cluster index, or `-1` if allocation failed even after fast-defrag attempts. Caller is responsible for writing data to the returned run. | -| `FreeRange` | `void FreeRange(int start, int count)` | Frees `count` clusters starting at `start`. | -| `Free` | `void Free(int cluster)` | Frees a previously-allocated cluster, returning it to the pool for reuse. | -| `IsUsed` | `bool IsUsed(int cluster)` | Returns true if `cluster` is currently allocated. | -| `ReserveRange` | `void ReserveRange(int start, int count)` | Marks `count` clusters starting at `start` as used. | -| `Reserve` | `void Reserve(int cluster)` | Marks `cluster` as used; used by writers during initial setup to exclude system areas (boot sector region, FAT area, MFT area) before user data. | - -#### `DeferredPayloads` - -File payloads a writer has placed but not yet emitted, each pinned to the byte offset it belongs at. Lets a writer lay out a volume without ever holding its contents. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeferredPayloads` | `DeferredPayloads()` | | -| `Count` | `int Count { get; }` | Number of payloads recorded. | -| `Add` | `void Add(long offset, FilePayload payload)` | Records that `payload` belongs at `offset`. | -| `Add` | `void Add(long offset, byte[] data)` | Records bytes at `offset`. | -| `FlushTo` | `void FlushTo(Stream output, long basePosition = 0)` | Copies every payload into `output` at its offset, relative to `basePosition`. Nothing larger than the copy buffer is resident at any point. | -| `Materialise` | `byte[] Materialise(SparseBlockImage image)` | Materialises `image` and fills in every payload, for callers that still need the whole volume as an array. | - -#### `ExtBlockGroupGeometry` - -Block-group arithmetic shared by the ext-family writers. ext1 and ext2/3/4 lay their groups out identically; only the superblock revision and magic differ. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BytesPerInode` | `static int BytesPerInode(long volumeBytes)` | Rounds the required inode count up to a sensible group size: every reserved/dir/file inode with headroom, never below the classic 128, and a multiple of 8 so the inode bitmap's byte boundaries stay tidy. | -| `ChooseInodeCount` | `static int ChooseInodeCount(int needed)` | | -| `Compute` | `static ExtGeometry Compute(int blockSize, int totalBlocks, int inodeSize, int neededInodes, int descriptorSize = 32)` | Works out how many block groups an ext-family volume needs and how the per-group metadata is sized. A group holds 8 * blockSize blocks because its block bitmap is a single block; anything larger takes more groups. Inodes are shared evenly across them, so a one-group volume ends up with exactly the geometry this writer produced before groups existed. | -| `DescriptorSize` | `static int DescriptorSize(ReadOnlySpan superblock)` | How wide one group descriptor is on the volume whose superblock this is. | - -#### `ExtBlockGroupGeometry.ExtGeometry` - -Block-group geometry derived from the block size and the volume size. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtGeometry` | `ExtGeometry(int TotalBlocks, int FirstDataBlock, int BlocksPerGroup, int GroupCount, int GdtBlocks, int InodesPerGroup, int InodeTableBlocks, int PerGroupMetaBlocks)` | Block-group geometry derived from the block size and the volume size. | -| `BlocksPerGroup` | `int BlocksPerGroup { get; init; }` | | -| `FirstDataBlock` | `int FirstDataBlock { get; init; }` | | -| `GdtBlocks` | `int GdtBlocks { get; init; }` | | -| `GroupCount` | `int GroupCount { get; init; }` | | -| `InodeTableBlocks` | `int InodeTableBlocks { get; init; }` | | -| `InodesPerGroup` | `int InodesPerGroup { get; init; }` | | -| `PerGroupMetaBlocks` | `int PerGroupMetaBlocks { get; init; }` | | -| `TotalBlocks` | `int TotalBlocks { get; init; }` | | - -#### `ExtentCopy` - -Copies a run of bytes from one place in an image to another, including when the two overlap. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Move` | `static void Move(Stream image, long srcOffset, long dstOffset, long length)` | Copies `length` bytes from `srcOffset` to `dstOffset` within `image`, then flushes. Overlapping ranges are handled. | -| `Zero` | `static void Zero(Stream image, long offset, long length)` | Zeros `length` bytes at `offset`. | - -#### `FilePayload` - -A file's contents as a filesystem writer needs them: a length that is known up front, plus either the bytes themselves or a factory that produces them. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FilePayload` | `FilePayload(long Size, byte[] Data, Func Opener)` | A file's contents as a filesystem writer needs them: a length that is known up front, plus either the bytes themselves or a factory that produces them. | -| `Data` | `byte[] Data { get; init; }` | | -| `Empty` | `static FilePayload Empty { get; }` | An empty payload. | -| `Opener` | `Func Opener { get; init; }` | | -| `Size` | `long Size { get; init; }` | | -| `FromBytes` | `static FilePayload FromBytes(byte[] data)` | Wraps bytes already in hand. | -| `FromStream` | `static FilePayload FromStream(long size, Func opener)` | Wraps a stream factory whose output is `size` bytes long. | -| `Open` | `Stream Open()` | Opens the payload for reading. | -| `ToArray` | `byte[] ToArray()` | The bytes, materialised. Only valid below the array limit. | - -#### `GptParser` - -Parses GPT (GUID Partition Table) headers and partition entries. GPT header is at LBA 1 (offset 512 for 512-byte sectors), with partition entries starting at LBA 2+. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IsGpt` | `static bool IsGpt(ReadOnlySpan data)` | Checks whether the given data contains a valid GPT header at LBA 1. | -| `Parse` | `static List Parse(Stream diskData)` | Parses all partitions from a GPT disk image. | - -#### `ImageAccessor` - -Random-access view over a disk image that may be far larger than the ~2 GB a `Byte` array or `MemoryStream` can hold. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ImageAccessor` | `ImageAccessor(Stream stream, bool leaveOpen = true)` | Wraps `stream`, which must be readable and seekable. | -| `Length` | `long Length { get; }` | Total length of the image in bytes. | -| `CopyTo` | `void CopyTo(long offset, Stream destination, long count)` | Copies `count` bytes from `offset` into `destination`. | -| `Dispose` | `void Dispose()` | | -| `FromBytes` | `static ImageAccessor FromBytes(byte[] data)` | Materialises an in-memory image. Convenience for callers that already hold the bytes. | -| `Invalidate` | `void Invalidate(long offset, long length)` | Drops the cached copy of the range `offset`..`offset` + `length`, so a caller that wrote to the underlying stream sees its own bytes on the next read. | -| `ReadByte` | `byte ReadByte(long offset)` | Reads a single byte, or 0 when `offset` lies outside the image. | -| `ReadInt32` | `int ReadInt32(long offset)` | Reads a little-endian signed 32-bit value. | -| `ReadInt64` | `long ReadInt64(long offset)` | Reads a little-endian signed 64-bit value. | -| `ReadUInt16` | `ushort ReadUInt16(long offset)` | Reads a little-endian unsigned 16-bit value. | -| `ReadUInt32` | `uint ReadUInt32(long offset)` | Reads a little-endian unsigned 32-bit value. | -| `ReadUInt64` | `ulong ReadUInt64(long offset)` | Reads a little-endian unsigned 64-bit value. | -| `Read` | `byte[] Read(long offset, int count)` | Reads `count` bytes from `offset`. The result is always `count` long; any part beyond the end of the image reads as zero. | -| `Read` | `int Read(long offset, Span destination)` | Fills `destination` from `offset`, returning the number of bytes actually available. Bytes past the end of the image are left untouched, so a short read yields zeros rather than throwing. | - -#### `MbrParser` - -Parses MBR (Master Boot Record) partition tables, including extended/logical partition chains. The MBR sits at LBA 0 (offset 0) of a disk image, with 4 primary partition entries at offset 0x1BE. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IsMbr` | `static bool IsMbr(ReadOnlySpan data)` | Checks whether the given data starts with a valid MBR. | -| `ParsePrimary` | `static List ParsePrimary(ReadOnlySpan mbr)` | Parses the 4 primary partition entries from an MBR without following extended chains. Operates on a 512-byte buffer (no stream needed). | -| `Parse` | `static List Parse(Stream diskData)` | Parses all partitions from an MBR, including extended/logical partitions. | - -#### `MbrWrapper` - -Wraps a raw filesystem image in a minimal MBR + single primary partition so that Windows' disk-attach path, `diskpart`, and typical VM managers recognise it as a partitioned disk. Without this wrapping, the only layout Windows mounts from a raw FS image is FAT "superfloppy" — NTFS and exFAT require a partition table. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Wrap` | `static byte[] Wrap(byte[] rawFilesystemImage, byte partitionType, bool active = false)` | Returns a new image containing: an MBR sector at offset 0 (with a single primary partition entry covering the whole payload, starting at LBA 2048), 2047 zero-filled sectors of alignment padding, then the supplied `rawFilesystemImage`. | - -#### `MbrWrapper.PartitionType` - -MBR partition-type bytes for common filesystems. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Fat12` | `const byte Fat12` | | -| `Fat16Lba` | `const byte Fat16Lba` | | -| `Fat16Small` | `const byte Fat16Small` | | -| `Fat16` | `const byte Fat16` | | -| `Fat32Chs` | `const byte Fat32Chs` | | -| `Fat32Lba` | `const byte Fat32Lba` | | -| `Linux` | `const byte Linux` | | -| `NtfsExfat` | `const byte NtfsExfat` | | - -#### `PartitionEditor` - -Read/write partition-table editor for raw disk images. Handles MBR (4 primary entries plus an extended/logical chain) and GPT (up to 128 entries with primary + backup headers, configurable entry size). Operates directly on the supplied `Stream` — the caller owns the stream and is responsible for flushing/closing it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PartitionEditor` | `PartitionEditor(Stream stream)` | Opens an editor over the given disk-image stream. The stream must be readable, writable, and seekable. The scheme (MBR/GPT/None) is auto-detected from the on-disk signature. | -| `SectorSize` | `const int SectorSize` | Standard sector size used by the editor. | -| `InPlaceFilesystemConverter` | `static Func InPlaceFilesystemConverter { get; set; }` | Pluggable in-place filesystem-variant converter. Set by the higher-level `Compression.Lib` layer at startup (it can reference the per-family FileSystem.* projects, which Core cannot). When non-null, `ConvertFilesystem` attempts a metadata-only conversion via this delegate before falling back to `false`. Contract: takes (partitionStream, sourceFsId, targetFsId), returns `true` if the conversion succeeded entirely via metadata edits, `false` if no in-place path exists for the pair (the caller should then do a full migration: extract files → FormatPartition → re-import). | -| `InPlaceFilesystemResizer` | `static Func InPlaceFilesystemResizer { get; set; }` | Pluggable in-place filesystem-resizer. Set by the higher-level `Compression.Lib` layer at startup (Core cannot reference FileSystem.* projects, so the actual resizer lives there). The contract is: (partitionStream, fsId, newSizeBytes, isShrink) → bool Returns `true` when the resize succeeded entirely via in-place edits, `false` when no in-place path exists for the fsId (the caller should fall back to a full extract → reformat → re-import). | -| `Scheme` | `PartitionScheme Scheme { get; }` | Partition scheme currently in use on the disk image. | -| `AddLogicalPartition` | `void AddLogicalPartition(long startByteOffset, long lengthBytes, PartitionType type, string label)` | Adds a new logical partition inside the existing MBR extended container. The byte range must lie entirely within the extended container and not overlap any existing logical (each logical occupies its EBR sector plus the data range). | -| `AddPartition` | `void AddPartition(long startByteOffset, long lengthBytes, PartitionType type, string label)` | Adds a new primary partition entry covering [`startByteOffset`, `startByteOffset` + `lengthBytes`). | -| `ConvertFilesystem` | `bool ConvertFilesystem(int partitionIndex, string newFsId)` | Attempts an in-place filesystem-variant conversion of the partition at `partitionIndex`. Reads the partition's current contents as a substream, dispatches to `InPlaceFilesystemConverter` (set by the Compression.Lib bootstrap), and returns the converter's answer. Returns `false` when:No converter has been registered (Core-only build).The source/target pair has no metadata-only conversion path (e.g. FAT → ext, NTFS → exFAT — any cross-family conversion).The image geometry rules out the requested target (e.g. a tiny FAT12 floppy can't fit FAT32's 32-reserved-sector overhead). In any of these cases the caller is expected to fall back to a full extract → reformat → re-import migration. | -| `ConvertGptToMbr` | `void ConvertGptToMbr()` | Reads the current GPT partition table, takes the first 4 entries (MBR hard limit), zero-fills both GPT header areas, and writes a fresh MBR with the translated entries. | -| `ConvertMbrToGpt` | `void ConvertMbrToGpt()` | Reads the current MBR partition table, drops it, then rewrites the equivalent GPT layout: protective MBR at LBA 0, primary GPT header at LBA 1, entries starting at LBA 2, backup GPT at the end of the disk. Translates MBR type bytes to GPT GUIDs via `PartitionTypeMapping`. The extended container (if present) is dropped — its logical children are promoted to top-level GPT entries. | -| `DeletePartition` | `void DeletePartition(int index)` | Deletes the partition at the given index. The partition byte range is not modified — see `PurgePartition` to zero it. | -| `FormatPartition` | `void FormatPartition(int index, string formatId, FormatCreateOptions options)` | Writes a fresh filesystem image of the given `formatId` into the partition's byte range. The format must be registered with `FormatRegistry` and support `IArchiveCreatable`. The resulting bytes must fit within the partition (an exception is thrown otherwise). | -| `ListPartitions` | `IReadOnlyList ListPartitions()` | Returns a snapshot of the current partition table. | -| `OpenFromContainer` | `static PartitionEditor OpenFromContainer(IPartitionEditable container, Stream containerImage)` | Convenience factory for an editor backed by an `IPartitionEditable` container (VHD/VHDX/VMDK/QCOW2/VDI). The caller is responsible for disposing the returned guest-disk view (the editor exposes no explicit close method — operations flush after every write). | -| `PurgePartition` | `void PurgePartition(int index)` | Deletes the partition and zero-fills its byte range on disk. | -| `Reload` | `void Reload()` | Reloads the in-memory partition table from disk. Useful after out-of-band edits to the stream. | -| `ResizePartition` | `void ResizePartition(int index, long newSizeBytes)` | Resizes the partition at `index` to `newSizeBytes`. Shrinks or grows the inner filesystem in place (via `InPlaceFilesystemResizer`) and updates the partition table entry to reflect the new size. For shrink: the FS is shrunk first (so its trailing data has been migrated down before we touch the partition table), then the partition entry is updated. A crash between the FS shrink and the table update leaves the partition at its old (larger) size with a smaller FS inside — readable, no data loss.For grow: the partition entry is updated first (so the substream view exposes the new range), then the FS is grown. A crash between the two leaves the partition at its new (larger) size with the old FS inside, which is also readable (the new tail bytes are just unused).The new size must be sector-aligned and must not cause overlap with the next partition (for grow) or fall below a minimum FS-defined floor (for shrink). All validation happens before any write. | -| `Verify` | `PartitionTableVerification Verify()` | Verifies on-disk integrity of the current partition table. Reports header signature/CRC mismatches, GPT entry-array CRC mismatches, primary/backup divergence, and out-of-range partition extents. | - -#### `PartitionEntry` - -Represents a partition table entry (MBR or GPT). - -| Member | Signature | Summary | -| --- | --- | --- | -| `PartitionEntry` | `PartitionEntry()` | | -| `Index` | `int Index { get; init; }` | Zero-based partition index. | -| `IsActive` | `bool IsActive { get; init; }` | Whether this partition is marked as active/bootable. | -| `Name` | `string Name { get; init; }` | Partition label/name (GPT only, empty for MBR). | -| `Size` | `long Size { get; init; }` | Size of the partition in bytes. | -| `Source` | `string Source { get; init; }` | Source: "MBR", "GPT", or "EBR" (extended boot record). | -| `StartOffset` | `long StartOffset { get; init; }` | Byte offset from the start of the disk to the partition data. | -| `TypeCode` | `string TypeCode { get; init; }` | Raw type code (MBR: single byte, GPT: GUID string). | -| `TypeName` | `string TypeName { get; init; }` | Human-readable filesystem/type name (e.g. "NTFS", "Linux ext4", "FAT32"). | - -#### `PartitionScheme` - -Partition scheme detected on a disk image. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No recognised partition table (raw / superfloppy / blank disk). | -| `Mbr` | `1` | MBR / DOS partition table at LBA 0. | -| `Gpt` | `2` | GPT (UEFI) partition table with protective MBR at LBA 0. | - -#### `PartitionTableDetector` - -Detects and parses partition tables from raw disk data. Tries GPT first (since GPT disks also have a protective MBR), then falls back to MBR. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Detect` | `static DetectionResult Detect(Stream diskData)` | Attempts to detect a partition table in the given stream. Tries GPT first (higher precedence), then MBR. Returns an empty partition list if no valid partition table is found. | -| `Detect` | `static DetectionResult Detect(byte[] diskData)` | Attempts to detect a partition table in the given byte array. Convenience overload that wraps the data in a `MemoryStream`. | -| `ExtractPartitionData` | `static byte[] ExtractPartitionData(Stream diskData, PartitionEntry partition)` | Extracts partition data from a disk image stream. Returns the raw bytes of the partition at the given offset and size. | -| `ExtractPartitionData` | `static byte[] ExtractPartitionData(byte[] diskData, PartitionEntry partition)` | Extracts partition data from a byte array. | - -#### `PartitionTableDetector.DetectionResult` - -Result of partition table detection, including the scheme used and the discovered partitions. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DetectionResult` | `DetectionResult()` | | -| `Partitions` | `List Partitions { get; init; }` | Discovered partitions. Empty if no partition table was found. | -| `Scheme` | `string Scheme { get; init; }` | The partition scheme detected: "GPT", "MBR", "APM", or "None". | - -#### `PartitionTableVerification` - -Result of `Verify` — a snapshot of integrity checks against the on-disk partition table. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PartitionTableVerification` | `PartitionTableVerification(PartitionScheme Scheme, bool IsValid, IReadOnlyList Issues)` | Result of `Verify` — a snapshot of integrity checks against the on-disk partition table. | -| `IsValid` | `bool IsValid { get; init; }` | `true` when no issues were detected. | -| `Issues` | `IReadOnlyList Issues { get; init; }` | Human-readable diagnostics for each detected problem. | -| `Scheme` | `PartitionScheme Scheme { get; init; }` | Detected partition scheme. | - -#### `PartitionType` - -Logical partition type. Used by partition-table editors so callers can describe a partition without caring whether the on-disk table is MBR (1-byte type code) or GPT (16-byte type GUID); the editor maps both directions automatically. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Empty` | `0` | Unallocated / empty slot. | -| `Fat12` | `1` | FAT12 (MBR 0x01). | -| `Fat16Small` | `2` | FAT16 below 32MB (MBR 0x04). | -| `Fat16` | `3` | FAT16 above 32MB (MBR 0x06). | -| `Fat16Lba` | `4` | FAT16 with LBA addressing (MBR 0x0E). | -| `Fat32Chs` | `5` | FAT32 with CHS addressing (MBR 0x0B). | -| `Fat32Lba` | `6` | FAT32 with LBA addressing (MBR 0x0C). Default for FAT32. | -| `NtfsExfat` | `7` | NTFS / exFAT / HPFS (MBR 0x07). | -| `Linux` | `8` | Linux native filesystem (MBR 0x83 / GPT 0FC63DAF-…). | -| `LinuxSwap` | `9` | Linux swap (MBR 0x82 / GPT 0657FD6D-…). | -| `LinuxLvm` | `10` | Linux LVM (MBR 0x8E / GPT E6D6D379-…). | -| `LinuxRaid` | `11` | Linux RAID (MBR 0xFD / GPT A19D880F-…). | -| `AppleHfsPlus` | `12` | Apple HFS+ (MBR 0xAF / GPT 48465300-…). | -| `AppleUfs` | `13` | Apple UFS (MBR 0xA8 / GPT 55465300-…). | -| `AppleApfs` | `14` | Apple APFS (GPT 7C3457EF-…). | -| `MicrosoftBasicData` | `15` | Microsoft Basic Data (GPT EBD0A0A2-…). Maps to MBR 0x07. | -| `MicrosoftReserved` | `16` | Microsoft Reserved (GPT E3C9E316-…). | -| `EfiSystem` | `17` | EFI System Partition (MBR 0xEF / GPT C12A7328-…). | -| `BiosBoot` | `18` | BIOS Boot Partition (GPT 21686148-…). | -| `ExtendedLba` | `19` | MBR extended partition (LBA, type 0x0F). Acts as a container for logical partitions chained through EBRs. No GPT equivalent. | -| `Unknown` | `20` | Unknown or unmapped type. | - -#### `PartitionTypeDatabase` - -Maps MBR partition type bytes and GPT partition type GUIDs to human-readable names. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GetGptTypeName` | `static string GetGptTypeName(Guid typeGuid)` | Gets the filesystem name for a GPT partition type GUID. | -| `GetMbrTypeName` | `static string GetMbrTypeName(byte type)` | Gets the filesystem name for an MBR partition type byte. | - -#### `PartitionTypeMapping` - -Translation tables between `PartitionType` and on-disk MBR bytes / GPT GUIDs. Centralised so the MBR↔GPT conversion paths stay in sync. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FromGptGuid` | `static PartitionType FromGptGuid(Guid guid)` | Best-effort reverse lookup from a GPT type GUID to a logical type. | -| `FromMbrByte` | `static PartitionType FromMbrByte(byte b)` | Best-effort reverse lookup from an MBR byte to a logical type. | -| `ToGptGuid` | `static Guid ToGptGuid(PartitionType type)` | Returns the GPT type GUID for the given logical type. | -| `ToMbrByte` | `static byte ToMbrByte(PartitionType type)` | Returns the MBR partition-type byte for the given logical type. | - -#### `PartitionWindowStream` - -Read-only window onto a sub-range of an underlying disk stream. Position 0 in the window maps to `offset` in the underlying stream; reads past `length` return EOF. Used to hand an inner-FS reader a stream that looks like the whole filesystem starts at byte 0, even though it actually lives at the partition's start offset on the host disk. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PartitionWindowStream` | `PartitionWindowStream(Stream inner, long offset, long length, bool leaveOpen = true)` | | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `PartitionedDiskLister` - -Partition-aware archive surface for raw disk image streams (VHD/VHDX/VMDK/Qcow2/VDI guest-disk views). When a valid MBR or GPT partition table is detected, presents each partition as a top-level directory `PartitionN_TypeName/` whose contents are the inner filesystem's entries (delegated through `InnerFsDetector`). When no partition table is present, returns `null` so the caller can fall through to the existing single-FS-at-offset-0 path. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Extract` | `static bool Extract(Stream disk, string outputDir, string password, string[] files)` | Extracts entries across every partition into per-partition subdirectories of `outputDir`. Returns `true` if a partition table was detected and handled; `false` if no partition table was found (caller falls through to the unpartitioned path). | -| `List` | `static List List(Stream disk, string password)` | Lists entries across every partition. Returns `null` if no partition table is present so the caller can fall through to the unpartitioned path. | -| `TryAdd` | `static bool TryAdd(Stream disk, IReadOnlyList inputs)` | Partition-aware `Add`. Returns `true` when a partition table was present and at least one input was dispatched through the partition-aware path; `false` when no partition table exists so the caller can fall through to the existing single-FS path. | -| `TryRemove` | `static bool TryRemove(Stream disk, string[] entryNames)` | Partition-aware `Remove`. Returns `true` when a partition table was present and at least one entry was removed; `false` if no partition table was detected. Entry name shapes: `Partition_/` deletes an inner-FS file; `Partition_` or `Partition_.raw` deletes the whole partition. | - -#### `SparseBlockImage` - -Sparse, block-addressed image buffer. Only the blocks a writer actually touches are allocated, so laying out a multi-gigabyte volume costs its metadata rather than its size — and a volume too large for a byte[] can still be written straight to a stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SparseBlockImage` | `SparseBlockImage(int blockSize, long totalBytes)` | Sparse, block-addressed image buffer. Only the blocks a writer actually touches are allocated, so laying out a multi-gigabyte volume costs its metadata rather than its size — and a volume too large for a byte[] can still be written straight to a stream. | -| `BlockSize` | `int BlockSize { get; }` | Block size in bytes. | -| `Item` | `byte this[long offset] { get; set; }` | Single byte at `offset`. | -| `TotalBytes` | `long TotalBytes { get; }` | Declared size of the finished volume. | -| `At` | `Span At(long offset, int length)` | `length` bytes at `offset`. Every ext structure this writer emits — superblock, group descriptor, inode, block pointer — is aligned so that it never crosses a block boundary. | -| `Block` | `Span Block(int block)` | The whole of `block`, allocated on first touch. | -| `Fill` | `void Fill(long offset, byte value, long count)` | Fills `count` bytes at `offset` with `value`. | -| `Materialise` | `byte[] Materialise()` | Materialises the whole volume. | -| `Read` | `byte[] Read(long offset, int length)` | Reads `length` bytes from `offset`, spanning blocks as needed. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the volume from the current position, extending the stream to its full size. | -| `Write` | `void Write(long offset, ReadOnlySpan data)` | Copies `data` to `offset`, spanning blocks as needed. | - -### Namespace `Compression.Core.DiskImage.Raid` - -[`ImsmContainer`](#imsmcontainer) · [`ImsmDisk`](#imsmdisk) · [`ImsmMetadataParser`](#imsmmetadataparser) · [`ImsmVolume`](#imsmvolume) · [`Md09SuperblockParser`](#md09superblockparser) · [`Md1SuperblockParser`](#md1superblockparser) · [`RaidArray`](#raidarray) · [`RaidAssembledStream`](#raidassembledstream) · [`RaidAssembler`](#raidassembler) · [`RaidLevel`](#raidlevel) · [`RaidMember`](#raidmember) · [`RaidMemberMetadata`](#raidmembermetadata) · [`RaidMetadataFormat`](#raidmetadataformat) - -#### `ImsmContainer` - -A parsed IMSM (Intel Matrix Storage Manager) container. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ImsmContainer` | `ImsmContainer()` | | -| `Disks` | `IReadOnlyList Disks { get; init; }` | Physical disks in the container. | -| `FamilyNum` | `uint FamilyNum { get; init; }` | Family number identifying the container across its member disks. | -| `GenerationNum` | `uint GenerationNum { get; init; }` | Generation counter (incremented each metadata write). | -| `Version` | `string Version { get; init; }` | Container signature/version string (after the fixed prefix). | -| `Volumes` | `IReadOnlyList Volumes { get; init; }` | RAID volumes defined on the container. | - -#### `ImsmDisk` - -A physical disk record in an IMSM container. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ImsmDisk` | `ImsmDisk()` | | -| `Serial` | `string Serial { get; init; }` | Disk serial string (trimmed). | -| `Status` | `uint Status { get; init; }` | Raw disk status flags. | -| `TotalBlocks` | `long TotalBlocks { get; init; }` | Total disk size in 512-byte blocks. | - -#### `ImsmMetadataParser` - -Parses Intel Matrix Storage Manager / IMSM (isw) container metadata. The metadata block (`imsm_super`) is written near the end of every member disk and begins with the signature `"Intel Raid ISM Cfg Sig. "`. Field offsets follow the on-disk structs documented in mdadm's `super-intel.c` (`imsm_super` / `imsm_disk` / `imsm_dev` / `imsm_vol` / `imsm_map`) for the classic non-migrating, single-map layout. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SignaturePrefix` | `static ReadOnlySpan SignaturePrefix { get; }` | The fixed 24-byte IMSM signature prefix. | -| `Parse` | `static ImsmContainer Parse(ReadOnlySpan mpb)` | Parses an IMSM container from a buffer positioned at the `imsm_super` signature. Returns `null` if the buffer is too short or malformed. | -| `TryParse` | `static ImsmContainer TryParse(Stream member)` | Scans the tail of `member` for IMSM metadata and parses the container. Returns `null` when no IMSM signature is found. | - -#### `ImsmVolume` - -A RAID volume (imsm_dev/imsm_map) defined inside an IMSM container. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ImsmVolume` | `ImsmVolume()` | | -| `BlocksPerMember` | `long BlocksPerMember { get; init; }` | Usable data size of the volume in 512-byte blocks. | -| `ChunkSizeBytes` | `long ChunkSizeBytes { get; init; }` | Stripe unit (chunk) size in bytes (blocks_per_strip × 512). | -| `DiskOrder` | `IReadOnlyList DiskOrder { get; init; }` | Disk-order table: map slot → index into the container disk array. | -| `Level` | `RaidLevel Level { get; init; }` | Mapped RAID personality. | -| `Name` | `string Name { get; init; }` | Volume name. | -| `NumMembers` | `int NumMembers { get; init; }` | Number of member disks in the volume map. | -| `RawLevel` | `int RawLevel { get; init; }` | Raw IMSM raid_level byte (0=RAID0, 1=RAID1/RAID10, 5=RAID5). | - -#### `Md09SuperblockParser` - -Decodes a Linux md `mdp_superblock_t` (metadata version 0.90). The 4 KiB superblock sits at a 64 KiB-aligned offset near the end of the device (`MD_NEW_SIZE_SECTORS`), and array data starts at device offset 0. Field offsets follow the section layout in `drivers/md/md_p.h`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SuperblockOffset` | `static long SuperblockOffset(long deviceLength)` | Computes the 0.90 superblock byte offset for a device of the given length. | -| `TryParse` | `static RaidMemberMetadata TryParse(Stream member)` | Tries to read a 0.90 superblock from `member`. Returns the decoded per-member metadata, or `null` when no valid superblock is present. | - -#### `Md1SuperblockParser` - -Decodes a Linux md `mdp_superblock_1` (metadata version 1.x) from a member device. The superblock lives at one of three sub-version locations, all probed here and validated against the self-describing `super_offset` field: 1.2 — 4 KiB from the start of the device.1.1 — at the very start of the device.1.0 — 4 KiB-aligned, ~8 KiB from the end of the device. Field offsets follow the kernel layout in `drivers/md/md_p.h` and mdadm's `super1.c`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MdMagic` | `const uint MdMagic` | md superblock magic (`MD_SB_MAGIC`), little-endian. | -| `TryParse` | `static RaidMemberMetadata TryParse(Stream member)` | Tries to read a 1.x superblock from `member`. Returns the decoded per-member metadata, or `null` when no valid superblock is present. | - -#### `RaidArray` - -Fully described, ready-to-read RAID array: its personality, geometry and the ordered set of member devices. Feed one of these to `RaidAssembledStream` to obtain the virtual guest-disk stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RaidArray` | `RaidArray()` | | -| `ArrayName` | `string ArrayName { get; init; }` | Array name, when available. | -| `ArrayUuid` | `string ArrayUuid { get; init; }` | Array identity (UUID / family signature). | -| `ChunkSizeBytes` | `long ChunkSizeBytes { get; init; }` | Stripe unit (chunk) size in bytes. Unused for RAID1/Linear. | -| `DataDisks` | `int DataDisks { get; }` | Number of data-bearing disks (excludes parity), per level. | -| `Layout` | `int Layout { get; init; }` | Raw md layout code, interpreted per level. | -| `Level` | `RaidLevel Level { get; init; }` | RAID personality. | -| `Members` | `IReadOnlyList Members { get; init; }` | Members ordered by role; index equals `Role`. Missing roles carry a placeholder with no stream. | -| `NearCopies` | `int NearCopies { get; init; }` | Mirror copies for RAID10 near layout (2 for a standard mirror-of-stripes). | -| `PerDeviceDataBytes` | `long PerDeviceDataBytes { get; init; }` | Usable data length of a single member in bytes. | -| `PresentCount` | `int PresentCount { get; }` | Number of member slots currently backed by a device. | -| `RaidDisks` | `int RaidDisks { get; init; }` | Number of member slots (roles 0..RaidDisks-1). | - -#### `RaidAssembledStream` - -Read-only, seekable virtual guest-disk stream assembled from the member devices of a `RaidArray`. It maps every virtual LBA to a (member, byte-offset) pair according to the array's personality: Linear — member data regions concatenated in role order.RAID0 — chunks round-robin across all members.RAID1 — read from the first available mirror.RAID4/5/6 — striped with parity chunks skipped; RAID5 uses mdadm's default left-symmetric rotation, RAID6 left-symmetric P+Q.RAID10 — stripe over mirrored pairs (near layout). A single missing member is transparently reconstructed by XOR where the level permits (RAID5 always; RAID6 data-disk recovery from P; RAID1/10 from a surviving mirror). - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RaidAssembledStream` | `RaidAssembledStream(RaidArray array, bool leaveOpen = true)` | Builds a virtual stream over `array`. | -| `Array` | `RaidArray Array { get; }` | The array this stream presents. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(Span buffer)` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `RaidAssembler` - -Assembles N member disks into one virtual guest-disk `RaidAssembledStream` by sniffing each member's RAID metadata, grouping members that belong to the same array, ordering them by role and describing the geometry. The resulting stream can be handed to the ordinary partition/filesystem readers unchanged. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Sniff` | `static RaidMemberMetadata Sniff(Stream member)` | Sniffs a single member stream for recognised RAID metadata. New metadata formats plug in here by returning a populated `RaidMemberMetadata`. | -| `TryAssemble` | `static RaidAssembledStream TryAssemble(IReadOnlyList members, bool leaveOpen = true)` | Sniffs and assembles the given member streams. Returns the assembled stream, or `null` when no coherent RAID array can be formed from the members. | -| `TryAssemble` | `static RaidAssembledStream TryAssemble(IReadOnlyList memberPaths)` | Convenience overload that opens the given member file paths read-only and assembles them. The returned stream owns and disposes the opened files. Returns `null` (after closing any opened files) when no array can be formed. | - -#### `RaidLevel` - -RAID personality of an assembled array. Mirrors the small set of levels the Linux md stack and Intel IMSM/Matrix metadata can describe. The numeric meaning of striping/parity is implemented by `RaidAssembledStream`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Linear` | `0` | Concatenation (JBOD/linear): member data regions are joined end to end. | -| `Raid0` | `1` | Striping with no redundancy: virtual chunks round-robin across all members. | -| `Raid1` | `2` | Mirroring: every member holds an identical copy of the data. | -| `Raid4` | `3` | Striping with a single dedicated parity disk (parity fixed on the last member). | -| `Raid5` | `4` | Striping with distributed single parity (rotating, mdadm default left-symmetric). | -| `Raid6` | `5` | Striping with distributed dual parity (P + Q). | -| `Raid10` | `6` | Stripe over mirrored pairs (mirror-of-stripes, near layout). | - -#### `RaidMember` - -One member device of an assembled array, addressed by its `Role`. A member whose backing device is absent (a degraded array) has a `null``Data` stream; its content is reconstructed from parity where the level allows. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RaidMember` | `RaidMember()` | | -| `DataOffsetBytes` | `long DataOffsetBytes { get; init; }` | Byte offset within `Data` at which array data begins. | -| `DataSizeBytes` | `long DataSizeBytes { get; init; }` | Usable data length of this member in bytes. | -| `Data` | `Stream Data { get; init; }` | Seekable, readable stream over the raw member device, or `null` when the member is missing (degraded array). | -| `IsPresent` | `bool IsPresent { get; }` | Whether the member's backing device is present. | -| `Role` | `int Role { get; init; }` | Zero-based role/slot of this member in the array. | - -#### `RaidMemberMetadata` - -The geometry and identity a single member device contributes to an array, as decoded from that member's RAID superblock. Members carrying the same `ArrayUuid` (and `Format`) belong to one array; `Role` gives the member's slot within it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RaidMemberMetadata` | `RaidMemberMetadata()` | | -| `ArrayName` | `string ArrayName { get; init; }` | Human-readable array name, when the metadata carries one. | -| `ArrayUuid` | `string ArrayUuid { get; init; }` | Stable identifier grouping members of the same array (array UUID / family signature). | -| `ChunkSizeBytes` | `long ChunkSizeBytes { get; init; }` | Stripe unit (chunk) size in bytes. Zero/irrelevant for RAID1 and Linear. | -| `DataOffsetBytes` | `long DataOffsetBytes { get; init; }` | Byte offset within this member at which array data begins. | -| `DataSizeBytes` | `long DataSizeBytes { get; init; }` | Usable data length (per member) in bytes. | -| `Format` | `RaidMetadataFormat Format { get; init; }` | Metadata format this member was decoded from. | -| `Layout` | `int Layout { get; init; }` | Raw layout code (md `layout` field); interpretation depends on level. | -| `Level` | `RaidLevel Level { get; init; }` | RAID personality of the array. | -| `NearCopies` | `int NearCopies { get; init; }` | Number of mirror copies (RAID10 near layout); 2 for a standard mirror-of-stripes. | -| `RaidDisks` | `int RaidDisks { get; init; }` | Total number of member slots the array was created with. | -| `Role` | `int Role { get; init; }` | This member's zero-based role/slot in the array. | - -#### `RaidMetadataFormat` - -On-disk RAID metadata format a member superblock was recognised as. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Mdraid090` | `0` | Linux md superblock version 0.90 (fixed-size block near end of device). | -| `Mdraid1x` | `1` | Linux md superblock version 1.x (1.0 end / 1.1 start / 1.2 4K-from-start). | -| `Imsm` | `2` | Intel Matrix Storage Manager / IMSM (isw) container metadata. | - -### Namespace `Compression.Core.Entropy` - -[`ArithmeticBuildingBlock`](#arithmeticbuildingblock) · [`BpeBuildingBlock`](#bpebuildingblock) · [`BpeConstructionStrategy`](#bpeconstructionstrategy) · [`DmcBuildingBlock`](#dmcbuildingblock) · [`EliasDeltaBuildingBlock`](#eliasdeltabuildingblock) · [`EliasGammaBuildingBlock`](#eliasgammabuildingblock) · [`FibonacciBuildingBlock`](#fibonaccibuildingblock) · [`FseBuildingBlock`](#fsebuildingblock) · [`GolombBuildingBlock`](#golombbuildingblock) · [`GolombFixedMBuildingBlock`](#golombfixedmbuildingblock) · [`GolombProfile`](#golombprofile) · [`LevenshteinBuildingBlock`](#levenshteinbuildingblock) · [`OmegaBuildingBlock`](#omegabuildingblock) · [`RangeCodingBuildingBlock`](#rangecodingbuildingblock) · [`ShannonFanoBuildingBlock`](#shannonfanobuildingblock) · [`TunstallBuildingBlock`](#tunstallbuildingblock) · [`UnaryBuildingBlock`](#unarybuildingblock) - -#### `ArithmeticBuildingBlock` - -Exposes order-0 arithmetic coding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArithmeticBuildingBlock` | `ArithmeticBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BpeBuildingBlock` - -Exposes Philip Gage's byte-pair compression as a benchmarkable building block. Repeated adjacent byte pairs are replaced by byte values that do not occur in the current block; the replacement table is stored with the encoded bytes. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BpeBuildingBlock` | `BpeBuildingBlock()` | Creates a BPE building block using greedy grammar construction. | -| `BpeBuildingBlock` | `BpeBuildingBlock(BpeConstructionStrategy constructionStrategy)` | Creates a BPE building block using the requested grammar-construction strategy. | -| `ConstructionStrategy` | `BpeConstructionStrategy ConstructionStrategy { get; }` | The grammar-construction strategy used by `Compress`. | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BpeConstructionStrategy` - -Controls how a byte-pair grammar is constructed. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Greedy` | `0` | Repeatedly replace the currently most frequent profitable pair. | -| `Exhaustive` | `1` | Explore every profitable merge sequence within each search block and keep the smallest result. | - -#### `DmcBuildingBlock` - -Exposes Dynamic Markov Compression as a benchmarkable building block. Bit-level finite-context modeling with state cloning: a finite automaton where each state predicts the next bit. States that become too frequent are cloned to create higher-order contexts, improving prediction. Uses an arithmetic coder for the output bitstream. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmcBuildingBlock` | `DmcBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `EliasDeltaBuildingBlock` - -Exposes Elias Delta coding as a benchmarkable building block. Encodes positive integer N by Gamma-coding the length of N, then appending the lower bits. Byte values are mapped to positive integers as (value + 1). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EliasDeltaBuildingBlock` | `EliasDeltaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `EliasGammaBuildingBlock` - -Exposes Elias Gamma coding as a benchmarkable building block. Encodes positive integer N as floor(log2(N)) zero-bits followed by the binary representation of N. Byte values are mapped to positive integers as (value + 1). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EliasGammaBuildingBlock` | `EliasGammaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `FibonacciBuildingBlock` - -Exposes Fibonacci universal coding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FibonacciBuildingBlock` | `FibonacciBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `FseBuildingBlock` - -Exposes FSE (Finite State Entropy) / tANS as a benchmarkable building block. Uses a state machine where transitions encode symbol probability information. Table size is 1024 (tableLog=10). Symbols are spread proportionally to frequency. Encoding processes symbols in reverse (ANS is LIFO). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FseBuildingBlock` | `FseBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `GolombBuildingBlock` - -Exposes Golomb/Rice coding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GolombBuildingBlock` | `GolombBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, GolombProfile profile, int fixedParameter = 2)` | Encodes `data` under the given `profile`. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data, GolombProfile profile)` | Decodes a stream produced by `Compress` under the same `profile`. M is always read back from the stream, so the profile only selects how the element count is framed. | - -#### `GolombFixedMBuildingBlock` - -Golomb/Rice coding with a pinned parameter — the fixed-M bit-stream profile. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GolombFixedMBuildingBlock` | `GolombFixedMBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `GolombProfile` - -Selects how a Golomb stream chooses its parameter M and frames its element count. The unary-plus-truncated-binary coding of each value is identical in every profile; only the parameter policy and the header differ. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `MeanAdaptive` | `0` | M is derived from the sample mean as `max(1, round(mean × ln 2))` and the element count is carried as a 4-byte little-endian field. This is the historical default. | -| `FixedParameter` | `1` | M is pinned by the caller and the element count is carried as an LEB128 varint, which keeps the header down to two bytes for short inputs. Coding remains Golomb/Rice; with a power-of-two M the truncated-binary remainder degenerates to plain Rice. | - -#### `LevenshteinBuildingBlock` - -Exposes Levenshtein coding as a benchmarkable building block. A self-delimiting universal code: encodes positive integer N by recursively prefixing the bit-length until it reaches 0, with a count prefix. Byte values are mapped to positive integers as (value + 1). - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LevenshteinBuildingBlock` | `LevenshteinBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `OmegaBuildingBlock` - -Exposes Elias Omega coding as a benchmarkable building block. A recursive universal code for positive integers: the value is prefixed with the bit-length of its binary representation, and that length is itself recursively prefixed the same way, until a group collapses to the value 1. A terminating "0" bit closes the code. Byte values are mapped to positive integers as (value + 1). Reference: P. Elias, "Universal Codeword Sets and Representations of the Integers", IEEE Trans. Information Theory, 1975; see also https://en.wikipedia.org/wiki/Elias_omega_coding for the canonical encode/decode procedure implemented here. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OmegaBuildingBlock` | `OmegaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `RangeCodingBuildingBlock` - -Exposes byte-oriented range coding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RangeCodingBuildingBlock` | `RangeCodingBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ShannonFanoBuildingBlock` - -Exposes Shannon-Fano coding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShannonFanoBuildingBlock` | `ShannonFanoBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `TunstallBuildingBlock` - -Exposes Tunstall coding as a benchmarkable building block. Variable-to-fixed-length code (dual of Huffman): builds a dictionary of variable-length input phrases, each assigned a fixed-width codeword. The dictionary is built by repeatedly extending the highest-probability leaf. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TunstallBuildingBlock` | `TunstallBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `UnaryBuildingBlock` - -Exposes Unary coding as a benchmarkable building block. Each byte value N is encoded as N one-bits followed by a zero-bit. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnaryBuildingBlock` | `UnaryBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Entropy.AdaptiveHuffman` - -[`AdaptiveHuffmanBuildingBlock`](#adaptivehuffmanbuildingblock) - -#### `AdaptiveHuffmanBuildingBlock` - -Exposes FGK adaptive (dynamic) Huffman coding as a benchmarkable building block. Unlike the static `BB_Huffman` block, no code-length table is transmitted: the encoder and decoder both start from an empty tree and rebuild identical codes symbol-by-symbol as data flows past, per `AdaptiveHuffmanTree`. Header: 4-byte LE original size, then the bit-packed adaptive Huffman stream. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdaptiveHuffmanBuildingBlock` | `AdaptiveHuffmanBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Entropy.Ans` - -[`RansBuildingBlock`](#ransbuildingblock) · [`RansDecoder`](#ransdecoder) · [`RansEncoder`](#ransencoder) - -#### `RansBuildingBlock` - -Exposes rANS (range-variant Asymmetric Numeral Systems) as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RansBuildingBlock` | `RansBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `RansDecoder` - -Range-variant Asymmetric Numeral Systems (rANS) decoder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RansDecoder` | `RansDecoder()` | | -| `Decode` | `byte[] Decode(ReadOnlySpan compressed, int originalSize, uint[] normFreq)` | Decompresses rANS-encoded data. | - -#### `RansEncoder` - -Range-variant Asymmetric Numeral Systems (rANS) encoder. Encodes symbols in reverse, producing a compressed bitstream that can be decoded forward. Used in AV1, LZFSE, and other modern codecs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RansEncoder` | `RansEncoder()` | | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Compresses data using rANS with an order-0 model. | -| `NormalizeFrequencies` | `static uint[] NormalizeFrequencies(uint[] freq, int totalCount)` | Returns the normalized frequency table for the given data. | - -### Namespace `Compression.Core.Entropy.Arithmetic` - -[`AdaptiveModel`](#adaptivemodel) · [`ArithmeticDecoder`](#arithmeticdecoder) · [`ArithmeticEncoder`](#arithmeticencoder) - -#### `AdaptiveModel` - -Adaptive frequency model for use with `ArithmeticEncoder` and `ArithmeticDecoder`. Tracks symbol frequencies and maintains cumulative frequency tables that update as symbols are processed. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdaptiveModel` | `AdaptiveModel(int numSymbols)` | Initializes a new `AdaptiveModel` with uniform initial frequencies. | -| `NumSymbols` | `int NumSymbols { get; }` | Gets the number of symbols. | -| `TotalFrequency` | `int TotalFrequency { get; }` | Gets the total frequency count. | -| `FindSymbol` | `int FindSymbol(int count)` | Looks up a symbol from a cumulative count value. | -| `GetCumulativeFrequency` | `int GetCumulativeFrequency(int symbol)` | Gets the cumulative frequency for a symbol (lower bound). | -| `GetFrequency` | `int GetFrequency(int symbol)` | Gets the frequency of a symbol. | -| `Update` | `void Update(int symbol)` | Updates the model after encoding/decoding a symbol. | - -#### `ArithmeticDecoder` - -Binary arithmetic decoder that decodes symbols bit-by-bit using adaptive probability estimation. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArithmeticDecoder` | `ArithmeticDecoder(Stream input)` | Initializes a new `ArithmeticDecoder` reading from the given stream. | -| `DecodeBit` | `int DecodeBit(int prob0)` | Decodes a single bit given the probability of the bit being 0. | -| `GetCumulativeCount` | `uint GetCumulativeCount(uint totalFreq)` | Gets the current cumulative count for symbol decoding. | -| `UpdateSymbol` | `void UpdateSymbol(uint cumFreq, uint symFreq, uint totalFreq)` | Updates the decoder state after looking up a symbol. | - -#### `ArithmeticEncoder` - -Binary arithmetic encoder that encodes symbols bit-by-bit using adaptive probability estimation. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArithmeticEncoder` | `ArithmeticEncoder(Stream output)` | Initializes a new `ArithmeticEncoder` writing to the given stream. | -| `EncodeBit` | `void EncodeBit(int bit, int prob0)` | Encodes a single bit with the given probability of the bit being 0. | -| `EncodeSymbol` | `void EncodeSymbol(uint cumFreq, uint symFreq, uint totalFreq)` | Encodes a symbol using a cumulative frequency table. | -| `Finish` | `void Finish()` | Finalises the encoding and flushes remaining bits. | - -### Namespace `Compression.Core.Entropy.ContextMixing` - -[`Apm`](#apm) · [`CmBuildingBlock`](#cmbuildingblock) · [`CmCompressor`](#cmcompressor) · [`ContextMixer`](#contextmixer) · [`ContextModel`](#contextmodel) · [`Logistic`](#logistic) · [`MatchModel`](#matchmodel) - -#### `Apm` - -Adaptive Probability Map (a.k.a. Secondary Symbol Estimation, SSE) — refines a probability produced by the mixer using a small refinement context. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Apm` | `Apm(int contexts, int rate = 7)` | Initializes a new `Apm`. | -| `Refine` | `int Refine(int probability, int context)` | Refines a probability for the given context, caching state for `Update`. | -| `Update` | `void Update(int bit)` | Updates the knots used by the last `Refine` call towards the observed bit. | - -#### `CmBuildingBlock` - -Exposes the logistic-domain context-mixing compressor as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CmBuildingBlock` | `CmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `CmCompressor` - -A clean-room lpaq-grade context-mixing compressor: a set of hashed order-N bit models combined in the logistic domain, refined by an adaptive probability map (SSE), and coded with a binary arithmetic coder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data using logistic-domain context mixing. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses context-mixing compressed data. | - -#### `ContextMixer` - -Combines predictions from multiple `ContextModel` instances in the logistic (stretch) domain — the genuine PAQ/lpaq mixer. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ContextMixer` | `ContextMixer(params ContextModel[] models)` | Initializes a new `ContextMixer` with the given models. | -| `Predict` | `int Predict(ReadOnlySpan contexts)` | Gets the mixed prediction (probability of bit 1) given contexts for each model. | -| `Update` | `void Update(ReadOnlySpan contexts, int bit)` | Updates all models and mixer weights after observing a bit. | - -#### `ContextModel` - -A single context model that predicts the probability of the next bit being 1, given a context hash. Each context maps to an adaptive 12-bit probability state with a per-state adaptive update rate. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ContextModel` | `ContextModel(int tableBits)` | Initializes a new `ContextModel` with the given table size. | -| `Predict` | `int Predict(int context)` | Gets the predicted probability of the next bit being 1 (scaled 0–4095). | -| `Update` | `void Update(int context, int bit)` | Updates the model after observing a bit. | - -#### `Logistic` - -Fast table-based logistic transforms used by PAQ/lpaq-style context mixing. Probabilities are 12-bit fixed point in the range [0, 4095] (i.e. p/4096), and the stretch domain is the integer logit clamped to [-2047, 2047]. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MaxStretch` | `const int MaxStretch` | Inclusive upper bound of the stretch (logit) domain. | -| `MinStretch` | `const int MinStretch` | Inclusive lower bound of the stretch (logit) domain. | -| `ProbabilityBits` | `const int ProbabilityBits` | Number of probability bits (12 → probabilities scaled to 4096). | -| `ProbabilityScale` | `const int ProbabilityScale` | The probability scale (4096); a probability p is stored as round(p * 4096). | -| `Squash` | `static int Squash(int logit)` | Converts a logit (stretch-domain value) back into a 12-bit probability. | -| `Stretch` | `static int Stretch(int probability)` | Converts a 12-bit probability into the stretch (logit) domain. | - -#### `MatchModel` - -Tracks the longest recent repeat of the byte stream and predicts the next byte by following that repeat forward — the "match model" technique used by lpaq/PAQ-family context-mixing compressors alongside their fixed-order context models. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MatchModel` | `MatchModel(int capacity, int minOrder = 4, int hashBits = 18)` | Initializes a new `MatchModel`. | -| `MatchLength` | `int MatchLength { get; }` | Gets the number of consecutive bytes that have matched so far (0 when no match is active). Larger values indicate higher prediction confidence. | -| `MatchPointer` | `int MatchPointer { get; }` | Gets the position in the byte history currently being predicted from, or -1 when no match is active. | -| `PredictedByte` | `int PredictedByte { get; }` | Gets the predicted next byte, or -1 when no match is active. | -| `Append` | `void Append(byte value)` | Records the actual next byte, extending or breaking the active match and updating the context hash table for future lookups. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Bcm` - -[`BcmBuildingBlock`](#bcmbuildingblock) · [`BcmCompressor`](#bcmcompressor) - -#### `BcmBuildingBlock` - -Exposes the BCM-style BWT + context-mixing compressor as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcmBuildingBlock` | `BcmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcmCompressor` - -A clean-room implementation of the BCM architecture: a Burrows-Wheeler Transform followed by a small logistic-domain context-mixing back end. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data via BWT followed by context-mixing entropy coding. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses BCM-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Bsc` - -[`BscBuildingBlock`](#bscbuildingblock) · [`BscCompressor`](#bsccompressor) - -#### `BscBuildingBlock` - -Exposes the BSC-style BWT + Move-to-Front + adaptive coder as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BscBuildingBlock` | `BscBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BscCompressor` - -A clean-room implementation of the BSC architecture: a Burrows-Wheeler Transform, a Move-to-Front recoding, and a simple adaptive binary coder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data via BWT, Move-to-Front, and adaptive bit-tree coding. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses BSC-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Cmix` - -[`CmixBuildingBlock`](#cmixbuildingblock) · [`CmixCompressor`](#cmixcompressor) - -#### `CmixBuildingBlock` - -Exposes the reduced cmix-style model set as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CmixBuildingBlock` | `CmixBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `CmixCompressor` - -A clean-room, deliberately reduced reimplementation of the cmix architecture: hashed byte-order contexts, a word context, and a match model, mixed by one logistic-domain mixer and refined by a two-stage SSE chain. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data using the reduced cmix-style model set. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses reduced-cmix-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Csc` - -[`CscBuildingBlock`](#cscbuildingblock) · [`CscCompressor`](#csccompressor) - -#### `CscBuildingBlock` - -Exposes the CSC-style LZ77 + context-mixing compressor as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CscBuildingBlock` | `CscBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `CscCompressor` - -A clean-room implementation of the CSC architecture: LZ77 parsing whose literal and flag streams are entropy-coded with logistic-domain context mixing. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data via LZ77 parsing with a context-mixed entropy back end. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses CSC-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Ctw` - -[`ContextTreeWeightingBuildingBlock`](#contexttreeweightingbuildingblock) · [`ContextTreeWeightingCompressor`](#contexttreeweightingcompressor) - -#### `ContextTreeWeightingBuildingBlock` - -Exposes genuine Context Tree Weighting (CTW) as a benchmarkable building block: a bounded-depth binary context tree with a Krichevsky-Trofimov estimator at every node, recursively weighted between each node's own estimate and the product of its children, driving the repository's binary arithmetic coder. See `ContextTreeWeightingCompressor` for the full model description and citation. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ContextTreeWeightingBuildingBlock` | `ContextTreeWeightingBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ContextTreeWeightingCompressor` - -A clean-room implementation of the Context Tree Weighting (CTW) method: a bounded-depth binary context tree in which every node holds a Krichevsky-Trofimov (KT) probability estimator, and the coding probability of each node is the recursive equal-weight mixture of that node's own KT estimate and the product of its two children's weighted probabilities. The resulting per-bit probability drives the repository's existing binary arithmetic coder (`ArithmeticEncoder` / `ArithmeticDecoder`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ContextDepthBits` | `const int ContextDepthBits` | Depth of the binary context tree, in bits. Sixteen bits mixes every order from 0 (no context) up to a two-byte binary history. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data by driving a binary arithmetic coder with per-bit probabilities from a Context Tree Weighting model. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses data previously produced by `Compress`. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Mcm` - -[`McmBuildingBlock`](#mcmbuildingblock) · [`McmCompressor`](#mcmcompressor) - -#### `McmBuildingBlock` - -Exposes the MCM-style two-level context-mixing network as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `McmBuildingBlock` | `McmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `McmCompressor` - -A clean-room implementation of the MCM architecture: several small context-mixers, each specialised on a group of related contexts, combined by a final mixing stage into one prediction — a two-level mixing network. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data using the two-level context-mixing network. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses MCM-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextMixing.Paq8hp` - -[`Paq8hpBuildingBlock`](#paq8hpbuildingblock) · [`Paq8hpCompressor`](#paq8hpcompressor) - -#### `Paq8hpBuildingBlock` - -Exposes the reduced PAQ8hp-style model set as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Paq8hpBuildingBlock` | `Paq8hpBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Paq8hpCompressor` - -A clean-room, deliberately reduced reimplementation of the PAQ8hp architecture: hashed byte-order contexts and a match model mixed by context-selected weight sets — one of PAQ8's signature techniques — refined by an SSE stage. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data using the reduced PAQ8hp-style model set. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses reduced-PAQ8hp-style compressed data. | - -### Namespace `Compression.Core.Entropy.ContextModeling` - -[`BytePredictor`](#bytepredictor) - -#### `BytePredictor` - -Order-N byte prediction model that estimates the probability distribution of the next byte given the previous N bytes of context. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BytePredictor` | `BytePredictor(int maxOrder = 4)` | Initializes a new `BytePredictor` with the given maximum context order. | -| `MaxOrder` | `int MaxOrder { get; }` | Gets the maximum context order. | -| `PredictByte` | `byte PredictByte(ReadOnlySpan context)` | Returns the most likely next byte given the context. | -| `Predict` | `int[] Predict(ReadOnlySpan context)` | Predicts the probability distribution of the next byte given the context (previous bytes). | -| `Update` | `void Update(ReadOnlySpan context, byte symbol)` | Updates the model after observing a byte. | - -### Namespace `Compression.Core.Entropy.ExpGolomb` - -[`ExpGolombBuildingBlock`](#expgolombbuildingblock) · [`ExpGolombDecoder`](#expgolombdecoder) · [`ExpGolombEncoder`](#expgolombencoder) - -#### `ExpGolombBuildingBlock` - -Exposes Exponential Golomb coding as a benchmarkable building block. Used in H.264/H.265 video codecs for encoding syntax elements. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExpGolombBuildingBlock` | `ExpGolombBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ExpGolombDecoder` - -Exponential Golomb decoder. Reads exp-Golomb coded values from a bitstream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExpGolombDecoder` | `ExpGolombDecoder(byte[] data, int order = 0)` | Creates a decoder with the specified order k. | -| `HasData` | `bool HasData { get; }` | Returns true if there are at least 8 bits remaining to read. | -| `Decode` | `int Decode()` | Decodes one exp-Golomb coded value. | - -#### `ExpGolombEncoder` - -Exponential Golomb encoder. Used in H.264/H.265 video codecs. Order-k exp-Golomb maps non-negative integer n to a variable-length codeword. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExpGolombEncoder` | `ExpGolombEncoder(Stream output, int order = 0)` | Creates an encoder with the specified order k. | -| `Encode` | `void Encode(int value)` | Encodes a non-negative value using exp-Golomb coding. | -| `Flush` | `void Flush()` | Flushes any remaining bits in the buffer. | - -### Namespace `Compression.Core.Entropy.Fpaq` - -[`Fpaq0BuildingBlock`](#fpaq0buildingblock) - -#### `Fpaq0BuildingBlock` - -Exposes FPAQ0-style adaptive order-0 arithmetic compression as a benchmarkable building block. Each byte is coded MSB-first with one binary probability model per prefix of the current byte. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Fpaq0BuildingBlock` | `Fpaq0BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -### Namespace `Compression.Core.Entropy.Fse` - -[`FseDecoder`](#fsedecoder) · [`FseEncoder`](#fseencoder) · [`FseTable`](#fsetable) · [`HuffmanFse`](#huffmanfse) - -#### `FseDecoder` - -FSE entropy decoder using tANS (table-based Asymmetric Numeral Systems). Reads a backward bitstream produced by `FseEncoder` and recovers the original symbol sequence. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FseDecoder` | `FseDecoder(short[] normalizedCounts, int maxSymbol, int tableLog)` | Initializes a new FSE decoder from normalized counts. | -| `Decode` | `byte[] Decode(ReadOnlySpan compressed, int originalSize)` | Decodes compressed data produced by `Encode` and returns the original byte sequence. | -| `ReadNormalizedCounts` | `static ValueTuple ReadNormalizedCounts(ReadOnlySpan input)` | Reads normalized counts from data written by `WriteNormalizedCounts`. | - -#### `FseEncoder` - -FSE entropy encoder using tANS (table-based Asymmetric Numeral Systems). Encodes symbols from back to front, producing a backward bitstream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FseEncoder` | `FseEncoder(short[] normalizedCounts, int maxSymbol, int tableLog)` | Initializes a new FSE encoder from normalized counts. | -| `Encode` | `byte[] Encode(ReadOnlySpan data)` | Encodes a sequence of bytes using FSE and returns the compressed data. FSE encodes symbols from back to front and produces a backward bitstream. The output includes a sentinel bit to mark the bitstream boundary. | -| `NormalizeCounts` | `static short[] NormalizeCounts(int[] counts, int maxSymbol, int tableLog)` | Normalizes raw frequency counts to sum to `1 << tableLog`. Every symbol with a non-zero count gets at least one table entry (normalized count of -1 for sub-probability, or a positive value). | -| `WriteNormalizedCounts` | `static int WriteNormalizedCounts(byte[] output, int outputPos, short[] normalizedCounts, int maxSymbol, int tableLog)` | Writes normalized counts to a byte array using a compact header format. The header stores the tableLog and maxSymbol, followed by the count values encoded as 16-bit signed integers. | - -#### `FseTable` - -FSE decoding table built from normalized frequency counts. Each entry stores the output symbol, the number of bits to read for the state transition, and the base value for computing the next state. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NewStateBase` | `int[] NewStateBase { get; }` | Gets the base value for computing the next state. | -| `NumBits` | `int[] NumBits { get; }` | Gets the number of bits to read for each state transition. | -| `Symbol` | `byte[] Symbol { get; }` | Gets the symbol output for each state. | -| `TableLog` | `int TableLog { get; }` | Gets the table log (log2 of table size). | -| `Build` | `static FseTable Build(short[] normalizedCounts, int maxSymbol, int tableLog)` | Builds an FSE decoding table from normalized counts. | - -#### `HuffmanFse` - -Huffman coding as used by Zstandard, with weight tables optionally transmitted via FSE. Weights represent the number of bits for each symbol (0 = unused). A weight w means 2^(w-1) occurrences in the Huffman table for w > 0. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BuildWeights` | `static int[] BuildWeights(ReadOnlySpan data)` | Builds Huffman bit-length weights from frequency data. Weight w means the symbol has a code of w bits. 0 means unused. | -| `CompressHuffman` | `static byte[] CompressHuffman(ReadOnlySpan data, int maxSymbol = 255)` | Compresses data using Huffman coding with direct-encoded weights. | -| `DecompressHuffman` | `static byte[] DecompressHuffman(ReadOnlySpan compressed, int decompressedSize)` | Decompresses Huffman-coded data produced by `CompressHuffman`. | -| `ReadWeights` | `static int[] ReadWeights(ReadOnlySpan input, out int bytesRead)` | Reads a Huffman weight table from compressed data. | -| `WriteWeights` | `static int WriteWeights(byte[] output, int pos, int[] weights, int maxSymbol)` | Writes a Huffman weight table to the output buffer using direct representation (4 bits per weight, 2 weights per byte). | - -### Namespace `Compression.Core.Entropy.GolombRice` - -[`GolombRiceDecoder`](#golombricedecoder) · [`GolombRiceEncoder`](#golombriceencoder) - -#### `GolombRiceDecoder` - -Decodes values encoded with Golomb-Rice coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GolombRiceDecoder` | `GolombRiceDecoder(byte[] data, int k = 0)` | Initializes a new `GolombRiceDecoder`. | -| `BitPosition` | `long BitPosition { get; }` | Gets the current bit position in the data. | -| `K` | `int K { get; set; }` | Gets or sets the Rice parameter k (number of remainder bits). | -| `DecodeSigned` | `int DecodeSigned()` | Decodes a signed value using zig-zag mapping. | -| `Decode` | `int Decode()` | Decodes a non-negative value. | - -#### `GolombRiceEncoder` - -Encodes values using Golomb-Rice coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GolombRiceEncoder` | `GolombRiceEncoder(int k = 0)` | Initializes a new `GolombRiceEncoder` with the given Rice parameter. | -| `K` | `int K { get; set; }` | Gets or sets the Rice parameter k (number of remainder bits). | -| `EncodeSigned` | `void EncodeSigned(int value)` | Encodes a signed value using zig-zag mapping: 0→0, -1→1, 1→2, -2→3, ... | -| `Encode` | `void Encode(int value)` | Encodes a non-negative value. | -| `ToArray` | `byte[] ToArray()` | Returns the encoded data and resets the encoder. | - -### Namespace `Compression.Core.Entropy.Huffman` - -[`CanonicalHuffman`](#canonicalhuffman) · [`DeterministicHuffman`](#deterministichuffman) · [`HuffmanBuildingBlock`](#huffmanbuildingblock) · [`HuffmanDecoder`](#huffmandecodertorder) · [`HuffmanEncoder`](#huffmanencodertorder) · [`HuffmanNode`](#huffmannode) · [`HuffmanTree`](#huffmantree) - -#### `CanonicalHuffman` - -Builds canonical Huffman encode/decode tables from code lengths. Canonical codes assign codes in a deterministic manner given only the code lengths. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanonicalHuffman` | `CanonicalHuffman(int[] codeLengths)` | Builds canonical Huffman encode and decode tables from the given code lengths. | -| `MaxCodeLength` | `int MaxCodeLength { get; }` | Gets the maximum code length in bits. | -| `MaxSymbol` | `int MaxSymbol { get; }` | Gets the maximum symbol value in this table. | -| `DecodeSymbol` | `int DecodeSymbol(BitBuffer bitBuffer)` | Decodes a symbol from the bit buffer using the canonical Huffman table. | -| `DecodeSymbol` | `int DecodeSymbol(BitReader bitReader)` | Decodes a symbol by reading bits one at a time from a `BitReader`. This is slower than `DecodeSymbol` but works without lookahead. | -| `GetCode` | `ValueTuple GetCode(int symbol)` | Gets the canonical code and length for the specified symbol. | - -#### `DeterministicHuffman` - -Builds Huffman code lengths from symbol weights under an explicit total order on tree nodes, so that the resulting lengths are a function of the weights alone. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BuildCodeLengths` | `static int[] BuildCodeLengths(ReadOnlySpan weights)` | Builds Huffman code lengths for the given symbol weights. | -| `BuildCodeLengths` | `static int[] BuildCodeLengths(ReadOnlySpan weights)` | Builds Huffman code lengths for the given symbol weights. | - -#### `HuffmanBuildingBlock` - -Exposes canonical Huffman coding as a benchmarkable building block. Builds a frequency table from input, encodes with canonical codes, and stores the code lengths for decoding. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuffmanBuildingBlock` | `HuffmanBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `HuffmanDecoder` - -Reads and decodes Huffman-coded symbols from a stream. Generic on `TOrder` for zero-branch bit-order dispatch. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuffmanDecoder` | `HuffmanDecoder(CanonicalHuffman table, BitBuffer bitBuffer)` | Initializes a new `HuffmanDecoder`. | -| `DecodeSymbol` | `int DecodeSymbol()` | Decodes the next symbol from the bit stream. | -| `DecodeSymbols` | `int[] DecodeSymbols(int count)` | Decodes `count` symbols from the bit stream. | - -#### `HuffmanEncoder` - -Writes symbols to a stream using canonical Huffman coding. Codes are written MSB-first (the standard for canonical Huffman). Generic on `TOrder` for zero-branch bit-order dispatch. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuffmanEncoder` | `HuffmanEncoder(CanonicalHuffman table, BitWriter bitWriter)` | Initializes a new `HuffmanEncoder`. | -| `EncodeSymbol` | `void EncodeSymbol(int symbol)` | Encodes a single symbol. | -| `EncodeSymbols` | `void EncodeSymbols(ReadOnlySpan symbols)` | Encodes a sequence of symbols. | -| `Flush` | `void Flush()` | Flushes any remaining bits in the writer. | - -#### `HuffmanNode` - -A node in a Huffman tree. Leaf nodes carry a symbol; internal nodes have left and right children. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuffmanNode` | `HuffmanNode(HuffmanNode left, HuffmanNode right)` | Creates an internal node with the specified children. | -| `HuffmanNode` | `HuffmanNode(int symbol, long frequency)` | Creates a leaf node with the specified symbol and frequency. | -| `Frequency` | `long Frequency { get; }` | Gets the frequency (weight) of this node. | -| `IsLeaf` | `bool IsLeaf { get; }` | Gets whether this is a leaf node. | -| `Left` | `HuffmanNode Left { get; }` | Gets the left child (represents bit 0), or `null` for leaf nodes. | -| `Right` | `HuffmanNode Right { get; }` | Gets the right child (represents bit 1), or `null` for leaf nodes. | -| `Symbol` | `int Symbol { get; }` | Gets the symbol value for leaf nodes, or -1 for internal nodes. | - -#### `HuffmanTree` - -Provides static methods for building Huffman trees and extracting code lengths. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BuildFromFrequencies` | `static HuffmanNode BuildFromFrequencies(long[] frequencies)` | Builds a Huffman tree from symbol frequencies. | -| `GetCodeLengths` | `static int[] GetCodeLengths(HuffmanNode root, int maxSymbol)` | Extracts code lengths from a Huffman tree for each symbol. | -| `LimitCodeLengths` | `static void LimitCodeLengths(int[] codeLengths, int maxLength)` | Limits code lengths to a maximum value using the package-merge algorithm variant. Redistributes code lengths to satisfy the Kraft inequality while staying within the limit. | - -### Namespace `Compression.Core.Entropy.Neural` - -[`NeuralPredictor`](#neuralpredictor) · [`NnBuildingBlock`](#nnbuildingblock) · [`NnCompressor`](#nncompressor) - -#### `NeuralPredictor` - -An online-trained two-layer neural network that predicts the probability of the next bit being 1, learning its weights as it sees data. This is the statistical engine behind `NnCompressor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NeuralPredictor` | `NeuralPredictor()` | Initializes a fresh predictor with small, fixed (deterministic) weights so the hidden layer is active from the first bit and backprop has a non-zero gradient to flow through. Identical on encode and decode. | -| `Predict` | `int Predict(int partialByte)` | Predicts the probability that the next bit is 1, given the partial byte coded so far. Caches the forward pass for the matching `Update`. | -| `PushByte` | `void PushByte(int value)` | Shifts a fully decoded byte into the rolling history. | -| `Update` | `void Update(int bit)` | Trains the network on the observed bit (one SGD step of backprop) and updates the backing context models. Must follow a matching `Predict` call. | - -#### `NnBuildingBlock` - -Exposes the online neural predictor as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NnBuildingBlock` | `NnBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `NnCompressor` - -A clean-room neural compressor: an online-trained multi-layer perceptron (`NeuralPredictor`) drives a binary arithmetic coder bit-by-bit. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data with the online neural predictor. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed)` | Decompresses data produced by `Compress`. | - -### Namespace `Compression.Core.Entropy.Ppmd` - -[`PpmdBuildingBlock`](#ppmdbuildingblock) · [`PpmdContext`](#ppmdcontext) · [`PpmdModelBase`](#ppmdmodelbase) · [`PpmdModelBase.ContextKey`](#ppmdmodelbasecontextkey) · [`PpmdModelH`](#ppmdmodelh) · [`PpmdModelI`](#ppmdmodeli) · [`PpmdRangeDecoder`](#ppmdrangedecoder) · [`PpmdRangeEncoder`](#ppmdrangeencoder) - -#### `PpmdBuildingBlock` - -Exposes PPMd (Prediction by Partial Matching, variant H) as a benchmarkable building block. Wraps the existing `PpmdModelH` context-tree model with `PpmdRangeEncoder`/`PpmdRangeDecoder` range coding. Unlike the simpler order-2 fallback used by the plain `BB_PPM` block, this uses a full context trie with per-context escape estimation (PPM Method D) and periodic rescaling, matching the model family 7-Zip calls "PPMd". Header: 1-byte order, 4-byte LE original size, then the range-coded stream. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdBuildingBlock` | `PpmdBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `PpmdContext` - -Represents a context node in the PPMd context tree. Each context holds a frequency distribution for symbols that follow the context's byte sequence, along with an escape frequency for novel symbols. Uses PPM Method D escape estimation: the escape frequency equals the number of distinct symbols observed in this context. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdContext` | `PpmdContext()` | | -| `EscapeFreq` | `int EscapeFreq { get; }` | Gets the escape frequency for this context. Uses Method D: escape frequency = number of distinct symbols observed. This ensures contexts with many different symbols have higher escape probability, while contexts with few unique symbols give more probability to known symbols. Minimum is 1 so that escape is always possible. | -| `Frequencies` | `IReadOnlyDictionary Frequencies { get; }` | Gets the frequency table (read-only view). | -| `SymbolCount` | `int SymbolCount { get; }` | Gets the number of distinct symbols observed in this context. | -| `TotalFreq` | `int TotalFreq { get; }` | Gets the total frequency across all symbols plus the escape frequency. | -| `BuildCodingTable` | `List> BuildCodingTable(HashSet excludedSymbols = null)` | Builds a sorted list of (symbol, cumFreq, freq) entries for encoding/decoding. Symbols are sorted by byte value for deterministic ordering. The escape is appended as the last entry. | -| `GetFreq` | `int GetFreq(byte symbol)` | Gets the frequency of the specified symbol, or zero if not observed. | -| `IncrementFreq` | `void IncrementFreq(byte symbol)` | Increments the frequency of the specified symbol. If the symbol has not been seen before, it is added with frequency 1. | -| `Rescale` | `void Rescale()` | Rescales all frequencies by halving them. Any frequency that drops to zero causes the symbol to be removed. | -| `SetFreq` | `void SetFreq(byte symbol, int freq)` | Sets the frequency of the specified symbol to a given value. | - -#### `PpmdModelBase` - -Base class for PPMd (Prediction by Partial Matching) context models. Provides the core context-tree machinery shared between Model H and Model I variants. The model maintains a trie of byte contexts and predicts the next symbol based on the longest matching context, falling back to shorter contexts via escape coding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdModelBase` | `protected PpmdModelBase(int maxOrder)` | Initializes the base PPMd model. | -| `_maxOrder` | `protected readonly int _maxOrder` | Maximum context order for this model instance. | -| `DecodeSymbol` | `byte DecodeSymbol(PpmdRangeDecoder decoder)` | Decodes a single byte symbol using the PPMd algorithm. Tries the highest-order context first, falling back to lower orders on escape. | -| `EncodeSymbol` | `void EncodeSymbol(PpmdRangeEncoder encoder, byte symbol)` | Encodes a single byte symbol using the PPMd algorithm. Tries the highest-order context first, falling back to lower orders on escape. | -| `GetContext` | `protected PpmdContext GetContext(int order)` | Gets the context node for the given order, using the current history. Returns `null` if no such context exists. | -| `GetOrCreateContext` | `protected PpmdContext GetOrCreateContext(int order)` | Gets or creates the context node for the given order using the current history. | -| `GetRescaleThreshold` | `protected abstract int GetRescaleThreshold()` | Gets the total frequency threshold at which a context should be rescaled. | -| `MaybeRescale` | `protected virtual void MaybeRescale(PpmdContext ctx)` | When overridden in a derived class, applies variant-specific rescaling logic. Called after a context is updated. The default implementation rescales when the total frequency exceeds `GetRescaleThreshold`. | -| `Reset` | `void Reset()` | Resets the model to its initial state (empty context tree, empty history). | -| `UpdateModel` | `protected void UpdateModel(byte symbol)` | Updates all matching context nodes with the new symbol, then adds the symbol to the history ring buffer. Contexts are updated BEFORE the symbol is pushed so that context keys reflect the preceding byte sequence (not the current symbol). | - -#### `PpmdModelBase.ContextKey` - -A compact, hashable key identifying a context by its order and content hash. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ContextKey` | `ContextKey(int Order, ulong Hash)` | A compact, hashable key identifying a context by its order and content hash. | -| `Hash` | `ulong Hash { get; init; }` | | -| `Order` | `int Order { get; init; }` | | - -#### `PpmdModelH` - -PPMd Model H — Prediction by Partial Matching, variant H by Dmitry Shkarin. Used by 7-Zip for PPMd compression. This variant uses SEE (Secondary Escape Estimation) for more accurate escape probability modeling. - -Inherits `PpmdModelBase`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdModelH` | `PpmdModelH(int order)` | Initializes a new PPMd Model H with the specified order and default memory. | -| `PpmdModelH` | `PpmdModelH(int order, int memorySize)` | Initializes a new PPMd Model H with the specified order and memory budget. | -| `GetRescaleThreshold` | `protected override int GetRescaleThreshold()` | | - -#### `PpmdModelI` - -PPMd Model I — Prediction by Partial Matching, variant I. Used by RAR for PPMd compression. This variant uses interleaved context storage and different update rules compared to Model H. - -Inherits `PpmdModelBase`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdModelI` | `PpmdModelI(int order)` | Initializes a new PPMd Model I with the specified order and default memory. | -| `PpmdModelI` | `PpmdModelI(int order, int memorySize)` | Initializes a new PPMd Model I with the specified order and memory budget. | -| `GetRescaleThreshold` | `protected override int GetRescaleThreshold()` | | - -#### `PpmdRangeDecoder` - -Range decoder for PPMd, supporting multi-symbol frequency-based coding. Unlike the LZMA range coder which uses adaptive binary probabilities, this decoder works with cumulative frequency tables for multi-symbol alphabets. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdRangeDecoder` | `PpmdRangeDecoder(Stream input)` | Initializes a new `PpmdRangeDecoder` reading from the specified stream. | -| `IsFinished` | `bool IsFinished { get; }` | Gets whether the input stream is exhausted. | -| `Decode` | `void Decode(uint lowCumFreq, uint freq, uint totalFreq)` | Updates the decoder state after the caller has identified the decoded symbol. Must be called after `GetThreshold` once the symbol is determined. | -| `GetThreshold` | `uint GetThreshold(uint totalFreq)` | Gets the current cumulative frequency threshold for symbol lookup. The caller uses this value to determine which symbol falls in this range, then calls `Decode` with the symbol's frequency information. | - -#### `PpmdRangeEncoder` - -Range encoder for PPMd, supporting multi-symbol frequency-based coding. Unlike the LZMA range coder which uses adaptive binary probabilities, this encoder works with cumulative frequency tables for multi-symbol alphabets. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdRangeEncoder` | `PpmdRangeEncoder(Stream output)` | Initializes a new `PpmdRangeEncoder` writing to the specified stream. | -| `Encode` | `void Encode(uint lowCumFreq, uint freq, uint totalFreq)` | Encodes a symbol with the given cumulative frequency range. | -| `Finish` | `void Finish()` | Flushes remaining state to the output, completing the encoding. | - -### Namespace `Compression.Core.Entropy.RangeCoding` - -[`BitTreeDecoder`](#bittreedecoder) · [`BitTreeEncoder`](#bittreeencoder) · [`RangeDecoder`](#rangedecoder) · [`RangeEncoder`](#rangeencoder) - -#### `BitTreeDecoder` - -Binary tree decoder using range coding. Decodes N-bit values using a tree of adaptive probability variables. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitTreeDecoder` | `BitTreeDecoder(int numBits)` | Initializes a new `BitTreeDecoder` for the specified number of bits. | -| `Probs` | `int[] Probs { get; }` | Gets the probability array. Size is `1 << numBits`. | -| `Decode` | `int Decode(RangeDecoder decoder)` | Decodes a value MSB-first using the bit tree. | -| `Reset` | `void Reset()` | Resets all probabilities to the midpoint. | -| `ReverseDecode` | `int ReverseDecode(RangeDecoder decoder)` | Decodes a value LSB-first (reverse) using the bit tree. | -| `ReverseDecode` | `static int ReverseDecode(RangeDecoder decoder, Span probs, int startIndex, int numBits)` | Reverse-decodes a value from the given probability array. Static helper for shared prob arrays. | - -#### `BitTreeEncoder` - -Binary tree encoder using range coding. Encodes N-bit values using a tree of adaptive probability variables. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BitTreeEncoder` | `BitTreeEncoder(int numBits)` | Initializes a new `BitTreeEncoder` for the specified number of bits. | -| `Probs` | `int[] Probs { get; }` | Gets the probability array. Size is `1 << numBits`. | -| `Encode` | `void Encode(RangeEncoder encoder, int value)` | Encodes a value MSB-first using the bit tree. | -| `Reset` | `void Reset()` | Resets all probabilities to the midpoint. | -| `ReverseEncode` | `static void ReverseEncode(RangeEncoder encoder, Span probs, int startIndex, int numBits, int value)` | Reverse-encodes a value into the given probability array. Static helper for shared prob arrays (e.g., LZMA distance special positions). | -| `ReverseEncode` | `void ReverseEncode(RangeEncoder encoder, int value)` | Encodes a value LSB-first (reverse) using the bit tree. Used for distance extra bits in LZMA. | - -#### `RangeDecoder` - -LZMA-style byte-aligned range decoder with adaptive binary probabilities. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RangeDecoder` | `RangeDecoder(Stream input)` | Initializes a new `RangeDecoder` reading from the specified stream. | -| `IsFinished` | `bool IsFinished { get; }` | Gets whether the stream is finished (no more data available). | -| `DecodeBit` | `int DecodeBit(ref int prob)` | Decodes a single bit using an adaptive probability model. | -| `DecodeDirectBits` | `int DecodeDirectBits(int count)` | Decodes bits without probability adaptation (fixed 50/50 split). | - -#### `RangeEncoder` - -LZMA-style byte-aligned range encoder with adaptive binary probabilities. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RangeEncoder` | `RangeEncoder(Stream output)` | Initializes a new `RangeEncoder` writing to the specified stream. | -| `ProbInitValue` | `const int ProbInitValue` | Probability midpoint for initializing probability variables (1024 out of 2048). | -| `BytesWritten` | `long BytesWritten { get; }` | Gets the number of bytes written to the output stream. | -| `EncodeBit` | `void EncodeBit(ref int prob, int bit)` | Encodes a single bit using an adaptive probability model. | -| `EncodeDirectBits` | `void EncodeDirectBits(int value, int count)` | Encodes bits without probability adaptation (fixed 50/50 split). Used for alignment bits and direct-coded distance extra bits. | -| `Finish` | `void Finish()` | Finishes encoding by flushing remaining state to the output. | - -### Namespace `Compression.Core.ExecutableUnpacking` - -[`CpuArchitecture`](#cpuarchitecture) · [`DetectionResult`](#detectionresult) · [`ElfParser`](#elfparser) · [`ExecutableContainerKind`](#executablecontainerkind) · [`ExecutableContainerParsers`](#executablecontainerparsers) · [`ExecutableDiagnostic`](#executablediagnostic) · [`ExecutableDiagnosticCode`](#executablediagnosticcode) · [`ExecutableDiagnosticsJson`](#executablediagnosticsjson) · [`ExecutableImageInfo`](#executableimageinfo) · [`ExecutableImport`](#executableimport) · [`ExecutableMemoryImageBuilder`](#executablememoryimagebuilder) · [`ExecutableRegion`](#executableregion) · [`ExecutableRegionFlags`](#executableregionflags) · [`ExecutableRelocation`](#executablerelocation) · [`ExecutableUnpackCapabilities`](#executableunpackcapabilities) · [`ExecutableUnpackLevel`](#executableunpacklevel) · [`FatMachOParser`](#fatmachoparser) · [`IExecutableContainerParser`](#iexecutablecontainerparser) · [`IExecutablePackerHandler`](#iexecutablepackerhandler) · [`IPackerTransform`](#ipackertransform) · [`MachOParser`](#machoparser) · [`PackedExecutable`](#packedexecutable) · [`PeParser`](#peparser) · [`PeRebuilder`](#perebuilder) · [`TransformResult`](#transformresult) · [`UnpackArtifact`](#unpackartifact) · [`UnpackOptions`](#unpackoptions) · [`UnpackResult`](#unpackresult) - -#### `CpuArchitecture` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `X86` | `0` | | -| `X64` | `1` | | -| `Arm32` | `2` | | -| `Arm64` | `3` | | -| `PowerPc32` | `4` | | -| `PowerPc64` | `5` | | -| `Mips32Le` | `6` | | -| `Mips32Be` | `7` | | -| `Mips64Le` | `8` | | -| `Mips64Be` | `9` | | -| `Unknown` | `10` | | - -#### `DetectionResult` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DetectionResult` | `DetectionResult(bool IsMatch, string PackerId, double Confidence, IReadOnlyList Diagnostics)` | | -| `Confidence` | `double Confidence { get; init; }` | | -| `Diagnostics` | `IReadOnlyList Diagnostics { get; init; }` | | -| `IsMatch` | `bool IsMatch { get; init; }` | | -| `PackerId` | `string PackerId { get; init; }` | | - -#### `ElfParser` - -Implements `IExecutableContainerParser`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ElfParser` | `ElfParser()` | | -| `Kind` | `ExecutableContainerKind Kind { get; }` | | -| `CanParse` | `bool CanParse(ReadOnlySpan image)` | | -| `Parse` | `ExecutableImageInfo Parse(ReadOnlySpan image)` | | - -#### `ExecutableContainerKind` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Pe` | `0` | | -| `Elf` | `1` | | -| `MachO` | `2` | | -| `FatMachO` | `3` | | -| `DosMz` | `4` | | -| `DosCom` | `5` | | -| `LinearExecutable` | `6` | | -| `Unknown` | `7` | | - -#### `ExecutableContainerParsers` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Elf` | `static readonly IExecutableContainerParser Elf` | | -| `FatMachO` | `static readonly IExecutableContainerParser FatMachO` | | -| `MachO` | `static readonly IExecutableContainerParser MachO` | | -| `Pe` | `static readonly IExecutableContainerParser Pe` | | -| `ParseBestEffort` | `static ExecutableImageInfo ParseBestEffort(ReadOnlySpan image)` | | - -#### `ExecutableDiagnostic` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExecutableDiagnostic` | `ExecutableDiagnostic(ExecutableDiagnosticCode Code, string Message, bool IsError = false)` | | -| `Code` | `ExecutableDiagnosticCode Code { get; init; }` | | -| `IsError` | `bool IsError { get; init; }` | | -| `Message` | `string Message { get; init; }` | | - -#### `ExecutableDiagnosticCode` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `NotPackedExecutable` | `0` | | -| `UnsupportedContainer` | `1` | | -| `UnsupportedArchitecture` | `2` | | -| `UnsupportedPackerVersion` | `3` | | -| `PayloadNotFound` | `4` | | -| `UnsupportedCompressionMethod` | `5` | | -| `DecompressionFailed` | `6` | | -| `TransformNotReversible` | `7` | | -| `MemoryImageBuildFailed` | `8` | | -| `ExecutableRebuildFailed` | `9` | | -| `RunnableRebuildNotGuaranteed` | `10` | | - -#### `ExecutableDiagnosticsJson` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Build` | `static byte[] Build(string packer, ExecutableImageInfo imageInfo, UnpackResult result)` | | - -#### `ExecutableImageInfo` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExecutableImageInfo` | `ExecutableImageInfo(ExecutableContainerKind Container, CpuArchitecture Architecture, ulong PreferredBaseAddress, ulong EntryPoint, IReadOnlyList Regions, IReadOnlyList Imports, IReadOnlyList Relocations, IReadOnlyList Diagnostics)` | | -| `Architecture` | `CpuArchitecture Architecture { get; init; }` | | -| `Container` | `ExecutableContainerKind Container { get; init; }` | | -| `Diagnostics` | `IReadOnlyList Diagnostics { get; init; }` | | -| `EntryPoint` | `ulong EntryPoint { get; init; }` | | -| `Imports` | `IReadOnlyList Imports { get; init; }` | | -| `PreferredBaseAddress` | `ulong PreferredBaseAddress { get; init; }` | | -| `Regions` | `IReadOnlyList Regions { get; init; }` | | -| `Relocations` | `IReadOnlyList Relocations { get; init; }` | | - -#### `ExecutableImport` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExecutableImport` | `ExecutableImport(string ModuleName, string SymbolName, ulong Address)` | | -| `Address` | `ulong Address { get; init; }` | | -| `ModuleName` | `string ModuleName { get; init; }` | | -| `SymbolName` | `string SymbolName { get; init; }` | | - -#### `ExecutableMemoryImageBuilder` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Build` | `static ValueTuple, IReadOnlyList> Build(ExecutableImageInfo info, byte[] replacementPayload = null, string replacementTargetRegionName = null, UnpackOptions options = null)` | | - -#### `ExecutableRegion` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExecutableRegion` | `ExecutableRegion(string Name, ulong FileOffset, ulong FileSize, ulong VirtualAddress, ulong VirtualSize, ExecutableRegionFlags Flags, byte[] FileBytes, byte[] MemoryBytes)` | | -| `FileBytes` | `byte[] FileBytes { get; init; }` | | -| `FileOffset` | `ulong FileOffset { get; init; }` | | -| `FileSize` | `ulong FileSize { get; init; }` | | -| `Flags` | `ExecutableRegionFlags Flags { get; init; }` | | -| `MemoryBytes` | `byte[] MemoryBytes { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `VirtualAddress` | `ulong VirtualAddress { get; init; }` | | -| `VirtualSize` | `ulong VirtualSize { get; init; }` | | - -#### `ExecutableRegionFlags` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | | -| `Read` | `1` | | -| `Write` | `2` | | -| `Execute` | `4` | | -| `Bss` | `8` | | - -#### `ExecutableRelocation` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExecutableRelocation` | `ExecutableRelocation(ulong Address, string Type)` | | -| `Address` | `ulong Address { get; init; }` | | -| `Type` | `string Type { get; init; }` | | - -#### `ExecutableUnpackCapabilities` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | | -| `CanDetect` | `1` | | -| `CanLocatePayload` | `2` | | -| `CanDecompressPayload` | `4` | | -| `CanBuildMemoryImage` | `8` | | -| `CanRebuildExecutable` | `16` | | -| `CanProduceRunnableExecutable` | `32` | | -| `SupportsPe` | `256` | | -| `SupportsElf` | `512` | | -| `SupportsMachO` | `1024` | | -| `SupportsX86` | `65536` | | -| `SupportsX64` | `131072` | | -| `SupportsArm32` | `262144` | | -| `SupportsArm64` | `524288` | | - -#### `ExecutableUnpackLevel` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `DetectionOnly` | `0` | | -| `PayloadLocated` | `1` | | -| `PayloadDecompressed` | `2` | | -| `RuntimeMemoryImage` | `3` | | -| `RebuiltExecutable` | `4` | | -| `RunnableRebuiltExecutable` | `5` | | - -#### `FatMachOParser` - -Implements `IExecutableContainerParser`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatMachOParser` | `FatMachOParser()` | | -| `Kind` | `ExecutableContainerKind Kind { get; }` | | -| `CanParse` | `bool CanParse(ReadOnlySpan image)` | | -| `Parse` | `ExecutableImageInfo Parse(ReadOnlySpan image)` | | - -#### `IExecutableContainerParser` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Kind` | `ExecutableContainerKind Kind { get; }` | | -| `CanParse` | `bool CanParse(ReadOnlySpan image)` | | -| `Parse` | `ExecutableImageInfo Parse(ReadOnlySpan image)` | | - -#### `IExecutablePackerHandler` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `IPackerTransform` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Id` | `string Id { get; }` | | -| `CanReverse` | `bool CanReverse(PackedExecutable packed)` | | -| `Reverse` | `TransformResult Reverse(byte[] decompressedPayload, PackedExecutable packed)` | | - -#### `MachOParser` - -Implements `IExecutableContainerParser`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MachOParser` | `MachOParser()` | | -| `Kind` | `ExecutableContainerKind Kind { get; }` | | -| `CanParse` | `bool CanParse(ReadOnlySpan image)` | | -| `Parse` | `ExecutableImageInfo Parse(ReadOnlySpan image)` | | - -#### `PackedExecutable` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackedExecutable` | `PackedExecutable(string PackerId, byte[] OriginalImage, DetectionResult Detection, ExecutableImageInfo ImageInfo, ExecutableUnpackCapabilities Capabilities, IReadOnlyDictionary Metadata)` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; init; }` | | -| `Detection` | `DetectionResult Detection { get; init; }` | | -| `ImageInfo` | `ExecutableImageInfo ImageInfo { get; init; }` | | -| `Metadata` | `IReadOnlyDictionary Metadata { get; init; }` | | -| `OriginalImage` | `byte[] OriginalImage { get; init; }` | | -| `PackerId` | `string PackerId { get; init; }` | | - -#### `PeParser` - -Implements `IExecutableContainerParser`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PeParser` | `PeParser()` | | -| `Kind` | `ExecutableContainerKind Kind { get; }` | | -| `CanParse` | `bool CanParse(ReadOnlySpan image)` | | -| `Parse` | `ExecutableImageInfo Parse(ReadOnlySpan image)` | | - -#### `PeRebuilder` - -| Member | Signature | Summary | -| --- | --- | --- | -| `RebuildSynthetic` | `static byte[] RebuildSynthetic(ExecutableImageInfo original, byte[] payload)` | | - -#### `TransformResult` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TransformResult` | `TransformResult(byte[] Payload, IReadOnlyList Diagnostics)` | | -| `Diagnostics` | `IReadOnlyList Diagnostics { get; init; }` | | -| `Payload` | `byte[] Payload { get; init; }` | | - -#### `UnpackArtifact` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnpackArtifact` | `UnpackArtifact(string Name, byte[] Data, string Method = "stored")` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Method` | `string Method { get; init; }` | | -| `Name` | `string Name { get; init; }` | | - -#### `UnpackOptions` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnpackOptions` | `UnpackOptions(bool StrictRebuild = false, bool BestEffort = true, long MaximumInputSize = 268435456, long MaximumDecompressedSize = 536870912, int MaximumRegionCount = 4096, ulong MaximumVirtualAddressSpan = 536870912)` | | -| `BestEffort` | `bool BestEffort { get; init; }` | | -| `MaximumDecompressedSize` | `long MaximumDecompressedSize { get; init; }` | | -| `MaximumInputSize` | `long MaximumInputSize { get; init; }` | | -| `MaximumRegionCount` | `int MaximumRegionCount { get; init; }` | | -| `MaximumVirtualAddressSpan` | `ulong MaximumVirtualAddressSpan { get; init; }` | | -| `StrictRebuild` | `bool StrictRebuild { get; init; }` | | - -#### `UnpackResult` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnpackResult` | `UnpackResult(ExecutableUnpackLevel Level, ExecutableUnpackCapabilities Capabilities, IReadOnlyList Artifacts, IReadOnlyList Diagnostics)` | | -| `Artifacts` | `IReadOnlyList Artifacts { get; init; }` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; init; }` | | -| `Diagnostics` | `IReadOnlyList Diagnostics { get; init; }` | | -| `Level` | `ExecutableUnpackLevel Level { get; init; }` | | - -### Namespace `Compression.Core.Image` - -[`PlaneSplitter`](#planesplitter) · [`PlaneSplitter.PixelLayout`](#planesplitterpixellayout) - -#### `PlaneSplitter` - -Decomposes an RGB/RGBA raster image into per-plane 8-bit grayscale payloads encoded as binary PGM (portable graymap). Downstream tooling can load a plane in any image viewer without a custom decoder, which is the whole point of surfacing images as archives — "R.pgm" opens in GIMP/Photoshop as a grayscale image even though the source format was JPEG or PNG. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Split` | `static IReadOnlyList> Split(byte[] pixels, int width, int height, PixelLayout layout)` | Splits a packed 8-bit-per-channel raster into per-plane PGMs. Channel order in `pixels` must match `layout`: Rgb → RGBRGBRGB…, Rgba → RGBARGBARGBA…, Grayscale → LLLL…. | - -#### `PlaneSplitter.PixelLayout` - -Pixel layouts recognised by `Split`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Rgb` | `0` | 3 bytes per pixel: R, G, B. | -| `Rgba` | `1` | 4 bytes per pixel: R, G, B, A. | -| `Grayscale` | `2` | 1 byte per pixel: luminance. | - -### Namespace `Compression.Core.Layout` - -[`BlockMapView`](#blockmapview) · [`ClusterMove`](#clustermove) · [`DefragPlan`](#defragplan) · [`DefragPlanner`](#defragplanner) · [`DefragPlannerExecutor`](#defragplannerexecutor) · [`DefragStaging`](#defragstaging) · [`DefragStagingBuffer`](#defragstagingbuffer) · [`ExtentLayoutPlanner`](#extentlayoutplanner) · [`ExtentMove`](#extentmove) · [`FilesystemDefragmentor`](#filesystemdefragmentor) · [`FilesystemLayoutOptimizer`](#filesystemlayoutoptimizer) · [`LayoutOptimizerAdapter`](#layoutoptimizeradapter) · [`LiveExtent`](#liveextent) · [`MediaGeometry`](#mediageometry) · [`MediaProjection`](#mediaprojection) · [`PlatterWedge`](#platterwedge) · [`PlatterWedgeLayout`](#platterwedgelayout) · [`SectorCache`](#sectorcache) · [`StackedPlatterWedge`](#stackedplatterwedge) - -#### `BlockMapView` - -How a block-map view projects a logical byte offset / LBA onto screen space. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `LinearBlocks` | `0` | Linear tile grid (row-major by byte offset) — the classic view. | -| `LinearLba` | `1` | Linear by logical block address (one cell per sector run, LBA order). | -| `CircularPlatter` | `2` | 2-D circular platter: angle = sector-in-track, radius = cylinder (outer rim is cylinder 0), as data sits on a spinning disk. | -| `CylinderStack` | `3` | 3-D cylinder stack: angle = sector, radius = cylinder, height = head (platter surface), to show the head/cylinder layering of the medium. | - -#### `ClusterMove` - -A single planned cluster move: source offset, destination offset, byte length, and the file name the extent belongs to. Produced by `DefragPlanner` and consumed by `IFilesystemBlockMover`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ClusterMove` | `ClusterMove(long SrcOffset, long DstOffset, long Length, string FileName)` | A single planned cluster move: source offset, destination offset, byte length, and the file name the extent belongs to. Produced by `DefragPlanner` and consumed by `IFilesystemBlockMover`. | -| `DstOffset` | `long DstOffset { get; init; }` | | -| `FileName` | `string FileName { get; init; }` | | -| `Length` | `long Length { get; init; }` | | -| `SrcOffset` | `long SrcOffset { get; init; }` | | -| `StagingSlot` | `int StagingSlot { get; init; }` | Which staging slot this move parks into or unparks from. | -| `Staging` | `DefragStaging Staging { get; init; }` | How this move uses the staging buffer, when the volume had nowhere to park the run itself. | - -#### `DefragPlan` - -Planning result from `Plan`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragPlan` | `DefragPlan(IReadOnlyList Moves, IReadOnlyList> ResidualHoles, IReadOnlyList> CarvedHoles, long FinalImageLength, long TotalBytesMoved)` | Planning result from `Plan`. | -| `CarvedHoles` | `IReadOnlyList> CarvedHoles { get; init; }` | Holes that were intentionally created. Equals the requested region for `CarveHole`; equals the trailing free region for `ConsolidateAtStart`. | -| `FinalImageLength` | `long FinalImageLength { get; init; }` | Image length after the moves are applied (caller can pass to `Stream.SetLength` if they want to truncate trailing free space). | -| `Moves` | `IReadOnlyList Moves { get; init; }` | The byte-range moves that, when applied, achieve the planned layout. Apply via `ApplyMoves`. | -| `ResidualHoles` | `IReadOnlyList> ResidualHoles { get; init; }` | Holes that still exist after the plan is applied. Empty for `ConsolidateAtStart` / `ConsolidateAtEnd` (those guarantee contiguity). | -| `TotalBytesMoved` | `long TotalBytesMoved { get; init; }` | Sum of move lengths — the actual byte cost of executing this plan. Useful for picking between modes. | - -#### `DefragPlanner` - -Planner-driven defrag engine. Given the current extent layout (from `EnumerateExtents`), a `LayoutProfile`, and the image geometry, computes an ordered list of `ClusterMove`s that transform the current layout into the target layout. Algorithm overview (Performance profile):Classify files into zones (Hot / Normal / Cold / Frozen) based on modification time or listing order.Compute target offsets: Hot at front, then Normal, Cold, Frozen at end. Within each zone, files are ordered largest-first to minimise fragmentation of remaining free space.Build a dependency graph: move A depends on B if A's target overlaps B's current position.Topological sort the moves. For cycles (A→B→A), use a free region as temporary staging — one extra move per cycle.Return the ordered list.Quick profile: only consolidates per-file fragments (makes each file contiguous) without global rearrangement. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Plan` | `static IReadOnlyList Plan(IReadOnlyList extents, long dataOrigin, long imageSize, int clusterSize, LayoutProfile profile, DefragMode mode, int interleaveStride = 1, long holeSize = 0, long holeAt = -1, MetadataZone metadataZone = 0, LayoutTemplate layoutTemplate = null, IReadOnlySet movableMetadata = null, bool allowMemoryStaging = true)` | Plans moves for the given extent map and layout profile. | - -#### `DefragPlannerExecutor` - -Shared execution loop for planner-driven defragmentation. Runs an ordered list of `ClusterMove`s against the archive, emitting per-move progress events so the UI can animate cluster relocations tile-by-tile. Replaces the duplicated move loops in each filesystem descriptor's `DefragmentWithPlanner` method. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Execute` | `static void Execute(Stream archive, DefragOptions options, IFilesystemBlockMover mover, IReadOnlyList moves, long imageSize, Action reinitAfterMove = null, IFilesystemMetadataMover metadataMover = null)` | Executes the supplied `moves` against `archive`, calling `MoveExtent` and `UpdateAllocationAfterMove` for each move. Emits a `DefragProgressEvent` per move so the UI can animate read/write head positions in real time. | - -#### `DefragStaging` - -What a move does with the staging buffer. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | An ordinary move: read from the source, write to the destination. | -| `Park` | `1` | Take the run out of the volume and hold it, leaving the space free for something else. Nothing is written and nothing is repointed yet — the filesystem still records the run where it was. | -| `Unpark` | `2` | Put a held run down at its destination and repoint it there. The move's source is where the filesystem still thinks the run is, which is what the repointing looks for. | - -#### `DefragStagingBuffer` - -Holds runs of a volume's bytes while the space they came from is reused, so a layout change that has nowhere on disk to park them can still be made. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragStagingBuffer` | `DefragStagingBuffer(long memoryBudgetBytes = 268435456)` | | -| `DefaultMemoryBudgetBytes` | `const long DefaultMemoryBudgetBytes` | Bytes held in memory before the rest goes to scratch. | -| `HeldInMemoryBytes` | `long HeldInMemoryBytes { get; }` | Bytes currently held in memory. | -| `MemoryBudgetBytes` | `long MemoryBudgetBytes { get; }` | Bytes this buffer may hold in memory before spilling. | -| `Spilled` | `bool Spilled { get; }` | Whether anything had to go to scratch rather than memory. | -| `Dispose` | `void Dispose()` | | -| `Park` | `void Park(Stream image, int slot, long offset, long length)` | Reads a run out of the image and holds it under `slot`. | -| `Unpark` | `void Unpark(Stream image, int slot, long offset)` | Writes the run held under `slot` back into the image. | - -#### `ExtentLayoutPlanner` - -Filesystem-agnostic block-layout planner for filesystems that store byte data interleaved with directory metadata (FAT, ISO 9660, HFS+, ext, etc.). Use case: a file is removed, leaving a hole in the middle of an image. The caller wants to close the hole. Two strategies are available: PackFromOrigin — full sequential repack. Every live extent is laid out contiguously starting at the requested origin, in source order. Already-correctly-placed prefix extents stay in place; the suffix that has shifted gets moved. Result: minimum image size; total bytes moved equal the suffix from the first hole onwards.FillHolesBestFit — lazy compaction. Each hole is filled with a single tail extent that fits exactly (or under-fits, leaving a smaller hole behind). Best-fit pairing minimises wasted space. Result: residual fragmentation, but only the moved extents pay the byte-copy cost. Useful when the caller cares more about wall-clock time than image size — e.g., removing one small file from a 4GB ISO. The planner is pure: it returns a list of `ExtentMove` and optional residual hole list. It does not touch any stream. Filesystem- specific code is responsible for: Computing live extents (which byte ranges contain file data).Calling one of the planner methods.Updating directory records / FAT chains / inode pointers using the `Tag` back-reference.Calling `ApplyMoves` (or rolling its own equivalent) to shuffle bytes in the underlying stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApplyMoves` | `static void ApplyMoves(Stream stream, IReadOnlyList moves)` | Applies a planned move set to `stream`. Moves are ordered to avoid source-before-target overwrite hazards: backward moves (target < source) execute in ascending source order; forward moves (target > source) execute in descending source order. Each move's bytes are read into a pooled buffer and rewritten at the new offset. The caller is responsible for any final `SetLength` truncation if they want to drop trailing free space. | -| `FillHolesBestFit` | `static ValueTuple, IReadOnlyList>> FillHolesBestFit(IReadOnlyList extents, long imageOrigin)` | Lazy compaction: fills holes with single tail extents that fit, in best- fit order. Extents that don't fit any hole stay in place. Result is a non-contiguous layout but moves the minimum number of bytes. Best-fit pairing: holes are walked largest-first; for each hole the largest tail extent that still fits is selected. An exact fit closes the hole entirely; an under-fit leaves a residual hole at `(holeOffset + extent.Length, hole.Length - extent.Length)` reported in the returned residual list. | -| `PackFromOrigin` | `static IReadOnlyList PackFromOrigin(IReadOnlyList extents, long origin, long alignment = 1)` | Plans a move set that packs every live extent contiguously starting at `origin`, in source-offset order. Extents already at their target offset are not emitted as moves (zero-cost when the layout is already partially correct). Total byte-cost: sum of lengths of every extent that lies past the first source-order hole. | - -#### `ExtentMove` - -One planned move from `SourceOffset` to `TargetOffset` of `Length` bytes. `Tag` is copied from the originating `LiveExtent` so the caller can update whatever pointer references the moved range. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtentMove` | `ExtentMove(long SourceOffset, long TargetOffset, long Length, object Tag)` | One planned move from `SourceOffset` to `TargetOffset` of `Length` bytes. `Tag` is copied from the originating `LiveExtent` so the caller can update whatever pointer references the moved range. | -| `Length` | `long Length { get; init; }` | | -| `SourceOffset` | `long SourceOffset { get; init; }` | | -| `Tag` | `object Tag { get; init; }` | | -| `TargetOffset` | `long TargetOffset { get; init; }` | | - -#### `FilesystemDefragmentor` - -Filesystem-agnostic defragmentor. Composes `ExtentLayoutPlanner` into named, useful, mode-driven workflows. Like the planner itself, this is pure logic — it returns moves; the caller decides whether to apply them. The intended pipeline:Filesystem-specific code walks its directory structures and produces a `LiveExtent` per file (with `Tag` set to the originating directory record / FAT chain head).Caller invokes `Plan` with chosen `DefragOptions`.Caller iterates `Moves` and updates each pointer that referenced the old offset, using the move's `Tag` to identify which directory record / inode to patch.Caller invokes `ApplyMoves` on the underlying stream to perform the byte-level shuffling.Caller optionally truncates the stream to `FinalImageLength`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Plan` | `static DefragPlan Plan(IReadOnlyList extents, DefragOptions options)` | Plans a defragmentation pass over `extents` using the chosen `options`. | - -#### `FilesystemLayoutOptimizer` - -Generic grid-search optimizer for cluster-based filesystem layouts. Minimises the sum of internal slack (wasted bytes in the tail of each file's last cluster) and structural overhead (allocation tables, metadata zones, etc.) across all valid combinations of the supplied parameter candidates. The optimizer is filesystem-agnostic: the caller supplies a cost function that encodes all filesystem-specific knowledge. The optimizer just finds the global minimum over the candidate space, pruning invalid combinations (cost == null).Typical usage — FAT cluster size:Typical usage — NTFS cluster + MFT record size: - -| Member | Signature | Summary | -| --- | --- | --- | -| `StandardClusterSizes` | `static readonly IReadOnlyList StandardClusterSizes` | Standard cluster sizes for FAT, exFAT, NTFS, and similar filesystems. All are powers of two, from 512 B to 64 KB. | -| `DataClusters` | `static long DataClusters(IReadOnlyList fileSizes, long clusterBytes)` | Number of clusters required to store all files. Zero-length files occupy no clusters. Positive file sizes are rounded up to the nearest cluster. | -| `SelectClusterSizeTiered` | `static int SelectClusterSizeTiered(IReadOnlyList candidates, Func tierFn, Func costFn)` | Like `SelectClusterSize` but groups candidates by the "tier" returned by `tierFn` (e.g. FAT type: 12, 16, 32) and optimises within the lowest tier first. Only escalates to a higher tier when no candidate in the lower tier is valid. This prevents a large-cluster option from appearing cheaper (less slack) while silently pushing the image into a costlier filesystem variant (FAT16 → FAT32, or NTFS with a larger MFT zone), which would add more structural overhead than the slack savings justify. | -| `SelectClusterSize` | `static int SelectClusterSize(IReadOnlyList candidates, Func costFn)` | Selects the value from `candidates` that minimises the cost returned by `costFn`. Returns null (invalid) costs are skipped. When all costs are null, the first candidate is returned as a safe fallback. | -| `SelectPair` | `static ValueTuple SelectPair(IReadOnlyList candidates1, IReadOnlyList candidates2, Func costFn)` | Exhaustive search over all pairs from `candidates1` × `candidates2`. Finds the pair that minimises `costFn`. Null costs are treated as constraint violations and skipped. Falls back to (candidates1[0], candidates2[0]) if all pairs are invalid. | -| `Slack` | `static long Slack(IReadOnlyList fileSizes, long clusterBytes)` | Total internal slack: bytes wasted in the unfilled tail of the last cluster of every non-empty file. Zero-length files contribute zero slack. | - -#### `LayoutOptimizerAdapter` - -One-call front-end over `FilesystemLayoutOptimizer` for the common case: a filesystem whose only tunable is a single power-of-two allocation unit (cluster / block size) and whose cost is dominated by per-file tail slack plus a per-size fixed structural overhead. A writer opts in by supplying only three things:the candidate sizes that are legal for the format (the caller is responsible for keeping these inside the documented range — a size outside the legal window can corrupt the image);the file-set sizes that will be stored;a per-candidate fixed-overhead function (allocation tables, metadata zones, bitmaps, …) — return `null` for a candidate that violates a format constraint so it is pruned.The total cost for each candidate is `slack(fileSizes, size) + overhead(size)`; the adapter returns the candidate with the global minimum, tie-breaking toward the smaller size (the same semantics as `SelectClusterSize`). All filesystem-specific knowledge lives in the caller's overhead function; the slack term is computed here so writers don't re-implement it by hand.Typical usage — a writer with reader-agnostic clusters: - -| Member | Signature | Summary | -| --- | --- | --- | -| `SelectAllocationUnit` | `static int SelectAllocationUnit(IReadOnlyList candidateSizes, IReadOnlyList fileSizes, Func fixedOverhead = null)` | Picks the allocation-unit size (cluster / block, in bytes) from `candidateSizes` that minimises total internal slack across `fileSizes` plus the per-size `fixedOverhead`. | -| `SlackAt` | `static long SlackAt(IReadOnlyList fileSizes, int unitSize)` | Total internal slack (wasted last-cluster tail bytes) the supplied file-set would incur at `unitSize`. Exposed so callers can report the before/after savings of a chosen unit without reaching into `FilesystemLayoutOptimizer` directly. | - -#### `LiveExtent` - -One contiguous run of bytes the caller wants to keep alive across a layout rewrite. Carries an opaque `Tag` so callers can correlate the planner's output back to their own metadata (a directory record, an inode, a FAT chain head, …) without the planner having to know what filesystem it's serving. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LiveExtent` | `LiveExtent(long SourceOffset, long Length, object Tag = null)` | One contiguous run of bytes the caller wants to keep alive across a layout rewrite. Carries an opaque `Tag` so callers can correlate the planner's output back to their own metadata (a directory record, an inode, a FAT chain head, …) without the planner having to know what filesystem it's serving. | -| `Length` | `long Length { get; init; }` | | -| `SourceOffset` | `long SourceOffset { get; init; }` | | -| `Tag` | `object Tag { get; init; }` | | - -#### `MediaGeometry` - -Cylinder/head/sector (CHS) geometry of a storage medium and the conversions between a flat logical block address (LBA) and its physical (cylinder, head, sector) coordinate. Used by the block-map visualiser to place each block where it would physically reside on the medium. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MediaGeometry` | `MediaGeometry(int BytesPerSector, int SectorsPerTrack, int Heads, long TotalSectors)` | Cylinder/head/sector (CHS) geometry of a storage medium and the conversions between a flat logical block address (LBA) and its physical (cylinder, head, sector) coordinate. Used by the block-map visualiser to place each block where it would physically reside on the medium. | -| `BytesPerSector` | `int BytesPerSector { get; init; }` | | -| `Cylinders` | `long Cylinders { get; }` | Number of cylinders needed to hold `TotalSectors`. | -| `Heads` | `int Heads { get; init; }` | | -| `SectorsPerCylinder` | `long SectorsPerCylinder { get; }` | Sectors per cylinder = sectorsPerTrack × heads. | -| `SectorsPerTrack` | `int SectorsPerTrack { get; init; }` | | -| `TotalSectors` | `long TotalSectors { get; init; }` | | -| `ChsFromLba` | `ValueTuple ChsFromLba(long lba)` | Splits a logical block address into (cylinder, head, sector). | -| `FromGeometry` | `static MediaGeometry FromGeometry(long totalBytes, int bytesPerSector, int sectorsPerTrack, int heads)` | Geometry from an explicit BPB-style description. | -| `Heuristic` | `static MediaGeometry Heuristic(long totalBytes, int bytesPerSector = 512)` | Picks plausible real-world CHS geometry for an image of `totalBytes`. Returns a known standard format (5¼" / 3½" / Zip / Jaz / typical HDD) when the size matches one; otherwise scales heads + cylinders proportionally to keep the cylinder count in [128, 4096] and sectors-per-track at 63. Use this instead of `Standard` when you want the visualization to reflect realistic geometry rather than the 255-head/63-spt HDD default. | -| `LbaFromChs` | `long LbaFromChs(long cylinder, int head, int sector)` | Reassembles a logical block address from (cylinder, head, sector). | -| `LbaOfByte` | `long LbaOfByte(long byteOffset)` | The LBA a byte offset falls in. | -| `Standard` | `static MediaGeometry Standard(long totalBytes, int bytesPerSector = 512)` | Standard hard-disk/USB geometry (63 sectors/track, 255 heads) for an image of `totalBytes`, rounded up to whole sectors. | - -#### `MediaProjection` - -Pure projections of an LBA onto normalised coordinates for each `BlockMapView`. The UI maps these unit values onto its canvas. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CircularPlatter` | `static ValueTuple CircularPlatter(MediaGeometry g, long lba, double innerRadiusFraction = 0.25)` | 2-D platter coordinate: angle in radians [0, 2π) from the sector position within its track, and radius (0..1) from the cylinder — cylinder 0 is the outer rim (radius 1), the innermost cylinder maps to `innerRadiusFraction`. | -| `CylinderStack` | `static ValueTuple CylinderStack(MediaGeometry g, long lba)` | 3-D cylinder-stack coordinate: angle (sector), radius (cylinder, 0..1 inner→outer), and height z (head/platter surface, 0..1). | -| `LinearFraction` | `static double LinearFraction(MediaGeometry g, long lba)` | Fraction (0..1) of the way through the medium for a linear/LBA view. | - -#### `PlatterWedge` - -One filled arc-segment (annular wedge) of a circular platter — the minimal primitive a defrag-style visualiser draws per LBA range. Angles are measured CW from the 12-o'clock position (matching how a real platter is read), radii are normalised 0..1 from the spindle outward. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PlatterWedge` | `PlatterWedge(double StartAngle, double SweepAngle, double InnerRadius, double OuterRadius)` | One filled arc-segment (annular wedge) of a circular platter — the minimal primitive a defrag-style visualiser draws per LBA range. Angles are measured CW from the 12-o'clock position (matching how a real platter is read), radii are normalised 0..1 from the spindle outward. | -| `InnerRadius` | `double InnerRadius { get; init; }` | Inner edge radius (0..1, 0 = spindle). | -| `IsFullRing` | `bool IsFullRing { get; }` | True iff this wedge spans the entire ring (used to short-circuit arc-segment construction in favour of a plain annulus). | -| `OuterRadius` | `double OuterRadius { get; init; }` | Outer edge radius (0..1, 1 = rim). | -| `StartAngle` | `double StartAngle { get; init; }` | Start angle in radians (CW from 12-o'clock). | -| `SweepAngle` | `double SweepAngle { get; init; }` | Angular extent in radians, always positive. | - -#### `PlatterWedgeLayout` - -Pure-geometry helpers that turn a byte range into the platter wedge a real defrag tool would draw for it. Independent of any UI framework so the layout maths can be unit-tested without WPF/GDI. The wedge concept: each tile renders as a filled annular segment whose angular extent matches the tile's sector range within a track and whose radial extent matches the cylinder range, exactly like UltimateDefrag's doughnut view. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ComputeStackedWedge` | `static StackedPlatterWedge ComputeStackedWedge(MediaGeometry g, long startByte, long endByteExclusive, double innerRadiusFraction = 0.25)` | 3-D variant: computes the head index plus the 2-D wedge on that head's platter. For ranges that straddle multiple heads, the wedge is returned for the START head — callers wanting per-head accuracy should slice their input range by head boundaries first. | -| `ComputeWedge` | `static PlatterWedge ComputeWedge(MediaGeometry g, long startByte, long endByteExclusive, double innerRadiusFraction = 0.25)` | Computes the 2-D annular wedge for a byte range on a single platter (head-agnostic view: the byte range may straddle heads, the wedge summarises the full radial sweep across cylinders). | -| `CylinderThickness` | `static double CylinderThickness(MediaGeometry g, double innerRadiusFraction = 0.25)` | Per-cylinder track thickness in normalised radius units. | -| `RadiusForCylinder` | `static double RadiusForCylinder(MediaGeometry g, long cylinder, double innerRadiusFraction = 0.25)` | Outer-edge radius of a track at the given cylinder. | - -#### `SectorCache` - -Chunked LRU read cache over a `Stream`. Lets extent walkers and block movers read FAT entries, allocation bitmaps, MFT records, etc. at arbitrary offsets without loading the whole image into memory. Designed for multi-TB filesystem images where the FAT alone (50 GB for a 50 TB exFAT volume) does not fit in RAM. Reads happen in fixed-size chunks (default 64 KB); recently-accessed chunks stay resident up to a configurable memory cap (default 256 MB ≈ 4096 chunks). LRU eviction beyond the cap. Sequential access (the common case — walking a defragmented file's chain) hits the same chunk repeatedly; random access (heavily fragmented FS) may miss once per cluster but the OS page cache absorbs much of that cost. Write coherence: if the caller writes to the underlying stream outside this cache, call `Invalidate` for the affected range so subsequent reads observe the new bytes. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SectorCache` | `SectorCache(Stream stream, int chunkSize = 65536, int maxChunks = 4096)` | | -| `DefaultChunkSize` | `const int DefaultChunkSize` | Default chunk size (64 KB). | -| `DefaultMaxChunks` | `const int DefaultMaxChunks` | Default chunk count (4096 × 64 KB ≈ 256 MB cap). | -| `Length` | `long Length { get; }` | Stream length passthrough. | -| `Dispose` | `void Dispose()` | | -| `InvalidateAll` | `void InvalidateAll()` | Drops all cached chunks (e.g. after a full image rewrite). | -| `Invalidate` | `void Invalidate(long offset, int length)` | Invalidates cached chunks overlapping [offset, offset+length). Call after any direct write to the underlying stream so the next Read returns the fresh bytes from disk. | -| `Read` | `byte[] Read(long offset, int length)` | Convenience wrapper that allocates the destination buffer. | -| `Read` | `void Read(long offset, Span dest)` | Reads `dest`.Length bytes starting at `offset` into `dest`. Spans multiple chunks transparently. | - -#### `StackedPlatterWedge` - -3-D extension of `PlatterWedge` for the cylinder-stack view: the wedge plus the head index it sits on. The 2-D wedge is interpreted on the platter for that head. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StackedPlatterWedge` | `StackedPlatterWedge(int Head, PlatterWedge Wedge)` | 3-D extension of `PlatterWedge` for the cylinder-stack view: the wedge plus the head index it sits on. The 2-D wedge is interpreted on the platter for that head. | -| `Head` | `int Head { get; init; }` | 0-based head index (which platter surface). | -| `Wedge` | `PlatterWedge Wedge { get; init; }` | 2-D wedge geometry for this head. | - -### Namespace `Compression.Core.Progress` - -[`ICompressionProgress`](#icompressionprogress) - -#### `ICompressionProgress` - -Interface for reporting compression/decompression progress. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Report` | `void Report(long bytesProcessed, long totalBytes)` | Reports progress of the current operation. | - -### Namespace `Compression.Core.Simd` - -[`SimdBitPack`](#simdbitpack) · [`SimdHistogram`](#simdhistogram) · [`SimdMatchLength`](#simdmatchlength) · [`SimdMemCopy`](#simdmemcopy) · [`SimdRunScan`](#simdrunscan) - -#### `SimdBitPack` - -SIMD-accelerated bit packing and unpacking for symbol streams. Uses BMI2 PDEP/PEXT instructions when available, with a scalar fallback. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GetPackedByteCount` | `static int GetPackedByteCount(int symbolCount, int bitsPerSymbol)` | Calculates the number of bytes required to store the given number of symbols at the specified bits-per-symbol rate. | -| `PackBits` | `static int PackBits(ReadOnlySpan symbols, int bitsPerSymbol, Span output)` | Packs symbols into a dense bitstream where each symbol occupies exactly `bitsPerSymbol` bits. | -| `UnpackBits` | `static int UnpackBits(ReadOnlySpan packed, int bitsPerSymbol, Span output, int count)` | Unpacks a dense bitstream into individual symbols where each symbol was stored using `bitsPerSymbol` bits. | - -#### `SimdHistogram` - -SIMD-accelerated byte frequency histogram for entropy analysis and Huffman tree building. Uses four-way unrolled counting with SIMD scatter when available, falling back to a four-way scalar unroll for cache-friendly counting. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ComputeEntropy` | `static double ComputeEntropy(ReadOnlySpan data)` | Computes the Shannon entropy (in bits per byte) of the given data. Uses the SIMD-accelerated histogram internally. | -| `ComputeHistogram` | `static long[] ComputeHistogram(ReadOnlySpan data)` | Counts the frequency of each byte value (0-255) in the given data. Returns a 256-element array where index `i` is the count of byte value `i`. | -| `ComputeHistogram` | `static void ComputeHistogram(ReadOnlySpan data, Span counts)` | Counts the frequency of each byte value (0-255) in the given data, writing results into the provided 256-element span (which is NOT cleared first). Uses a scalar four-way unrolled loop for cache-friendly counting. | -| `ComputeHistogram` | `static void ComputeHistogram(ReadOnlySpan data, long[] counts)` | Counts the frequency of each byte value (0-255) in the given data, writing results into the provided 256-element array (which is NOT cleared first). | - -#### `SimdMatchLength` - -SIMD-accelerated match length calculation for LZ-style compressors. Compares two spans byte-by-byte and returns the length of the matching prefix, using `Vector256` to compare 32 bytes at a time when available. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GetMatchLength` | `static int GetMatchLength(ReadOnlySpan a, ReadOnlySpan b, int limit)` | Returns the number of leading bytes that are identical between two separate spans, up to a maximum of `limit` bytes. | -| `GetMatchLength` | `static int GetMatchLength(ReadOnlySpan data, int pos1, int pos2, int limit)` | Returns the number of leading bytes that are identical in `data` starting at positions `pos1` and `pos2`, up to a maximum of `limit` bytes. | - -#### `SimdMemCopy` - -SIMD-accelerated memory copy utilities for bulk literal output in decompressors. Uses `Vector256` to copy 32 bytes at a time when available, falling back to `CopyTo` for smaller blocks. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Copy` | `static void Copy(ReadOnlySpan source, int srcOffset, Span destination, int dstOffset, int length)` | Copies `length` bytes from `source` at `srcOffset` to `destination` at `dstOffset` using SIMD when beneficial. | -| `Fill` | `static void Fill(Span destination, int offset, int length, byte value)` | Fills `length` bytes in `destination` starting at `offset` with the given `value` using SIMD broadcast. | - -#### `SimdRunScan` - -SIMD-accelerated run-length scanning for RLE encoders. Uses `Vector256` to quickly find where consecutive equal bytes end (i.e., the first position where `data[i] != data[i-1]`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `FindAllRuns` | `static List> FindAllRuns(ReadOnlySpan data, int maxRunLength = 255)` | Scans `data` and returns an array of (start, length, value) tuples representing all runs. Uses SIMD acceleration when available. | -| `GetRunLength` | `static int GetRunLength(ReadOnlySpan data, int start, int maxRun)` | Starting from position `start` in `data`, returns the length of the run of bytes equal to `data[start]`. The run length is capped at `maxRun`. | - -### Namespace `Compression.Core.Statistics` - -[`FileFingerprint`](#filefingerprint) · [`FileSimilarityGrouper`](#filesimilaritygrouper) - -#### `FileFingerprint` - -A statistical fingerprint of file contents: bigram histogram, entropy, and chi-square score. Two files with similar fingerprints are likely to compress well together in a solid block. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FileFingerprint` | `FileFingerprint(double Entropy, double ChiSquare, double[] BigramHistogram, int SampleSize)` | A statistical fingerprint of file contents: bigram histogram, entropy, and chi-square score. Two files with similar fingerprints are likely to compress well together in a solid block. | -| `BigramHistogram` | `double[] BigramHistogram { get; init; }` | 256-element XOR-folded bigram frequency vector (sums to ~1.0). | -| `ChiSquare` | `double ChiSquare { get; init; }` | Chi-square uniformity score (higher = more structured/compressible). | -| `Entropy` | `double Entropy { get; init; }` | Shannon entropy in bits (0-8). | -| `SampleSize` | `int SampleSize { get; init; }` | Number of bytes actually sampled. | - -#### `FileSimilarityGrouper` - -Computes statistical fingerprints of file contents and groups statistically-similar files together for better solid-block compression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ComputeFingerprint` | `static FileFingerprint ComputeFingerprint(byte[] data)` | Computes a statistical fingerprint for a byte array: bigram histogram, entropy, chi-square uniformity score. Two files with similar fingerprints are likely to compress well together in a solid block. | -| `Distance` | `static double Distance(FileFingerprint a, FileFingerprint b)` | Measures similarity between two fingerprints (0.0 = identical, 1.0 = maximally different). Uses Pearson correlation of bigram histograms + entropy distance + chi-square divergence. | -| `GroupBySimilarity` | `static List> GroupBySimilarity(IReadOnlyList files, int maxGroups, long maxGroupSize)` | Groups files into clusters of statistically-similar content. Uses greedy agglomerative clustering: start with each file as its own cluster, repeatedly merge the two most-similar clusters until we reach the target count or max-cluster-size is hit. | - -### Namespace `Compression.Core.Streams` - -[`CompressionStream`](#compressionstream) · [`CompressionStreamMode`](#compressionstreammode) · [`ConcatenatedStream`](#concatenatedstream) · [`VolumeHelper`](#volumehelper) - -#### `CompressionStream` - -Abstract base class for compression/decompression streams. Routes Read/Write operations based on the mode. Subclasses implement the actual compression/decompression logic. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressionStream` | `protected CompressionStream(Stream stream, CompressionStreamMode mode, bool leaveOpen = false)` | Initializes a new `CompressionStream`. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `InnerStream` | `protected Stream InnerStream { get; }` | Gets the underlying stream. | -| `Length` | `override long Length { get; }` | | -| `Mode` | `CompressionStreamMode Mode { get; }` | Gets the compression mode. | -| `Position` | `override long Position { get; set; }` | | -| `CompressBlock` | `protected abstract void CompressBlock(byte[] buffer, int offset, int count)` | Compresses data from the provided buffer and writes it to the inner stream. | -| `DecompressBlock` | `protected abstract int DecompressBlock(byte[] buffer, int offset, int count)` | Decompresses data from the inner stream into the provided buffer. | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `FinishCompression` | `protected virtual void FinishCompression()` | Called when the stream is being closed in Compress mode. Implementations should flush any remaining compressed data. | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `CompressionStreamMode` - -Specifies whether a compression stream is compressing or decompressing. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Compress` | `0` | The stream compresses data written to it. | -| `Decompress` | `1` | The stream decompresses data read from it. | - -#### `ConcatenatedStream` - -Presents multiple streams as a single seekable, read-only stream. Used for reading multi-volume/split archives where volumes are byte-aligned splits of one logical stream. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ConcatenatedStream` | `ConcatenatedStream(Stream[] segments, bool leaveOpen = false)` | Creates a concatenated view of multiple streams. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `VolumeHelper` - -Utility for splitting archive data into fixed-size volumes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SplitIntoVolumes` | `static byte[][] SplitIntoVolumes(byte[] data, long maxVolumeSize)` | Splits a byte array into volumes of the specified maximum size. | -| `WriteVolumes` | `static void WriteVolumes(byte[] data, long maxVolumeSize, Stream[] volumeStreams)` | Writes volumes to a set of streams. | - -### Namespace `Compression.Core.Transforms` - -[`Bcj2Filter`](#bcj2filter) · [`BcjArm64BuildingBlock`](#bcjarm64buildingblock) · [`BcjArmBuildingBlock`](#bcjarmbuildingblock) · [`BcjArmThumbBuildingBlock`](#bcjarmthumbbuildingblock) · [`BcjFilter`](#bcjfilter) · [`BcjIa64BuildingBlock`](#bcjia64buildingblock) · [`BcjPowerPcBuildingBlock`](#bcjpowerpcbuildingblock) · [`BcjRiscVBuildingBlock`](#bcjriscvbuildingblock) · [`BcjSparcBuildingBlock`](#bcjsparcbuildingblock) · [`BcjX86BuildingBlock`](#bcjx86buildingblock) · [`BurrowsWheelerTransform`](#burrowswheelertransform) · [`BwtBuildingBlock`](#bwtbuildingblock) · [`DeltaBuildingBlock`](#deltabuildingblock) · [`DeltaFilter`](#deltafilter) · [`DeltaRleBuildingBlock`](#deltarlebuildingblock) · [`DeltaRleEncoding`](#deltarleencoding) · [`DpcmBuildingBlock`](#dpcmbuildingblock) · [`MoveToFrontTransform`](#movetofronttransform) · [`MtfBuildingBlock`](#mtfbuildingblock) · [`PackBitsBuildingBlock`](#packbitsbuildingblock) · [`PackBitsEncoding`](#packbitsencoding) · [`RleBuildingBlock`](#rlebuildingblock) · [`RunLengthEncoding`](#runlengthencoding) - -#### `Bcj2Filter` - -BCJ2 filter for 7z: splits x86 code into 4 sub-streams. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan mainStream, ReadOnlySpan callStream, ReadOnlySpan jumpStream, ReadOnlySpan rangeStream, int outputSize)` | Decodes BCJ2-filtered data from 4 input streams. | -| `Encode` | `static ValueTuple Encode(ReadOnlySpan data)` | Encodes data using the BCJ2 filter, producing 4 output streams. | - -#### `BcjArm64BuildingBlock` - -Exposes the ARM64 (AArch64) BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjArm64BuildingBlock` | `BcjArm64BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjArmBuildingBlock` - -Exposes the ARM BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjArmBuildingBlock` | `BcjArmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjArmThumbBuildingBlock` - -Exposes the ARM Thumb BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjArmThumbBuildingBlock` | `BcjArmThumbBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjFilter` - -Branch/Call/Jump (BCJ) filters for executable preprocessing. Converts relative branch/call/jump target addresses to absolute addresses, which improves compression by making repeated references to the same function produce identical byte sequences. Supports x86, ARM, ARM Thumb, ARM64, PowerPC, SPARC, IA-64 (Itanium), and RISC-V architectures. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecodeArm64` | `static byte[] DecodeArm64(ReadOnlySpan data, int startOffset = 0)` | Decodes ARM64 (AArch64) machine code by converting absolute BL and ADRP addresses back to relative. Matches the liblzma arm64 filter. | -| `DecodeArmThumb` | `static byte[] DecodeArmThumb(ReadOnlySpan data, int startOffset = 0)` | Decodes ARM Thumb machine code by converting absolute BL addresses back to relative. | -| `DecodeArm` | `static byte[] DecodeArm(ReadOnlySpan data, int startOffset = 0)` | Decodes ARM machine code by converting absolute BL addresses back to relative. | -| `DecodeIA64` | `static byte[] DecodeIA64(ReadOnlySpan data, int startOffset = 0)` | Decodes IA-64 (Itanium) machine code by converting absolute branch target addresses back to relative addresses within 128-bit instruction bundles. | -| `DecodePowerPC` | `static byte[] DecodePowerPC(ReadOnlySpan data, int startOffset = 0)` | Decodes PowerPC machine code by converting absolute B/BL addresses back to relative. | -| `DecodeRiscV` | `static byte[] DecodeRiscV(ReadOnlySpan data, int startOffset = 0)` | Decodes RISC-V machine code produced by `EncodeRiscV`. Faithful port of liblzma riscv.c. | -| `DecodeSparc` | `static byte[] DecodeSparc(ReadOnlySpan data, int startOffset = 0)` | Decodes SPARC machine code by converting absolute CALL addresses back to relative. | -| `DecodeX86` | `static byte[] DecodeX86(ReadOnlySpan data, int startOffset = 0)` | Decodes x86 machine code by converting absolute CALL/JMP addresses back to relative. | -| `EncodeArm64` | `static byte[] EncodeArm64(ReadOnlySpan data, int startOffset = 0)` | Encodes ARM64 (AArch64) machine code by converting relative BL and ADRP target addresses to absolute addresses. Matches the liblzma arm64 filter. | -| `EncodeArmThumb` | `static byte[] EncodeArmThumb(ReadOnlySpan data, int startOffset = 0)` | Encodes ARM Thumb machine code by converting relative BL (Branch with Link) instruction offsets to absolute addresses. | -| `EncodeArm` | `static byte[] EncodeArm(ReadOnlySpan data, int startOffset = 0)` | Encodes ARM machine code by converting relative BL (Branch with Link) instruction offsets to absolute addresses. | -| `EncodeIA64` | `static byte[] EncodeIA64(ReadOnlySpan data, int startOffset = 0)` | Encodes IA-64 (Itanium) machine code by converting relative branch target addresses to absolute addresses within 128-bit instruction bundles. | -| `EncodePowerPC` | `static byte[] EncodePowerPC(ReadOnlySpan data, int startOffset = 0)` | Encodes PowerPC machine code by converting relative B/BL (Branch/Branch with Link) instruction offsets to absolute addresses. | -| `EncodeRiscV` | `static byte[] EncodeRiscV(ReadOnlySpan data, int startOffset = 0)` | Encodes RISC-V machine code by converting JAL and AUIPC+inst2 pc-relative references to a canonical absolute form. Faithful port of liblzma riscv.c. | -| `EncodeSparc` | `static byte[] EncodeSparc(ReadOnlySpan data, int startOffset = 0)` | Encodes SPARC machine code by converting relative CALL instruction offsets to absolute addresses. | -| `EncodeX86` | `static byte[] EncodeX86(ReadOnlySpan data, int startOffset = 0)` | Encodes x86 machine code by converting relative CALL/JMP addresses to absolute. | - -#### `BcjIa64BuildingBlock` - -Exposes the IA-64 (Itanium) BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjIa64BuildingBlock` | `BcjIa64BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjPowerPcBuildingBlock` - -Exposes the PowerPC BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjPowerPcBuildingBlock` | `BcjPowerPcBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjRiscVBuildingBlock` - -Exposes the RISC-V BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjRiscVBuildingBlock` | `BcjRiscVBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjSparcBuildingBlock` - -Exposes the SPARC BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjSparcBuildingBlock` | `BcjSparcBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BcjX86BuildingBlock` - -Exposes the x86 BCJ filter as a building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcjX86BuildingBlock` | `BcjX86BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `BurrowsWheelerTransform` - -Burrows-Wheeler Transform for data preprocessing before compression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Forward` | `static ValueTuple Forward(ReadOnlySpan data)` | Performs the forward BWT on the input data. Returns the transformed data and the index of the original string in the sorted rotations. | -| `Inverse` | `static byte[] Inverse(ReadOnlySpan data, int originalIndex)` | Performs the inverse BWT to recover the original data. | - -#### `BwtBuildingBlock` - -Exposes the Burrows-Wheeler Transform as a benchmarkable building block. Prepends a 4-byte LE original index to the transformed data. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BwtBuildingBlock` | `BwtBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DeltaBuildingBlock` - -Exposes the Delta filter as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeltaBuildingBlock` | `DeltaBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DeltaFilter` - -Delta filter for data preprocessing. Encodes each byte as the difference from the byte at a fixed distance behind it, which is effective for data with local correlations (e.g., audio samples, sensor data). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data, int distance = 1)` | Decodes delta-encoded data back to the original. Each output byte is the sum of the encoded byte and the already-decoded byte `distance` positions earlier. The first `distance` bytes are copied unchanged. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, int distance = 1)` | Encodes data using the delta filter. Each output byte is the difference between the input byte and the input byte `distance` positions earlier. The first `distance` bytes are copied unchanged. | - -#### `DeltaRleBuildingBlock` - -Exposes Delta + RLE (see `DeltaRleEncoding`) as a benchmarkable building block: the Delta filter followed by run-length encoding of the delta stream. Distinct from the pure filter exposed by `DeltaBuildingBlock` (id `BB_Delta`), which never changes the data length — this variant actually compresses repetitive data. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeltaRleBuildingBlock` | `DeltaRleBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `DeltaRleEncoding` - -Delta + RLE: the `DeltaFilter` transform (distance 1) followed by a marker-based run-length encoding of the resulting delta stream. Unlike the pure `DeltaFilter`, which never changes the data length, this stage actually compresses — runs of two or more identical delta bytes collapse to a 3-byte (marker, count, value) triplet. This is a different codec from `RunLengthEncoding`: that one always emits unconditional (count, value) pairs, so every non-repeated byte costs two output bytes. Here, non-repeated bytes pass through literally (one output byte), runs of 2-255 identical bytes are encoded as the triplet `(0xFF, count, value)`, and a literal occurrence of the marker byte 0xFF is escaped as the triplet `(0xFF, 1, 0xFF)` so the decoder can never mistake a genuine data byte for the start of a run. This exact scheme (and the composition with delta) mirrors the reference "Delta + RLE" wire format so that the two implementations are byte-for-byte interoperable. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data)` | Decodes Delta+RLE-encoded data back to the original bytes. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data with the Delta filter (distance 1) followed by marker-based run-length encoding of the delta stream. | - -#### `DpcmBuildingBlock` - -Exposes Differential Pulse-Code Modulation as a benchmarkable building block. Stores differences between consecutive samples. The first sample is stored verbatim. This is a reversible transform (not lossy) — it converts correlated signal data into small residuals that compress well with entropy coders. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DpcmBuildingBlock` | `DpcmBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `MoveToFrontTransform` - -Move-to-Front transform for data preprocessing. Converts symbols to their indices in a dynamically reordered alphabet, producing small values for recently-seen symbols. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data)` | Decodes MTF-encoded data back to the original. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data using the Move-to-Front transform. | - -#### `MtfBuildingBlock` - -Exposes the Move-to-Front Transform as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MtfBuildingBlock` | `MtfBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `PackBitsBuildingBlock` - -Exposes Apple PackBits as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackBitsBuildingBlock` | `PackBitsBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `PackBitsEncoding` - -Apple PackBits run-length encoding, as specified in Apple Technical Note TN1023 and adopted by the TIFF 6.0 specification (section 2, "PackBits" compression). The compressed stream is a sequence of control bytes, each interpreted as a signed 8-bit count: 0..127: copy the following (count + 1) bytes literally.-1..-127: repeat the single following byte (1 - count) times.-128: no-op, reserved (skipped). The format is self-terminating — no length header is required since the decoder simply consumes control bytes until the input is exhausted. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data)` | Decodes PackBits-encoded data back to the original bytes. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data using Apple PackBits run-length encoding. | - -#### `RleBuildingBlock` - -Exposes Run-Length Encoding as a benchmarkable building block. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RleBuildingBlock` | `RleBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `RunLengthEncoding` - -Run-Length Encoding (RLE) transform. Encodes runs of identical bytes as (count, value) pairs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(ReadOnlySpan data)` | Decodes RLE-encoded data back to the original. Input format: repeated pairs of (count, value) where count is 1-255. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | Encodes data using run-length encoding. Output format: repeated pairs of (count, value) where count is 1-255. Uses SIMD-accelerated run scanning when available. | - -### Namespace `Compression.Registry` - -[`AlgorithmFamily`](#algorithmfamily) · [`ArchiveEntryInfo`](#archiveentryinfo) · [`ArchiveInputInfo`](#archiveinputinfo) · [`ArchiveShrinker`](#archiveshrinker) · [`AudioPseudoArchive`](#audiopseudoarchive) · [`AudioPseudoArchive.Entry`](#audiopseudoarchiveentry) · [`BuildingBlockRegistry`](#buildingblockregistry) · [`CompoundTarDescriptor`](#compoundtardescriptor) · [`DefragBlockClass`](#defragblockclass) · [`DefragBlockInfo`](#defragblockinfo) · [`DefragBlockKind`](#defragblockkind) · [`DefragContentGuard`](#defragcontentguard) · [`DefragMode`](#defragmode) · [`DefragOptions`](#defragoptions) · [`DefragProgressEvent`](#defragprogressevent) · [`DefragRebuilder`](#defragrebuilder) · [`EntropyDetector`](#entropydetector) · [`FatDirStamp`](#fatdirstamp) · [`FilesystemSchemaPresets`](#filesystemschemapresets) · [`FormatCapabilities`](#formatcapabilities) · [`FormatCategory`](#formatcategory) · [`FormatCreateOptions`](#formatcreateoptions) · [`FormatHealth`](#formathealth) · [`FormatHelpers`](#formathelpers) · [`FormatMethodInfo`](#formatmethodinfo) · [`FormatOptionDescriptor`](#formatoptiondescriptor) · [`FormatOptionKind`](#formatoptionkind) · [`FormatRegistry`](#formatregistry) · [`IArchiveCreatable`](#iarchivecreatable) · [`IArchiveDefragmentable`](#iarchivedefragmentable) · [`IArchiveFormatOperations`](#iarchiveformatoperations) · [`IArchiveInMemoryExtract`](#iarchiveinmemoryextract) · [`IArchiveLayoutMap`](#iarchivelayoutmap) · [`IArchiveModifiable`](#iarchivemodifiable) · [`IArchiveShrinkable`](#iarchiveshrinkable) · [`IArchiveWriteConstraints`](#iarchivewriteconstraints) · [`IAsyncArchiveOperations`](#iasyncarchiveoperations) · [`IBuildingBlock`](#ibuildingblock) · [`IFileInternalChunkMover`](#ifileinternalchunkmover) · [`IFileInternalLayoutMap`](#ifileinternallayoutmap) · [`IFilesystemBlockMover`](#ifilesystemblockmover) · [`IFilesystemExtentMap`](#ifilesystemextentmap) · [`IFilesystemMetadataMover`](#ifilesystemmetadatamover) · [`IFormatDescriptor`](#iformatdescriptor) · [`IFormatOptionsSchema`](#iformatoptionsschema) · [`IFormatValidator`](#iformatvalidator) · [`ILayoutOptimizable`](#ilayoutoptimizable) · [`IPartitionEditable`](#ipartitioneditable) · [`IStreamFormatOperations`](#istreamformatoperations) · [`IWipeEmpty`](#iwipeempty) · [`InnerFsDetector`](#innerfsdetector) · [`IssueSeverity`](#issueseverity) · [`LayoutAnalysis`](#layoutanalysis) · [`LayoutPatch`](#layoutpatch) · [`LayoutProfile`](#layoutprofile) · [`LayoutRebuildOptions`](#layoutrebuildoptions) · [`LayoutReclaim`](#layoutreclaim) · [`MagicSignature`](#magicsignature) · [`MediaProfile`](#mediaprofile) · [`MediaProfileLookup`](#mediaprofilelookup) · [`MetadataPlacementProfile`](#metadataplacementprofile) · [`MetadataPlacementRule`](#metadataplacementrule) · [`MetadataZone`](#metadatazone) · [`MethodNameParser`](#methodnameparser) · [`ModifyRebuilder`](#modifyrebuilder) · [`PlacementZone`](#placementzone) · [`RebuildVerb`](#rebuildverb) · [`SymlinkResolver`](#symlinkresolver) · [`UnusedSpaceWiper`](#unusedspacewiper) · [`ValidationIssue`](#validationissue) · [`ValidationLevel`](#validationlevel) · [`ValidationResult`](#validationresult) - -#### `AlgorithmFamily` - -Classification of a compression algorithm's family for grouping and display. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Other` | `0` | Unclassified or other. | -| `Dictionary` | `1` | LZ dictionary-based compression (LZ77, LZ78, LZW, LZSS, etc.). | -| `Entropy` | `2` | Entropy coding (Huffman, Arithmetic, FSE, Golomb, Range coding, etc.). | -| `Transform` | `3` | Data transforms (BWT, MTF, RLE, Delta, PackBits). | -| `ContextMixing` | `4` | Context mixing and statistical modeling (PAQ8, cmix, MCM, PPM, CTW, BCM, BSC). | -| `Classic` | `5` | Classic/legacy algorithms (Bzip2, SZDD, PowerPacker, RNC, etc.). | -| `Encoding` | `6` | Binary-to-text and container encodings (UuEncoding, YEnc, BinHex, MacBinary). | -| `Archive` | `7` | Archive and container formats (Zip, Tar, 7z, RAR, etc.). | - -#### `ArchiveEntryInfo` - -Normalized archive entry metadata returned by format descriptors. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArchiveEntryInfo` | `ArchiveEntryInfo(int Index, string Name, long OriginalSize, long CompressedSize, string Method, bool IsDirectory, bool IsEncrypted, DateTime? LastModified, string Kind = null, bool IsSymlink = false, string LinkTarget = null, long? TargetSize = null)` | Normalized archive entry metadata returned by format descriptors. | -| `CompressedSize` | `long CompressedSize { get; init; }` | The entry's stored/compressed size, or -1 when unknown. | -| `Index` | `int Index { get; init; }` | Zero-based position of the entry in the listing. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | True when the entry is a directory. | -| `IsEncrypted` | `bool IsEncrypted { get; init; }` | True when the entry's data is encrypted. | -| `IsSymlink` | `bool IsSymlink { get; init; }` | True when the entry is a symbolic link (or NTFS junction / reparse-point link). | -| `Kind` | `string Kind { get; init; }` | Optional taxonomy label (container/stream/track/channel/tag). | -| `LastModified` | `DateTime? LastModified { get; init; }` | The entry's last-modified timestamp, when known. | -| `LinkTarget` | `string LinkTarget { get; init; }` | The raw stored link target path, or null when the entry is not a link. | -| `Method` | `string Method { get; init; }` | The compression/storage method label. | -| `Name` | `string Name { get; init; }` | Full slash-separated path of the entry within the archive. | -| `OriginalSize` | `long OriginalSize { get; init; }` | The entry's own uncompressed on-disk size. For a symbolic link this is the byte length of the stored target path (the on-disk truth), NOT the size of whatever the link points at — see `TargetSize` for the resolved target size. | -| `TargetSize` | `long? TargetSize { get; init; }` | The size of the file the link ultimately resolves to, when it points at a regular file within the same filesystem listing; null when unresolved (absolute target, target outside the listing, a directory target, or a dangling/cyclic link). Filled by `SymlinkResolver`. | - -#### `ArchiveInputInfo` - -Describes a single input file/directory for archive creation. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArchiveInputInfo` | `ArchiveInputInfo(string FullPath, string ArchiveName, bool IsDirectory, byte[] InMemoryContent = null)` | Describes a single input file/directory for archive creation. | -| `ArchiveName` | `string ArchiveName { get; init; }` | | -| `FullPath` | `string FullPath { get; init; }` | | -| `InMemoryContent` | `byte[] InMemoryContent { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `FromFile` | `static ArchiveInputInfo FromFile(FileInfo file, string archiveName = null)` | Creates an on-disk input from a `FileInfo`. Content is read lazily from the file via `ReadContent`; the archive name defaults to the file's leaf name. | -| `InMemory` | `static ArchiveInputInfo InMemory(string archiveName, ReadOnlySpan content)` | Creates an in-memory input from a byte span (copied into the input, so the caller's buffer may be reused/stack-allocated). | -| `InMemory` | `static ArchiveInputInfo InMemory(string archiveName, Stream content)` | Creates an in-memory input by reading `content` fully into memory. Reads from the stream's current position to its end. | -| `InMemory` | `static ArchiveInputInfo InMemory(string archiveName, byte[] content)` | Creates an in-memory input whose content comes from `content` rather than a file on disk. | -| `ReadContent` | `byte[] ReadContent()` | Returns the input's bytes: the in-memory content when present, otherwise the file at `FullPath`. Descriptors should call this instead of `File.ReadAllBytes(FullPath)` so they transparently support in-memory (temp-free) creation and conversion. | - -#### `ArchiveShrinker` - -Generic shrink driver for any archive whose descriptor implements `IArchiveCreatable`. Lists the archive's entries, extracts them to memory, and re-creates a fresh archive into the output stream using the smallest canonical size that fits (from `CanonicalSizes`). Works as the default `Shrink` implementation for most R/W filesystems: the "rebuild via WORM" pattern implicitly defragments as a side effect. Format-specific shrinkers can override for efficiency. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChooseTargetSize` | `static long ChooseTargetSize(IReadOnlyList canonicalSizes, long payloadBytes)` | Smallest size in `canonicalSizes` that is >= `payloadBytes`. If no size is large enough, returns the largest available. | -| `ShrinkViaRebuild` | `static void ShrinkViaRebuild(Stream input, Stream output, IArchiveFormatOperations ops, IArchiveCreatable creator, IReadOnlyList canonicalSizes)` | Rebuilds `input` into `output`, choosing the smallest size from `canonicalSizes` that still holds the payload. | - -#### `AudioPseudoArchive` - -Shared plumbing for audio containers surfaced as pseudo-archives. The model separates the CONTAINER from the DATA it carries: the pseudo-archive is the container format itself, and every listed entry is a pseudo-file of carried data. Kinds encode that distinction — `Container` — the byte-exact original container (`FULL.`); round-trips the file unchanged.`Stream` — a carried elementary bitstream (e.g. an Ogg logical stream's packets) still in its coded form.`Track` — a carried audio/video track in multi-track containers, or one rendered subtune of a multi-song chiptune.`Channel` — one decoded speaker as a playable mono PCM WAV (named per `Codec.Pcm.ChannelLayout`, mono through 22.2 and beyond).`Tag` — carried metadata (comments, ID3, bext, …). A descriptor builds the `Entry` list (the format-specific part) and delegates listing, on-disk extraction and single-entry streaming here. Eager vs. lazy entries. An entry's payload may be supplied eagerly as a `Byte`[] (the common case for already-parsed blobs) or lazily through a producing factory plus a declared byte size (for expensive renders such as emulated chiptune subtunes). For a lazy entry the declared size is exact and deterministic — a render's WAV byte count is fully predictable — so listing reports it without ever invoking the factory; the factory runs only when that specific entry is extracted, and its result is cached so a repeat extraction does not re-render. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtractEntry` | `static void ExtractEntry(IReadOnlyList entries, string entryName, Stream output)` | Streams a single named entry to `output`, materialising only the requested entry. | -| `Extract` | `static void Extract(IReadOnlyList entries, string outputDir, string[] files)` | Writes the entries to `outputDir`, honouring an optional name filter. Only the entries actually written are materialised. | -| `List` | `static List List(IReadOnlyList entries)` | Projects built entries into `ArchiveEntryInfo` rows for listing. Lazy entries report their `DeclaredSize` without being materialised, so listing stays fast regardless of how expensive a render would be. | - -#### `AudioPseudoArchive.Entry` - -One surfaced pseudo-archive entry with its display `Kind` and codec `Method`. The payload is either eager (`Data` set at construction) or lazy (produced on demand by `Factory` with the byte count declared up-front in `DeclaredSize`); see `Lazy`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entry` | `Entry(string Name, string Kind, byte[] Data, string Method = "stored")` | Builds an eager entry whose payload is already materialised. This is the long-standing entry shape relied on by the bulk of the audio descriptors and must keep compiling unchanged. | -| `DeclaredSize` | `long DeclaredSize { get; }` | The declared byte size — the materialised payload length for an eager entry, or the producer's promised output length for a lazy one (no factory invocation). | -| `IsLazy` | `bool IsLazy { get; }` | True for a lazy entry whose payload has not yet been produced (becomes false once the factory has run and the result is cached). | -| `Kind` | `string Kind { get; }` | The display kind (Container/Stream/Track/Channel/Tag). | -| `Method` | `string Method { get; }` | The codec/method label reported in listings. | -| `Name` | `string Name { get; }` | The display name (path-like; may contain `/` separators). | -| `Lazy` | `static Entry Lazy(string name, string kind, Func factory, long declaredSize, string method = "stored")` | Builds a lazy entry: `factory` produces the payload only when the entry is extracted, and `declaredSize` is the exact byte count the factory will yield (used for listing without invoking the factory). The produced bytes are cached on first materialisation so a second extraction reuses them. | -| `Materialize` | `byte[] Materialize()` | Returns the payload, invoking and caching the factory on first access for a lazy entry. | - -#### `BuildingBlockRegistry` - -Central registry for compression building blocks (algorithm primitives). Populated at startup via source-generated code, similar to `FormatRegistry`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `All` | `static IReadOnlyList All { get; }` | All registered building blocks. | -| `GetById` | `static IBuildingBlock GetById(string id)` | Look up a building block by its unique ID. | -| `Register` | `static void Register(IBuildingBlock block)` | Register a building block. | - -#### `CompoundTarDescriptor` - -Auto-generated descriptor for compound tar formats (tar.gz, tar.bz2, etc.). Wraps tar archive operations with a stream compression layer via the registry. - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`, `IFormatOptionsSchema`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompoundTarDescriptor` | `CompoundTarDescriptor(string id, string displayName, string streamFormatId, string defaultExtension, IReadOnlyList compoundExtensions)` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Inherits the inner TAR descriptor's schema and adds a `CompressionLevel` knob for the wrapping stream compressor (gzip / bzip2 / xz / zstd / etc.). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry` so the per-entry isolation contract is enforced uniformly across every compound tar variant. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry by first decompressing the outer stream (gzip / bzip2 / xz / zstd / etc.) and delegating to the inner TAR descriptor's own bounded `OpenEntry`. The decompressed TAR isn't seekable in general, so we materialise it into a `MemoryStream` once and let TAR's positional decoder produce the per-entry bounded view over that buffer. The returned stream is bounded to the inner entry's logical size — any block padding past the entry is unreachable. | - -#### `DefragBlockClass` - -Heuristic classification of a file's "thermal" zone based on its modification time. Drives layout placement: hot at start, normal in the middle, frozen near the end. Used by the live-progress block map for tile coloring. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Hot` | `0` | File modified recently (top quartile) — placed near start. | -| `Normal` | `1` | File modified normally — placed in the middle. | -| `Cold` | `2` | File modified a while ago — placed near end. | -| `Frozen` | `3` | File hasn't been touched in a long time (bottom quartile) — placed at end. | -| `Directory` | `4` | Directory metadata (folder contents, B-tree dir node, etc.) — rendered gold to make placement visible. | - -#### `DefragBlockInfo` - -One contiguous region of an image's address space, as seen by the live-progress block map. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragBlockInfo` | `DefragBlockInfo(long Offset, long Length, DefragBlockKind Kind, string FileName = null, DefragBlockClass? Classification = null)` | One contiguous region of an image's address space, as seen by the live-progress block map. | -| `Classification` | `DefragBlockClass? Classification { get; init; }` | | -| `FileName` | `string FileName { get; init; }` | | -| `Kind` | `DefragBlockKind Kind { get; init; }` | | -| `Length` | `long Length { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | - -#### `DefragBlockKind` - -What kind of bytes a contiguous region holds. Used by the live-progress block map to color-code regions as defrag proceeds. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Free` | `0` | Free space — not allocated to any file. | -| `Used` | `1` | Allocated to a file (see `FileName`). | -| `Bad` | `2` | Marked bad / quarantined (FAT-style "BAD" cluster, or post-fsck flag). | -| `MetadataReserved` | `3` | Reserved for filesystem metadata (boot sectors, superblock, MFT, FAT, bitmap, root directory). | -| `InProgress` | `4` | Currently being read or written by the in-progress defrag operation. | - -#### `DefragContentGuard` - -Runs an in-place defragmentation and keeps its result only if every file still reads back byte for byte; otherwise the image is restored and rebuilt. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RunOrRebuild` | `static void RunOrRebuild(Stream archive, Func> readContents, Action inPlace, Action rebuild)` | Snapshots `archive`, runs `inPlace`, and verifies the contents. On any mismatch — or any exception — the snapshot is restored and `rebuild` runs instead. | - -#### `DefragMode` - -Defragmentation strategies for `Defragment`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `ConsolidateAtStart` | `0` | Pack every live extent contiguously starting at the image's data origin. Free space ends up after the last extent. The default mode and the closest match to traditional "defrag" tools. | -| `ConsolidateAtEnd` | `1` | Pack every live extent contiguously at the end of the image, leaving free space at the start (after metadata). Useful when a bootloader / installer / preallocated header expects to land in low offsets. | -| `FillHolesLazy` | `2` | Lazy compaction: each existing hole is filled with a single tail extent that fits, in best-fit order. Moves the minimum number of bytes but doesn't guarantee a contiguous final layout. Use when only a few small files were removed from a huge image. | -| `CarveHole` | `3` | Carve a contiguous free region of `HoleSize` bytes at `HoleAt`. Live extents intersecting the target region are relocated to the first available post-region free slot (or appended to the end of the image if no existing free slot fits). | - -#### `DefragOptions` - -Inputs to `Defragment`. `Mode` selects the strategy; the rest are mode-specific knobs that default to "do the obvious thing" for the chosen mode. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragOptions` | `DefragOptions()` | | -| `Alignment` | `long Alignment { get; init; }` | Round each target offset up to this byte alignment (1 for byte-tight, 2048 for ISO 9660 sectors, 512 for FAT12/16, …). Default: 1. | -| `HoleAt` | `long HoleAt { get; init; }` | Byte offset where the carved hole should start. -1 (default) = auto-pick (carve at the end, immediately after the last live extent). Ignored except in `CarveHole`. | -| `HoleSize` | `long HoleSize { get; init; }` | Size in bytes of the hole to carve. Required for `CarveHole`; ignored otherwise. | -| `ImageEnd` | `long ImageEnd { get; init; }` | Byte offset just past the last sector available for live data. -1 = auto-detect from the image's physical size. Required for `ConsolidateAtEnd` — must be set explicitly or auto-detected. | -| `InterleaveStride` | `int InterleaveStride { get; init; }` | Block interleave factor. 1 = contiguous (default), 2 = every-other-block, N = place each file's Kth block at (start + K*stride). Free blocks between the scattered fragments are left available for other files' interleaved blocks, round-robin style. Useful for optimizing sequential read throughput on spinning media (interleave matches rotational latency) and for testing FS robustness with fragmented layouts. Range: 1-256. | -| `LayoutTemplate` | `LayoutTemplate LayoutTemplate { get; init; }` | Optional layout template that overrides `Mode` / `MetadataZonePlacement` with a fine-grained per-zone plan. When set, the planner uses `LayoutTemplateResolver` to assign files to byte ranges; `Mode` is interpreted as the fallback strategy for files outside all zones (per the template's leftover strategy). When `null` (default), the planner uses the classic mode/profile/metadata-zone pipeline. | -| `MetadataPlacement` | `MetadataPlacementProfile MetadataPlacement { get; init; }` | Optional metadata placement profile for file-internal optimizers. When non-null, optimizers that support `IFileInternalChunkMover` use these rules to decide where metadata chunks land relative to the primary data payload. When null, each optimizer uses its format-specific default placement. | -| `MetadataZonePlacement` | `MetadataZone MetadataZonePlacement { get; init; }` | Controls where filesystem metadata and directory extents are placed during defragmentation. Default: `Unchanged` (metadata stays where it is). Only affects planner-driven defragmentation of filesystem images; ignored for archive optimization and file-internal layout. | -| `Mode` | `DefragMode Mode { get; init; }` | Defragmentation strategy. Default: `ConsolidateAtStart`. | -| `OnProgress` | `Action OnProgress { get; init; }` | Optional progress callback. When non-null, the defragmenter emits at least three events: a "scanning" event with the pre-defrag block map, periodic "writing" events with read/write offsets during the rebuild, and a "complete" event with the post-defrag block map. UI consumers can render a live tile chart from these events. | -| `Origin` | `long Origin { get; init; }` | Byte offset of the first sector available for live data (e.g. 16 * 2048 for ISO 9660 to leave the volume descriptor space alone, 0 for raw FAT). Default: 0. | -| `Profile` | `LayoutProfile Profile { get; init; }` | Layout profile for planner-driven defragmentation. Controls whether the defragmenter performs full zone-based rearrangement (`Performance`) or per-file consolidation only (`Quick`). Default: `Performance`. | -| `StagingMemoryBudgetBytes` | `long StagingMemoryBudgetBytes { get; set; }` | Bytes a defragmentation may hold in memory while rearranging a volume that has nowhere of its own to park a run. | - -#### `DefragProgressEvent` - -Snapshot of an image's block layout at a moment in time. Emitted by `Defragment` implementations through DefragOptions.OnProgress at scan start, periodically during writes, and at completion. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragProgressEvent` | `DefragProgressEvent(string Phase, double Fraction, long CurrentReadOffset, long CurrentWriteOffset, long ImageSize, IReadOnlyList BlockMap, string Status = null)` | Snapshot of an image's block layout at a moment in time. Emitted by `Defragment` implementations through DefragOptions.OnProgress at scan start, periodically during writes, and at completion. | -| `BlockMap` | `IReadOnlyList BlockMap { get; init; }` | Block-map snapshot, present at scan start + completion. Null during incremental updates. | -| `CurrentReadOffset` | `long CurrentReadOffset { get; init; }` | Byte offset currently being read; -1 if not reading. | -| `CurrentWriteOffset` | `long CurrentWriteOffset { get; init; }` | Byte offset currently being written; -1 if not writing. | -| `Fraction` | `double Fraction { get; init; }` | 0..1 fraction of work done. -1 = indeterminate. | -| `ImageSize` | `long ImageSize { get; init; }` | Total image size in bytes (helpful for tile binning). | -| `Phase` | `string Phase { get; init; }` | Progress phase identifier ("scanning" / "writing" / "complete" / "error"). | -| `Status` | `string Status { get; init; }` | Optional human-readable status (e.g. "moving extent 23 of 87"). | - -#### `DefragRebuilder` - -Generic rebuild-based defragmentor for filesystems whose writer always emits a contiguous start-packed layout. Dispatches the four `DefragMode` values onto a read-extract-rebuild path with mode-specific file ordering or capacity validation. Per-filesystem code provides two delegates — the entry extractor (reads from the existing image) and the image builder (writes a fresh image) — and gets all four modes for free. The trade-off vs a planner-driven byte-level mutation: this rebuilds the entire image on every Defragment call, so cost is `O(image size)`. For filesystems whose writer is much faster than the planner-driven path would be (small images, simple layouts), or where on-disk pointer-rewriting is too complex to justify, this is the pragmatic option. FAT for instance uses this for now; a planner-based path can replace it later without breaking the public `IArchiveDefragmentable` contract. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RebuildStreaming` | `static void RebuildStreaming(Stream archive, DefragOptions options, Func>> readEntries, Action beginWrite, Action writeEntry, Action finishWrite)` | Streaming variant of `Rebuild` for filesystems that can build their image incrementally — i.e. whose writer exposes a sink-style `Begin / WriteEntry / Finish` protocol rather than a batch `Build()`. Bytes flow per-entry from reader to writer without accumulating the full file list in memory, so multi-GB containers can start the write before the full directory tree has been walked. `ConsolidateAtStart` and `FillHolesLazy` pack in input order and stream straight through. `ConsolidateAtEnd` and `CarveHole` need every size before the first byte is written, so they spill each entry to scratch, sort, and then write — still without ever holding the volume in memory, which is what the buffered `Rebuild` path cannot do above two gigabytes. | -| `Rebuild` | `static void Rebuild(Stream archive, DefragOptions options, Func>> readEntries, Func>, byte[]> buildImage)` | Rebuilds `archive` in place using the supplied reader+writer delegates and the layout strategy in `options`. | - -#### `EntropyDetector` - -Detects incompressible (already compressed, encrypted, or random) data using a chi-square goodness-of-fit test on byte frequency distribution. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IsIncompressible` | `static bool IsIncompressible(byte[] data)` | Returns true if the data appears incompressible (compressed, encrypted, or random). Uses a chi-square test: uniform byte distribution → incompressible. | -| `IsIncompressible` | `static bool IsIncompressible(string filePath)` | Returns true if the file at the given path appears incompressible. Reads only a sample from the file for efficiency. | - -#### `FatDirStamp` - -Small helpers for writing FAT directory metadata (creation/modification timestamp and volume label) into the genuine CVF writers' inner FAT volume. Shared so DoubleSpace/DriveSpace 3/Stacker emit identical, spec-correct dir-entry metadata. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static ValueTuple Encode(DateTime t)` | Encodes a timestamp into the FAT 16-bit (time, date) dir-entry fields. Returns `(0, 0)` for timestamps outside the representable FAT range (before 1980 or after 2107), which DOS treats as "unset". | -| `Parse` | `static DateTime Parse(string iso)` | Parses an ISO-8601 date/time string for a create-option; returns `default(DateTime)` (treated as "unset") when blank or unparsable. | -| `WriteVolumeLabel` | `static void WriteVolumeLabel(byte[] img, int entryOffset, string label)` | Writes an 11-byte volume-label directory entry (attribute 0x08, no cluster, zero size) at `entryOffset`. The label is upper-cased and space-padded/truncated to 11 bytes, matching the FAT short-name field. | - -#### `FilesystemSchemaPresets` - -Reusable `FormatOptionDescriptor` building blocks shared by every filesystem that exposes tunable layout parameters through `IFormatOptionsSchema`. Cluster/block size and volume size are near-universal across cluster-based filesystems, so they live here rather than being re-declared in each descriptor. Filesystem-specific knobs (MFT record size, inode size, FAT type, …) are declared by the individual descriptor. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ClusterSize` | `static FormatOptionDescriptor ClusterSize(string key = "ClusterSize", string displayName = "Cluster size", int min = 512, int max = 65536, string description = null)` | Standard "Auto + power-of-two" cluster/block size dropdown. | -| `FormatSize` | `static string FormatSize(long bytes)` | Formats a byte count as "512 B", "4 KB", "1 MB" (powers of two only). | -| `ImageSize` | `static FormatOptionDescriptor ImageSize(IReadOnlyList sizes, string description = null)` | Standard "Auto (fit to files) + fixed sizes" image-size dropdown. Pass the medium-specific size labels that the descriptor's parser understands. | -| `ParseSize` | `static int ParseSize(string label)` | Parses a size label produced by `FormatSize` back into bytes; "Auto"/unknown → 0. | -| `PowerOfTwoSize` | `static FormatOptionDescriptor PowerOfTwoSize(string key, string displayName, int min, int max, string defaultLabel, string description)` | Generic power-of-two size dropdown for any byte-valued knob (inode size, MFT record, …). | -| `VolumeLabel` | `static FormatOptionDescriptor VolumeLabel(int maxChars = 11)` | Standard volume-label text field. | - -#### `FormatCapabilities` - -Flags describing what operations a format supports. Write capability is a four-level scale: Unsupported — no descriptor exists.Read-Only — `CanList` and/or `CanExtract` only.WORM (Write-Once-Read-Many) — adds `CanCreate`: a fresh archive can be produced from inputs, but existing archives cannot be modified in place.R/W (Modify) — adds `CanModify`: entries can be added, replaced, or removed in an existing archive without full rewrite. Most archive formats stop at WORM; true in-place modification is rare because compressed archive containers don't generally support entry mutation without a full rebuild. Honesty rule — rebuild-backed modification is WORM, not R/W. A format may implement `IArchiveModifiable` purely to make the add / remove / purge verbs work, backing them with the verified extract → re-create rebuild (the default `IArchiveModifiable` members, or `ModifyRebuilder` / `RebuildVerb`). That is a full rewrite of the container, so such a format advertises `CanCreate` only and must not set `CanModify` — the verb still runs, but no in-place R/W is claimed. `CanModify` is reserved for formats with a genuine in-place writer that edits the existing container (e.g. ZIP/TAR central-directory edits, FAT/NTFS/ext block writes, byte-identity append). `Compression.Tests.Operations.WriteCapabilityHonestyTests` enforces this for every claimant. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | | -| `CanList` | `1` | | -| `CanExtract` | `2` | | -| `CanCreate` | `4` | WORM: can produce a fresh archive from inputs (no in-place modification). | -| `CanTest` | `8` | | -| `SupportsPassword` | `16` | | -| `SupportsMultipleEntries` | `32` | | -| `SupportsDirectories` | `64` | | -| `SupportsOptimize` | `256` | | -| `CanCompoundWithTar` | `512` | | -| `CanModify` | `1024` | R/W: can modify an existing archive (add/replace/remove entries) without full rewrite. Implies `CanCreate`. | - -#### `FormatCategory` - -Classifies a format by its primary behavior. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Archive` | `0` | Multi-file container (ZIP, TAR, 7z, etc.). | -| `Stream` | `1` | Single-stream compressor (Gzip, Bzip2, Xz, etc.). | -| `Wrapper` | `2` | Encoding wrapper (MacBinary, BinHex). | -| `CompoundTar` | `3` | Auto-generated tar + stream combination (tar.gz, tar.bz2, etc.). | -| `DetectionOnly` | `4` | Recognized by signature only, no operations (ISO, UDF). | -| `Audio` | `5` | Audio container surfaced as an archive of tracks/channels/tags (FLAC, WAV, MP3, OGG). | -| `Video` | `6` | Video container surfaced as an archive of demuxed tracks + attachments (MKV, MP4). | -| `Image` | `7` | Image container surfaced as an archive of the full image + per-plane pixel data (PNG, JPEG). | - -#### `FormatCreateOptions` - -Options for archive/stream creation, passed from the orchestration layer to format descriptors. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FormatCreateOptions` | `FormatCreateOptions()` | | -| `DictSize` | `long DictSize { get; init; }` | Dictionary size in bytes, or 0 for format default. | -| `EncryptFilenames` | `bool EncryptFilenames { get; init; }` | When true, encrypt file names/headers. | -| `EncryptionMethod` | `string EncryptionMethod { get; init; }` | Encryption method override (e.g. "aes256", "zipcrypto"). | -| `ForceCompress` | `bool ForceCompress { get; init; }` | Whether to compress all files regardless of entropy detection. | -| `FormatSpecific` | `IReadOnlyDictionary FormatSpecific { get; init; }` | Format-specific tunable knobs collected from a `IFormatOptionsSchema`. Keys come from `Key`; values are in canonical string form (the format's writer parses them per its schema). Writers should call `GetOption` or `GetOptionInt` rather than reading the dict directly, so a missing entry falls back to the schema default. | -| `IncompressiblePaths` | `HashSet IncompressiblePaths { get; init; }` | Set of file paths detected as incompressible (null = not computed). | -| `Level` | `int? Level { get; init; }` | Compression level (0-9), or null for format default. | -| `MethodName` | `string MethodName { get; init; }` | Compression method name (e.g. "deflate", "lzma"). | -| `Optimize` | `bool Optimize { get; init; }` | Whether "+" optimization was requested. | -| `Password` | `string Password { get; init; }` | Encryption password. | -| `SolidSize` | `long SolidSize { get; init; }` | Maximum solid block size in bytes. | -| `Threads` | `int Threads { get; init; }` | Number of parallel threads. | -| `WordSize` | `int? WordSize { get; init; }` | Word size / fast bytes, or null for format default. | -| `GetOptionBool` | `bool GetOptionBool(string key, bool fallback)` | Reads a format-specific boolean option. Accepts "true"/"false"/"1"/"0" (case-insensitive). | -| `GetOptionInt` | `int GetOptionInt(string key, int fallback)` | Reads a format-specific integer option. Returns `fallback` if absent or unparsable. | -| `GetOption` | `string GetOption(string key, string fallback)` | Reads a format-specific string option, returning `fallback` if absent. | -| `HasOption` | `bool HasOption(string key)` | True when the caller explicitly supplied `key` (with a non-empty value). Writers use this to distinguish "caller pinned a size" from "use the format default / auto-optimise" — an unset size must leave the auto-selection path free, while a pinned size must be honoured byte-for-byte. | - -#### `FormatHealth` - -Describes the structural/integrity health of a detected format instance. Orthogonal to identification confidence — a file can be confidently identified as ZIP (high confidence) but have broken entries (Damaged health). - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Perfect` | `0` | All validation checks pass, checksums verified, fully extractable. | -| `Good` | `1` | Structure valid, minor non-critical issues (e.g. extra trailing data). | -| `Degraded` | `2` | Mostly valid but some entries broken, unknown methods, or minor corruption. | -| `Damaged` | `3` | Significant damage: premature EOF, corrupted sections, but partially readable. | -| `Uncertain` | `4` | Identification uncertain — magic matches but structure doesn't validate. | -| `Unknown` | `5` | Cannot determine health (validation not available or not attempted). | - -#### `FormatHelpers` - -Shared utility methods for format descriptors (path sanitization, filtering, etc.). - -| Member | Signature | Summary | -| --- | --- | --- | -| `CreateEntryFile` | `static FileStream CreateEntryFile(string baseDir, string entryName)` | Opens the destination file for `entryName` under `baseDir`, applying the same traversal sanitising as `WriteFile`. Lets a caller stream an entry straight to disk instead of materialising it, which an entry larger than a byte[] requires. | -| `FilesOnly` | `static IEnumerable> FilesOnly(IReadOnlyList inputs)` | Returns only file entries (non-directories) with their data, preserving paths. | -| `FlatFiles` | `static IEnumerable> FlatFiles(IReadOnlyList inputs)` | Flattens all entries to root level (filename only) with their data. For formats without path support. | -| `MatchesFilter` | `static bool MatchesFilter(string name, string[] filters)` | Returns true if `name` matches any of the `filters` by exact name, trailing path segment, or filename-only comparison. | -| `WriteFile` | `static void WriteFile(string baseDir, string entryName, byte[] data)` | Sanitizes an entry name and writes its data to disk under `baseDir`. Prevents path traversal attacks. | - -#### `FormatMethodInfo` - -Describes a compression method available within a format. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FormatMethodInfo` | `FormatMethodInfo(string Name, string DisplayName, bool SupportsOptimize = false)` | Describes a compression method available within a format. | -| `DisplayName` | `string DisplayName { get; init; }` | Human-readable name (e.g. "Deflate", "LZMA"). | -| `Name` | `string Name { get; init; }` | Internal method name (e.g. "deflate", "lzma"). | -| `SupportsOptimize` | `bool SupportsOptimize { get; init; }` | Whether "method+" optimization is available. | - -#### `FormatOptionDescriptor` - -Describes one tunable knob. The dialog / CLI uses `DisplayName` for the label, `Description` as hover-tip help, `Default` as the initial value, and `AllowedValues` to constrain the input where applicable. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FormatOptionDescriptor` | `FormatOptionDescriptor(string Key, string DisplayName, FormatOptionKind Kind, string Default, IReadOnlyList AllowedValues = null, string Description = null, string DependsOn = null)` | Describes one tunable knob. The dialog / CLI uses `DisplayName` for the label, `Description` as hover-tip help, `Default` as the initial value, and `AllowedValues` to constrain the input where applicable. | -| `AllowedValues` | `IReadOnlyList AllowedValues { get; init; }` | For `Enum`: mandatory list of allowed values. For `Integer`: optional preset list (renders as dropdown rather than text box). For other kinds: null. | -| `Default` | `string Default { get; init; }` | Initial value, in canonical string form (e.g. "0" for "auto", "Auto" for an enum). | -| `DependsOn` | `string DependsOn { get; init; }` | Optional gate: only show this knob if another knob's current value matches one of these. Format: `"OtherKey=value1\|value2"`. Used for cascading options (e.g. "Journal" only visible when "Version" is ext3/ext4). | -| `Description` | `string Description { get; init; }` | Hover-tip help. | -| `DisplayName` | `string DisplayName { get; init; }` | UI label. | -| `Key` | `string Key { get; init; }` | Stable machine-readable key; used as the `FormatSpecific` dictionary key. Convention: PascalCase. | -| `Kind` | `FormatOptionKind Kind { get; init; }` | How to render + parse. | - -#### `FormatOptionKind` - -How a `FormatOptionDescriptor` renders + parses. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `String` | `0` | Free-form text (e.g. volume label). | -| `Integer` | `1` | Integer (e.g. cluster size in bytes). `AllowedValues` renders as a dropdown of preset sizes. | -| `Boolean` | `2` | Boolean toggle (e.g. "enable journal"). | -| `Enum` | `3` | One of a fixed enumerated set (e.g. FAT12 / FAT16 / FAT32). `AllowedValues` is mandatory. | - -#### `FormatRegistry` - -Central registry of all format descriptors. Populated at startup via `Register` calls (typically from source-generated code), then finalized with `Initialize`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `All` | `static IReadOnlyList All { get; }` | All registered descriptors. | -| `GetArchiveOps` | `static IArchiveFormatOperations GetArchiveOps(string id)` | Get archive operations for a format ID, or null if not an archive format. | -| `GetAsyncArchiveOps` | `static IAsyncArchiveOperations GetAsyncArchiveOps(string id)` | Get async archive operations for a format ID, or null if the format doesn't support async listing. | -| `GetByCategory` | `static IEnumerable GetByCategory(FormatCategory category)` | Get all descriptors in a given category. | -| `GetByExtension` | `static IFormatDescriptor GetByExtension(string path)` | Look up a descriptor by file path/extension. Checks compound extensions first (longest match). | -| `GetById` | `static IFormatDescriptor GetById(string id)` | Look up a descriptor by its unique ID. | -| `GetStreamOps` | `static IStreamFormatOperations GetStreamOps(string id)` | Get stream operations for a format ID, or null if not a stream format. | -| `Initialize` | `static void Initialize()` | Finalize the registry by building lookup tables. Safe to call multiple times. Call this after all `Register` calls are complete. | -| `Register` | `static void Register(IFormatDescriptor descriptor)` | Register a format descriptor. Called by generated code and for compound tar auto-generation. Must be called before `Initialize`. | - -#### `IArchiveCreatable` - -Opt-in capability: the descriptor can produce a fresh archive from a list of inputs (WORM). Descriptors that do not implement this interface cannot be created from scratch. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CreateFromStreams` | `void CreateFromStreams(Stream target, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming variant of `Create`: `inputs` is an enumerable of (name, size, openStream) tuples. Writers that override this method can use the pre-known sizes to plan layout/geometry in a first pass, then write the target stream and copy each entry's bytes via 64 KB chunks in a second pass — never holding an entry's bytes in RAM beyond the chunk buffer. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Produces a fresh archive at `output` containing `inputs`. Existing archive contents (if any) at `output` are overwritten. | - -#### `IArchiveDefragmentable` - -Opt-in capability: the descriptor can rewrite an archive in place so that every file occupies a contiguous cluster run, optionally with a chosen layout strategy (consolidate at start / end, lazy hole-fill, carve a free region). Complements the allocator's automatic fast-defrag (which fires only when a pending allocation can't find a contiguous hole); this is the user-initiated full pass. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Defragment` | `void Defragment(Stream archive)` | Rebuilds the archive content in place so every file is contiguous. Outer byte size is preserved. Free space is consolidated at the end. Default implementation: any descriptor that also implements `IArchiveFormatOperations` + `IArchiveCreatable` gets defragmentation for free — a verified in-place extract → re-create rebuild via `RebuildInPlace` (the rebuild-via-WORM pattern inherently lays every file out contiguously) that refuses to commit a lossy result. Formats with a true in-place block mover override this for efficiency and full mode support. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rewrites the archive content according to `options`. Default implementation forwards to `Defragment` for `ConsolidateAtStart` and throws for every other mode — implementers should override to support all modes their on-disk format permits. | - -#### `IArchiveFormatOperations` - -The base capability every archive descriptor implements: list entries and extract them to a directory. All other archive capabilities (create, modify, in-memory extract, defragment, shrink, input constraints) are separate opt-in interfaces so callers can discover them at the type level. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Extracts a single entry to a byte array without writing to disk. The default implementation now routes through `OpenEntry` so the bounded streaming contract is enforced even when callers ask for a buffered result. Descriptors that have a more efficient native byte-array path (e.g. a reader that already materialises the whole entry) can still override. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | Extract entries from the archive to an output directory. | -| `List` | `List List(Stream stream, string password)` | List all entries in the archive. | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a read-only `Stream` bounded to that entry's logical bytes — physically incapable of reading slack space, adjacent entries, padding/alignment fillers, or header/metadata regions. This is the canonical per-entry isolation primitive used by streaming conversion pipelines. | - -#### `IArchiveInMemoryExtract` - -Opt-in capability: the descriptor can extract a single named entry straight to a `Stream` without materialising it to disk. Used by the recursive-descent driver to avoid per-layer temp-dir roundtrips. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | Writes the bytes of `entryName` (as named by `List`) into `output`. | - -#### `IArchiveLayoutMap` - -Opt-in capability: the descriptor can enumerate the real byte-level layout of an archive — every entry's header, compressed payload, and inter-entry gaps at their actual offsets. Parallel to `IFilesystemExtentMap` but for archive formats (ZIP, 7z, TAR, LZH, ARJ, etc.). Drives the Defragment/Optimize window block-map preview so the user sees the real archive layout before pressing "Optimize". - -| Member | Signature | Summary | -| --- | --- | --- | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | Enumerates the actual byte layout of `archive`. Coverage may be sparse; callers fill the gaps with `Free`. The stream's position may be modified during enumeration but the caller owns the lifetime — implementations must not dispose `archive`. | - -#### `IArchiveModifiable` - -Opt-in capability: the descriptor exposes add / remove (and thereby the purge verb). Implementing this interface makes the verbs work; it does not by itself entitle the format to advertise `CanModify` (R/W). The default `Add` / `Remove` below — and any override that delegates to `ModifyRebuilder` / `RebuildVerb` — are a verified extract → re-create rebuild, i.e. a full rewrite of the container. A format whose modification is only rebuild-backed is WORM: it advertises `CanCreate` and must NOT advertise `CanModify` (see `FormatCapabilities`). Reserve `CanModify` for a genuine in-place writer that edits the existing bytes (R/W filesystems; central-directory / member edits; byte-identity append). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends or replaces files inside `archive`. On replacement the previous bytes are wiped the same way `Remove` wipes them. Default implementation: any descriptor that also implements `IArchiveFormatOperations` + `IArchiveCreatable` gets add for free — a verified extract → splat-new-files → re-create rebuild via `EditViaRebuild` (the same WORM rebuild that backs the other verbs). Formats with a true in-place writer override for efficiency. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from `archive` and wipes all on-disk traces. Default implementation: a verified extract → drop-named-files → re-create rebuild via `EditViaRebuild`. Passing every entry name (or all files) yields an empty container — i.e. the purge verb. Formats with a true in-place writer override for efficiency and forensic wiping. | - -#### `IArchiveShrinkable` - -Opt-in capability: the descriptor can rebuild an archive into a new output stream, stepping down to the smallest size in `CanonicalSizes` that still holds the current payload. For formats with continuous sizing (most filesystems), `CanonicalSizes` returns just the current image size and shrink tight-packs to exactly that. For fixed-size disk image families (C64 D64/D71/D81; PC 720K/1.44M/2.88M floppies; Amiga ADF), the list walks from largest to smallest standard size. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | Canonical image sizes in bytes, ascending. A 1.44 MB PC floppy descriptor returns `[737280, 1474560, 2949120]`; a filesystem without a disc-size concept returns an empty list (the default), meaning "rebuild tight / auto-fit to content". | -| `ShrinkDefault` | `void ShrinkDefault(Stream input, Stream output)` | The default rebuild-or-copy-through shrink, exposed so a format-specific `Shrink` override (e.g. a genuine in-place shrinker) can fall back to it when the in-place path declines an image. Rebuilds into a buffer and emits the result only when it round-tripped AND is actually smaller; on any rebuild failure it copies the original through unchanged. Shrink is thus total — it never throws or damages the source. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | Rebuilds `input` into `output`, picking the smallest `CanonicalSizes` entry that holds the current content. Default implementation: any descriptor that also implements `IArchiveFormatOperations` + `IArchiveCreatable` (i.e. it can round-trip its own files) gets shrink for free — a verified extract → re-create rebuild via `RebuildToStream` that tight-packs the payload (auto-fit) and refuses to emit a lossy result. Formats with a fixed canonical-size ladder (floppy/disk images) override this to step down standard sizes. | - -#### `IArchiveWriteConstraints` - -Opt-in capability: the descriptor can reject inputs that don't belong in this archive type. Applied by the UI (drag-drop prohibition cursor + tooltip) and the CLI (rejection with non-zero exit) before `Create` or `Add` is called. Descriptors that accept anything (ZIP, TAR, …) simply don't implement this interface. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | One-line human summary shown in UI tooltips on rejection — e.g. `"accepts: metadata.ini, cover.jpg/png, lyrics.txt"` for an MP3 archive. | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | Maximum cumulative size of all inputs the archive can hold, in bytes. Null means no inherent size ceiling (most formats). Fixed-size disk images (C64 D64 = 174848, Amiga ADF = 901120, PC 1.44 MB floppy = 1474560) expose their limit here so the UI can reject drops that would overflow. | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | Minimum total image size the format requires, in bytes. Null (default) means no floor. Filesystem images (UDF ≈ 1 MB, XFS = 16 MB, ReiserFS = 128 MB) advertise their real-world minimum-viable size here so UI can warn before the writer produces a round-tripable but mount-rejected image. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | Evaluates `input` against the descriptor's rules. Returns `false` with a human-readable `reason` when the input is rejected. | - -#### `IAsyncArchiveOperations` - -Optional interface for archive formats that support lazy, asynchronous entry enumeration. Implementations yield entries one at a time, enabling processing of huge archives without materializing the full entry list in memory. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ListEntriesAsync` | `IAsyncEnumerable ListEntriesAsync(Stream stream, string password, CancellationToken ct = null)` | Lazily enumerates archive entries as an async stream. Each entry is yielded as it is discovered, without requiring the full archive to be scanned first. | - -#### `IBuildingBlock` - -A raw compression/decompression building block (algorithm primitive) that can be benchmarked. Unlike `IFormatDescriptor`, building blocks have no file format container — they operate directly on raw byte data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Description` | `string Description { get; }` | Short description of the algorithm. | -| `DisplayName` | `string DisplayName { get; }` | Human-readable display name (e.g. "LZ77", "DEFLATE"). | -| `Family` | `AlgorithmFamily Family { get; }` | Algorithmic family for grouping. | -| `Id` | `string Id { get; }` | Unique identifier (e.g. "Lz77", "Deflate"). | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | Compress raw data and return the compressed bytes. | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | Decompress previously compressed data and return the original bytes. | - -#### `IFileInternalChunkMover` - -Moves chunks within a single file and patches internal offset pointers so the file remains valid. Examples: moving MP4 moov atom before mdat, relocating JPEG EXIF to the front, compacting ID3v2 padding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Optimize` | `void Optimize(Stream file)` | Performs the canonical optimization for the format (e.g., MP4 fast-start, JPEG EXIF-first). The stream must be readable, writable, and seekable. If the file is already in the optimal layout, this is a no-op. | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | Performs optimization with an optional metadata placement profile that controls where metadata chunks land relative to the data payload. The default implementation ignores the profile and delegates to `Optimize`. | - -#### `IFileInternalLayoutMap` - -Exposes the byte-level internal structure of a single file (not an archive or filesystem) so the block-chart can visualize and rearrange its chunks. Examples: JPEG APP markers, MP4 atoms, RIFF chunks, ID3 tags, PNG chunks. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | Enumerates the top-level structural chunks inside `file`. Each chunk becomes a `DefragBlockInfo` with its byte offset and length within the file. The stream's position may be modified during enumeration but the caller owns the lifetime — implementations must not dispose `file`. | - -#### `IFilesystemBlockMover` - -Opt-in capability for filesystems that support true in-place defragmentation via cluster-level moves. Implementing this interface allows the planner-driven defrag path to move extents without rebuilding the entire image. `MoveExtent` performs the raw byte copy from source to destination within the image. `UpdateAllocationAfterMove` patches filesystem metadata (FAT chain entries, directory entry start-cluster, bitmap bits, etc.) so the file remains reachable at its new location. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | Size of one allocation unit — a cluster, a block — in bytes, or zero when the mover does not say. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Whether `UpdateAllocationAfterMove` repoints exactly the run it is told about and leaves the owner's other runs alone. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | Whether this mover copes with a run being held outside the volume while the rest of the layout moves. | -| `SupportsScatteredRelink` | `bool SupportsScatteredRelink { get; }` | Whether this mover can relink an owner's whole allocation in one call. A fragmented file's runs have to become a single chain; `UpdateAllocationAfterMove`, called once per run, can only describe each run as a file of its own — which truncates the file to its last run. A mover that returns false is never asked to move a fragmented owner: the caller falls back to a rebuild instead. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | Copies `length` bytes from `srcOffset` to `dstOffset` within `image`. Optionally zeros the source region after the copy (controlled by `zeroSource`). Caller is responsible for ensuring the destination region is free. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | Patches filesystem metadata after a raw extent move. Walks the allocation structures (FAT chain, directory entries, bitmaps, etc.) to update every reference from the old cluster range to the new one. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length, bool releaseOldSpace)` | Repoints a run the way `UpdateAllocationAfterMove` does, but says whether the space it came from should be released. | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldBlockOffsets, IReadOnlyList newBlockOffsets, IReadOnlySet blocksLiveElsewhere)` | Rewrites `fileName`'s allocation so that it occupies `newBlockOffsets` in that order, having previously occupied `oldBlockOffsets`. Both lists are one entry per allocation block, in the file's own order. | - -#### `IFilesystemExtentMap` - -Opt-in capability: the descriptor (or a partner type) can enumerate the actual on-disk byte layout of a filesystem image — every used cluster chain per file (one `DefragBlockInfo` per contiguous run), every metadata-reserved region (boot sector, FAT, bitmap, superblock, MFT, root directory, inode table, BAM, group descriptor table, etc.), and optionally every free region. Coverage may be sparse — gaps in the returned set are interpreted by the caller as `Free`. The yielded extents don't need to be sorted; the caller is responsible for sorting + gap filling. Implementations must not throw for malformed or partially-walked images — they should yield whatever they can identify and return.Drives the Defragment-window block-map preview so the user sees the real fragmented layout before pressing "Defragment" rather than the post-defrag approximation. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Enumerates the actual on-disk layout of `image`. Coverage may be sparse; callers fill the gaps with `Free`. The stream's position may be modified during enumeration but the caller owns the lifetime — implementations must not dispose `image`. | - -#### `IFilesystemMetadataMover` - -Opt-in capability for filesystems whose own structures — the MFT, an allocation bitmap, an inode table, a root directory — can be relocated rather than only worked around. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RelocatableMetadata` | `IReadOnlySet RelocatableMetadata { get; }` | The metadata regions this filesystem can relocate, named as its extent map reports them. Everything not listed stays where it is. | -| `PrepareMetadataMove` | `void PrepareMetadataMove(Stream image, string metadataName, long oldOffset, long newOffset, long length)` | Gives the filesystem a chance to make the destination safe before the raw bytes are copied there. | -| `UpdateMetadataAfterMove` | `void UpdateMetadataAfterMove(Stream image, string metadataName, long oldOffset, long newOffset, long length, IReadOnlyList> liveRanges = null)` | Repoints whatever locates `metadataName` after its bytes have been copied from `oldOffset` to `newOffset`, and moves the allocation with it. | - -#### `IFormatDescriptor` - -Self-describing metadata for a file format. Each FileFormat.* project provides one implementation of this interface to register itself with the format registry. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Capabilities flags for this format. | -| `Category` | `FormatCategory Category { get; }` | Primary category of this format. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | Compound (multi-dot) extensions this format owns (e.g. [".tar.gz", ".tgz"]). Checked before single extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default file extension including the dot (e.g. ".gz"). | -| `Description` | `string Description { get; }` | Short human-readable description of the algorithm. Defaults to `DisplayName`. | -| `DisplayName` | `string DisplayName { get; }` | Human-readable display name (e.g. "ZIP", "GZIP"). | -| `Extensions` | `IReadOnlyList Extensions { get; }` | All recognized single extensions (e.g. [".gz", ".gzip"]). | -| `Family` | `AlgorithmFamily Family { get; }` | Algorithmic family for grouping and display. Defaults to `Other`. | -| `Id` | `string Id { get; }` | Unique format identifier (e.g. "Zip", "Gzip"). Must match the Format enum name for backward compat. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | Magic byte signatures for detection. | -| `Methods` | `IReadOnlyList Methods { get; }` | Compression methods available for this format. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | For compound tar formats: the ID of the outer stream compression format. Null for non-compound formats. | - -#### `IFormatOptionsSchema` - -Opt-in capability: the descriptor publishes a list of tunable knobs the user can adjust before the format is written. Drives the "Convert Archive" target-options dialog in the UI and the CLI's `--opt key=value` flag. Implementations should return a stable list of `FormatOptionDescriptor`s describing each knob. The dialog / CLI collects user values into `FormatSpecific` keyed by `Key`; the writer reads them back out in `Create()`.Descriptors that don't implement this surface get the default "no extra knobs" experience. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The set of knobs this format exposes. Empty list = no extra options. | - -#### `IFormatValidator` - -Optional interface for format descriptors that can perform deep validation beyond simple magic byte matching. Implementations progressively validate header fields, structural coherence, and data integrity. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | Validate header fields beyond magic bytes: version numbers, flags, field ranges, plausible sizes. Requires only the first few hundred bytes. | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | Verify checksums and/or attempt partial decompression. Most expensive level. | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | Parse the directory/TOC and verify structural coherence: entry counts match, offsets are within bounds, no overlapping entries. Requires seekable stream. | - -#### `ILayoutOptimizable` - -A filesystem descriptor that can analyse and optimise its own layout parameters without loading the full image into memory, enabling seamless operation on images of any size (including multi-TB exFAT or ext4 volumes). In-place patches (volume label, serial number, geometry fields): implemented by seeking to the known superblock/BPB offset and overwriting a handful of bytes. Zero copy; no allocation; works at any scale.Structural changes (cluster size, inode size, FAT type, block size): require a streaming rebuild via `RebuildStreaming`. The source is read sequentially; the target is written sequentially. Peak memory use is bounded by `O(max(FAT-table, directory-tree))`, not by image size. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ReclaimSupport` | `LayoutReclaim ReclaimSupport { get; }` | What this format can reclaim when asked, beyond moving its data about. | -| `AnalyzeLayout` | `LayoutAnalysis AnalyzeLayout(Stream image)` | Reads only the superblock / BPB of `image` to determine the current layout parameters and compute the optimal alternatives. The stream must be readable and seekable but is never fully loaded. Default implementation: returns an honest, no-op analysis that reports the current image size and recommends no change. Formats that can discover their on-disk allocation-unit size cheaply (FAT, ext, …) override this to populate `CurrentUnitSize` and propose an optimal alternative. The generic default never claims a saving it cannot substantiate, so it is always safe to surface. | -| `PatchInPlace` | `void PatchInPlace(Stream image, LayoutPatch patch)` | Applies metadata-only changes (volume label, serial number, geometry CHS fields, etc.) by seeking directly to the relevant superblock offsets. Throws `NotSupportedException` for changes that would require moving data clusters (e.g. cluster-size change) — call `RebuildStreaming` for those. Default implementation: throws `NotSupportedException`. In-place superblock patching is necessarily format-specific (each filesystem keeps its label/serial at a different offset), so the generic mechanism re-applies geometry through the verified rebuild path (`RebuildStreaming`) rather than guessing byte offsets. | -| `RebuildStreaming` | `void RebuildStreaming(Stream source, Stream target, LayoutRebuildOptions options)` | Converts `source` to `target` with the layout parameters in `options`. Reads and writes sequentially — never loads the full source into memory. Suitable for images of any size; typical peak allocation is O(cluster-size + FAT-sector). Default implementation: any descriptor that also implements `IArchiveFormatOperations` + `IArchiveCreatable` gets a layout rebuild for free — the requested geometry is mapped to a format-specific options dictionary (`UnitSize` → `ClusterSize` in bytes, `ImageSize` → `ImageSize`, plus every entry of `Parameters` verbatim, with the explicit parameters winning), then handed to the verified extract → re-create engine `RebuildToStream`, which refuses any lossy round-trip. Descriptors that can stream a true in-place geometry conversion override this. | - -#### `IPartitionEditable` - -Capability marker for archive/disk-container formats whose payload is a raw block-device image (MBR/GPT partitioned) that the user can edit with a partition editor. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | Opens the inner (guest) disk image as a `Stream` suitable for partition-table editing. The returned stream must support reading, writing, and seeking. The caller owns the returned stream and must dispose it; disposing it must not dispose the outer `image` stream. | - -#### `IStreamFormatOperations` - -Operations for single-stream compression formats. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | Compress with maximum/optimal settings. Defaults to `Compress`. | -| `Compress` | `void Compress(Stream input, Stream output)` | Compress the input stream to the output stream. | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | Compress honouring the format-specific tunables in `options` (the keys declared by this format's `IFormatOptionsSchema` — e.g. compression level, dictionary size, lc/lp/pb). Formats that expose a schema override this; the default ignores the options and falls back to `Compress`, so unparameterised formats keep working. | -| `Decompress` | `void Decompress(Stream input, Stream output)` | Decompress the input stream to the output stream. | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | Returns a compression wrapper stream, or null if the format doesn't support wrapping. | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | Returns a decompression wrapper stream, or null if the format doesn't support wrapping. Used for compound tar formats where the tar reader needs to read through the decompressor. | - -#### `IWipeEmpty` - -Opt-in capability: the descriptor can zero-fill all unused bytes in an image or archive — free clusters/sectors, cluster-tip slack, deleted directory entries, padding regions, and dead archive bytes. This is a forensic-cleanliness tool ensuring no deleted file remnants survive. Implementations that don't need format-specific logic can delegate to `Wipe` which works generically with any `IFilesystemExtentMap` or `IArchiveLayoutMap`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all bytes in `image` that are not part of any live file or required metadata. Returns the total number of bytes wiped. | - -#### `InnerFsDetector` - -Detects the filesystem contained within a virtual disk stream by scanning `FormatRegistry` magic signatures against the stream header. Falls back to heuristic BPB checks for FAT (which has no magic signature). Returns the inner descriptor if it implements the required archive operations. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Detect` | `static IFormatDescriptor Detect(Stream virtualDisk)` | Tries to detect the inner filesystem descriptor from a virtual disk stream. Returns the descriptor if one is found and it implements `IArchiveFormatOperations`; otherwise `null`. | - -#### `IssueSeverity` - -Severity of a validation issue. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Info` | `0` | Informational observation (e.g. "uses uncommon compression method"). | -| `Warning` | `1` | Non-critical issue that may indicate partial damage. | -| `Error` | `2` | Critical issue that prevents correct extraction. | - -#### `LayoutAnalysis` - -Result of `AnalyzeLayout`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LayoutAnalysis` | `LayoutAnalysis()` | | -| `CurrentSlackBytes` | `long CurrentSlackBytes { get; init; }` | Total internal slack at the current unit size in bytes. | -| `CurrentUnitSize` | `int CurrentUnitSize { get; init; }` | Current allocation-unit size in bytes (cluster, block, …). | -| `ImageSize` | `long ImageSize { get; init; }` | Total image size in bytes as read from the superblock. | -| `InPlaceChanges` | `IReadOnlyList InPlaceChanges { get; init; }` | Metadata changes that can be applied by `PatchInPlace`. | -| `Notes` | `IReadOnlyList Notes { get; init; }` | Free-form notes from the analyser (warnings, recommendations, etc.). | -| `OptimalSlackBytes` | `long OptimalSlackBytes { get; init; }` | Total internal slack at the optimal unit size in bytes. | -| `OptimalUnitSize` | `int OptimalUnitSize { get; init; }` | Optimal unit size chosen by `Compression.Core.Layout.FilesystemLayoutOptimizer`. | -| `PotentialSavingsBytes` | `long PotentialSavingsBytes { get; }` | Bytes that could be saved by switching to `OptimalUnitSize`. | -| `RequiresRebuild` | `IReadOnlyList RequiresRebuild { get; init; }` | Structural changes that require `RebuildStreaming`. | - -#### `LayoutPatch` - -Metadata fields that `PatchInPlace` can overwrite without touching data clusters. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LayoutPatch` | `LayoutPatch()` | | -| `Extra` | `IReadOnlyDictionary Extra { get; init; }` | Additional filesystem-specific fields keyed by name. | -| `SerialNumber` | `uint? SerialNumber { get; init; }` | New volume serial number. Null = leave unchanged. | -| `VolumeLabel` | `string VolumeLabel { get; init; }` | New volume label. Null = leave unchanged. | - -#### `LayoutProfile` - -High-level layout strategy for planner-driven defragmentation. Complements `DefragMode` (which controls *where* files land) with a *how* dimension (rebuild vs. in-place planning). - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Performance` | `0` | Full zone-based layout: classify files into Hot / Normal / Cold / Frozen zones based on modification time, place Hot at the front and Frozen at the end, largest-first within each zone. Minimises seek latency for frequently-accessed files on rotational media. | -| `Quick` | `1` | Per-file consolidation only: each fragmented file's clusters are made contiguous, but no global rearrangement is performed. Fastest to execute; useful on SSDs or when only a handful of files are fragmented. | -| `Custom` | `2` | Caller supplies sort/group rules via `DefragOptions`. Reserved for future extensibility; currently behaves like `Performance`. | - -#### `LayoutRebuildOptions` - -Target parameters for `RebuildStreaming`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LayoutRebuildOptions` | `LayoutRebuildOptions()` | | -| `DeduplicateWithLinks` | `bool DeduplicateWithLinks { get; init; }` | Store one copy of files that are byte-for-byte identical and point the rest at it, where the filesystem has hard links. | -| `ImageSize` | `long ImageSize { get; init; }` | Target image total size in bytes. 0 = auto-size to fit files. | -| `MakeSparse` | `bool MakeSparse { get; init; }` | Store runs of zeros as holes, where the filesystem can say so. | -| `OnProgress` | `Action OnProgress { get; init; }` | Optional progress callback: (bytesRead, totalBytes). Called after each cluster or metadata region is processed. | -| `Parameters` | `IReadOnlyDictionary Parameters { get; init; }` | Format-specific tunable parameters (same keys as `Key`). Merged with auto-selected values; explicit entries win. | -| `UnitSize` | `int UnitSize { get; init; }` | Target allocation unit size in bytes. 0 = auto-select optimal. | - -#### `LayoutReclaim` - -What a format can be asked to reclaim beyond re-laying its data out. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | Neither holes nor links; a rebuild only moves what is there. | -| `Sparse` | `1` | Runs of zeros can be recorded as absent rather than allocated. | -| `HardLinks` | `2` | Identical files can share one copy under several names. | - -#### `MagicSignature` - -A magic-byte signature for format identification. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MagicSignature` | `MagicSignature(byte[] Bytes, int Offset = 0, double Confidence = 0.9, byte[] Mask = null)` | A magic-byte signature for format identification. | -| `Bytes` | `byte[] Bytes { get; init; }` | The magic bytes to match. | -| `Confidence` | `double Confidence { get; init; }` | Detection confidence (0.0 - 1.0). | -| `Mask` | `byte[] Mask { get; init; }` | Optional bitmask applied before comparison (null = exact match). | -| `Offset` | `int Offset { get; init; }` | Byte offset from the start of the file where the signature appears. | - -#### `MediaProfile` - -Predefined media profiles for disk image resizing. Each profile specifies the canonical byte size of the target medium. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Floppy35Hd` | `0` | 3.5" HD floppy: 1,474,560 bytes (1.44 MB, FAT12). | -| `Floppy35Dd` | `1` | 3.5" DD floppy: 737,280 bytes (720 KB). | -| `Floppy525Hd` | `2` | 5.25" HD floppy: 1,228,800 bytes (1.2 MB). | -| `Floppy525Dd` | `3` | 5.25" DD floppy: 368,640 bytes (360 KB). | -| `Cd` | `4` | CD-ROM: 681,984,000 bytes (650 MB, ISO 9660). | -| `Dvd` | `5` | DVD: 4,700,000,000 bytes (4.7 GB). | -| `BluRay` | `6` | Blu-ray Disc: 25,025,314,816 bytes (25 GB). | - -#### `MediaProfileLookup` - -Maps `MediaProfile` values to their canonical byte sizes and provides lookup from human-readable profile names. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AllProfiles` | `static IReadOnlyList> AllProfiles { get; }` | All known profiles with their names and sizes for display. | -| `GetSize` | `static long GetSize(MediaProfile profile)` | Returns the byte size for the given profile. | -| `TryParse` | `static bool TryParse(string name, out MediaProfile profile)` | Tries to parse a profile name (case-insensitive). Recognized names: `3.5-hd`, `3.5-dd`, `5.25-hd`, `5.25-dd`, `cd`, `dvd`, `bd`. | - -#### `MetadataPlacementProfile` - -A named set of `MetadataPlacementRule`s that controls where metadata chunks are placed during file-internal optimization. Optimizers that accept this profile apply matching rules; chunks not covered by any rule keep their format-specific default placement. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MetadataPlacementProfile` | `MetadataPlacementProfile()` | | -| `DataFirst` | `static MetadataPlacementProfile DataFirst { get; }` | Data payload first, metadata after. Optimizes for streaming playback at the cost of slower metadata access. | -| `Default` | `static MetadataPlacementProfile Default { get; }` | No rules — each optimizer uses its own format-specific default. | -| `MetadataFirst` | `static MetadataPlacementProfile MetadataFirst { get; }` | All metadata chunks placed before the data payload. The optimizer should load metadata first for fastest access. | -| `Name` | `string Name { get; init; }` | Human-readable label for UI display. | -| `Rules` | `IReadOnlyList Rules { get; init; }` | Rules keyed by chunk type. Order is irrelevant; lookup is by type. | -| `GetZone` | `PlacementZone? GetZone(string chunkType)` | Looks up the placement zone for a given chunk type. Returns `null` when no rule matches (caller should fall back to the format-specific default). | - -#### `MetadataPlacementRule` - -Maps a chunk type (e.g. "eXIf", "APP1", "moov", "idx1") to a `PlacementZone`. Used by file-internal optimizers to decide where metadata chunks land relative to the data payload. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MetadataPlacementRule` | `MetadataPlacementRule(string ChunkType, PlacementZone Zone)` | Maps a chunk type (e.g. "eXIf", "APP1", "moov", "idx1") to a `PlacementZone`. Used by file-internal optimizers to decide where metadata chunks land relative to the data payload. | -| `ChunkType` | `string ChunkType { get; init; }` | | -| `Zone` | `PlacementZone Zone { get; init; }` | | - -#### `MetadataZone` - -Controls where filesystem metadata (superblock, FAT, MFT, bitmaps, inode tables) and directory extents land during defragmentation. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Unchanged` | `0` | Don't move metadata — preserve current positions. This is the default. | -| `Front` | `1` | Metadata + directories at lowest offsets (fast outer-track on HDDs, low-address flash advantage). | -| `Back` | `2` | Metadata + directories at highest offsets (reserve front for file data). | -| `Middle` | `3` | Metadata + directories centered in the image (minimize average seek time on platters). | -| `BeforeContent` | `4` | Each directory block placed immediately before its children's data (read-ahead optimization). | - -#### `MethodNameParser` - -Parses a format method name into (base method, plus level). Convention (Zopfli-inspired): a trailing `+` (or repeated `++`, `+++`) on a method id means "spend extra CPU for a better compression ratio". The base method is the longest prefix that does not end with `+`; the plus level is the number of trailing `+` characters that were stripped. Examples: `"deflate"` → `("deflate", 0)``"deflate+"` → `("deflate", 1)` — ~10× effort (e.g. enable lazy matching, deeper search)`"deflate++"` → `("deflate", 2)` — ~100× effort (e.g. full Zopfli)`"stored"` → `("stored", 0)` Writers consult `Item2` (the plus level) to pick: 0 = default fast, 1 = "+", 2+ = "++" and slower variants. Surrounding whitespace is trimmed before parsing. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Parse` | `static ValueTuple Parse(string method)` | Parses `method` into `(BaseMethod, PlusLevel)`. Whitespace is trimmed first; a null or whitespace-only input returns `("", 0)`. A string that is only `+` characters returns `("", n)`. | - -#### `ModifyRebuilder` - -Generic rebuild-based `IArchiveModifiable` dispatch for filesystems whose writer always emits a contiguous start-packed layout. Per-FS code provides two delegates — the entry extractor (reads the existing image) and the image builder (writes a fresh image with the supplied file list) — and gets `Add` and `Remove` for free with the documented `IArchiveModifiable` semantics, including secure-wipe (the rebuild starts from zeroed bytes so removed file data leaves no trace). The trade-off vs a planner-driven byte-level mutation: this rebuilds the entire image on every Add/Remove call, so cost is `O(image size)`. For filesystems whose on-disk pointer-rewriting is too complex to justify (most retro and read-only-by-design filesystems), this is the pragmatic option. Filesystems with a real planner-driven path (FAT once optimised, Btrfs, etc.) implement `Add`/`Remove` themselves and don't use this helper.Companion to `DefragRebuilder` — same shape, different outcome. The two share zero state. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddLargeVolume` | `static void AddLargeVolume(Stream archive, IReadOnlyList inputs, IArchiveFormatOperations ops, IArchiveCreatable creator, IReadOnlySet syntheticNames = null)` | Adds files to a volume too large to hold in memory. Every entry is extracted to scratch, the inputs are merged in by name, and the format's own `Create` lays a fresh volume out — the in-place modifiers read the whole image into an array to find their trees, which is impossible past two gigabytes. | -| `AddStreaming` | `static void AddStreaming(Stream archive, IReadOnlyList inputs, Func>> readEntries, Action>>> rebuild, StringComparer nameComparer = null)` | Streaming counterpart to `Add` for volumes that no byte[] can hold. The merged entry list is produced lazily and handed to `rebuild`, which writes the new image straight to the stream; nothing bigger than one file is ever in memory. | -| `Add` | `static void Add(Stream archive, IReadOnlyList inputs, Func>> readEntries, Func>, byte[]> buildImage, StringComparer nameComparer = null, IArchiveCreatable largeVolumeCreator = null)` | Adds (or replaces) files inside `archive`. Existing entries whose name matches an input are replaced (the new bytes win); other existing entries are carried forward unchanged. The whole image is rebuilt from the merged file list. | -| `NeedsLargeVolumePath` | `static bool NeedsLargeVolumePath(Stream archive)` | Whether a volume is past the size an in-memory edit can handle. | -| `RemoveLargeVolume` | `static void RemoveLargeVolume(Stream archive, string[] entryNames, IArchiveFormatOperations ops, IArchiveCreatable creator, IReadOnlySet syntheticNames = null)` | Removes entries from a volume too large to hold in memory, by the same route as `AddLargeVolume`. | -| `RemoveStreaming` | `static void RemoveStreaming(Stream archive, string[] entryNames, Func>> readEntries, Action>>> rebuild, StringComparer nameComparer = null)` | Streaming counterpart to `Remove`, for the same reason as `AddStreaming`: the kept entries are streamed into a fresh image rather than assembled into one array. | -| `Remove` | `static void Remove(Stream archive, string[] entryNames, Func>> readEntries, Func>, byte[]> buildImage, StringComparer nameComparer = null, IArchiveCreatable largeVolumeCreator = null)` | Removes the named entries from `archive`. The image is rebuilt from scratch with every entry whose name does NOT match one of `entryNames`. Old file bytes are wiped because the new layout starts fresh — no forensic recovery should be possible. | - -#### `PlacementZone` - -Which zone a metadata chunk should be placed in relative to the primary data payload during file-internal optimization. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `BeforeData` | `0` | Place the chunk before the primary data payload. | -| `AfterData` | `1` | Place the chunk after the primary data payload. | -| `Remove` | `2` | Remove the chunk entirely during optimization. | - -#### `RebuildVerb` - -Generic, round-trip-verified "extract → re-create" engine shared by the default implementations of the maintenance verbs (shrink, defragment) for any descriptor that can both enumerate/extract (`IArchiveFormatOperations`) and create (`IArchiveCreatable`) its format. Every rebuild is verified: the freshly created image is listed back and its live-file count compared against the source. If the rebuild would drop files, the operation throws `InvalidOperationException` instead of producing a lossy result — so enabling a verb on a format whose create path doesn't faithfully round-trip fails loudly rather than silently corrupting data. This is what makes broad, default-implementation rollout across filesystems safe. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EditViaRebuild` | `static void EditViaRebuild(Stream archive, IArchiveFormatOperations ops, IArchiveCreatable creator, Action mutate)` | Rebuild-based in-place edit shared by the default `IArchiveModifiable`: extract the archive, apply `mutate` to the extracted file tree (add/overwrite/delete real files on disk), re-create the image, and overwrite the stream. The original bytes are left untouched on any failure. | -| `RebuildInPlace` | `static void RebuildInPlace(Stream archive, IArchiveFormatOperations ops, IArchiveCreatable creator, IReadOnlyDictionary formatSpecific = null)` | In-place rebuild: re-creates `archive` from its own contents (consolidating live data — the defragmentation side effect of the rebuild-via-WORM pattern) and overwrites the stream only when the rebuild is verified to round-trip. On any failure the original bytes are left untouched. | -| `RebuildToStream` | `static int RebuildToStream(Stream input, Stream output, IArchiveFormatOperations ops, IArchiveCreatable creator, IReadOnlyDictionary formatSpecific = null, IReadOnlySet syntheticNames = null)` | Extracts every entry of `input` and re-creates the image into `output` via `creator`. Returns the source live-file count. Throws if the rebuilt image lists fewer live files than the source (lossy round-trip) — the caller's `output` should be discarded in that case. | - -#### `SymlinkResolver` - -Resolves the correct target size of symbolic links inside a single filesystem listing — the headline "show the pointed-to file's size, not the link's own size" behaviour. Given a complete `ArchiveEntryInfo` listing produced by one filesystem, each link's `LinkTarget` is resolved RELATIVE to the directory that holds the link, against the other entries in the same listing, following link chains up to `MaxHops` hops with a cycle guard. When the chain ends at a regular file that is present in the listing, that file's `OriginalSize` is written back as the link's `TargetSize`. Policy — `TargetSize` is deliberately left `null` (unknown) in every case where the answer cannot be proven from the listing alone: an absolute target (leading `/` or a drive-letter prefix), a target that escapes the volume root, a target that is not present in the listing (dangling, or pointing outside this filesystem), a target that resolves to a directory, and any cyclic or over-long (> `MaxHops`) chain. Only relative links to a regular file inside the same filesystem yield a size. The link's own `OriginalSize` is never altered — it stays the on-disk target-path byte length. Path matching is ordinal (case-sensitive), matching the dominant Unix filesystem behaviour of the readers this serves (ext/UFS/SquashFS/EROFS); a case-insensitive volume simply resolves fewer links, never wrong ones. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MaxHops` | `const int MaxHops` | Maximum number of symlink hops followed before a chain is abandoned as too long. | -| `Resolve` | `static List Resolve(List entries)` | Returns a new listing in which every relative symlink that resolves to a regular file within the same listing has its `TargetSize` filled in. Non-link entries and unresolvable links are returned unchanged. | - -#### `UnusedSpaceWiper` - -Generic unused-space wiper that works with any format exposing an extent or layout map. Enumerates all live regions, sorts them, and zero-fills every gap. This covers free clusters/sectors, inter-entry padding in archives, dead bytes after file removal, and any other region not claimed by a live extent. For cluster-tip wiping (trailing slack within a Used extent), callers can supply a file-size lookup so the wiper knows the true file length vs. the cluster-aligned extent length. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ComputeUnusedBytes` | `static long ComputeUnusedBytes(IEnumerable extents, long imageSize, bool includeClusterTips = false, Func fileSizeLookup = null)` | Read-only companion to `Wipe`: returns the total number of bytes in `imageSize` that are NOT covered by a live extent. Useful for telling the user how much of their image is unused *before* the I/O-skipping optimisation in `Wipe` hides the fact that most unused bytes were already zero. | -| `Wipe` | `static long Wipe(Stream image, IEnumerable extents, long imageSize, bool wipeClusterTips = true, Func fileSizeLookup = null)` | Zero-fills every byte in `image` that is not covered by a live (non-Free) extent in `extents`. Optionally wipes cluster tips when `fileSizeLookup` is provided. | - -#### `ValidationIssue` - -A single issue discovered during format validation. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ValidationIssue` | `ValidationIssue(ValidationLevel Level, IssueSeverity Severity, string Code, string Description, long? Offset = null)` | A single issue discovered during format validation. | -| `Code` | `string Code { get; init; }` | | -| `Description` | `string Description { get; init; }` | | -| `Level` | `ValidationLevel Level { get; init; }` | | -| `Offset` | `long? Offset { get; init; }` | | -| `Severity` | `IssueSeverity Severity { get; init; }` | | - -#### `ValidationLevel` - -Depth of validation performed. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Magic` | `0` | Magic byte pattern match only. | -| `Header` | `1` | Header fields checked for valid ranges and consistency. | -| `Structure` | `2` | Directory/TOC parsed, offsets and entry counts verified. | -| `Integrity` | `3` | Checksums verified and/or partial decompression succeeded. | - -#### `ValidationResult` - -Result of validating a format at a specific depth. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ValidationResult` | `ValidationResult()` | | -| `Confidence` | `double Confidence { get; init; }` | Combined confidence after this validation level (0.0–1.0). | -| `Health` | `FormatHealth Health { get; init; }` | Overall health assessment. | -| `IsValid` | `bool IsValid { get; init; }` | Whether the validation at this level passed. | -| `Issues` | `IReadOnlyList Issues { get; init; }` | All issues found during validation. | -| `Level` | `ValidationLevel Level { get; init; }` | Highest validation level that was attempted. | -| `TotalEntries` | `int? TotalEntries { get; init; }` | Total number of entries (for archives). Null for stream formats. | -| `ValidEntries` | `int? ValidEntries { get; init; }` | Number of valid/extractable entries (for archives). Null for stream formats. | - -### Namespace `Compression.Registry.Cvf` - -[`CvfLzCodec`](#cvflzcodec) · [`CvfLzMethod`](#cvflzmethod) · [`Sd4Codec`](#sd4codec) - -#### `CvfLzCodec` - -Genuine DoubleSpace/DriveSpace per-cluster compression codec (DS-0-x and JM-0-x), verified byte-exact against the independent dmsdos decoder. The bitstream packs bits LSB-first into little-endian 16-bit words; a cluster payload is a 16-bit magic (`"DS"`=0x5344 / `"MJ"`=0x4D4A) + 16-bit version + an LZ77 token stream terminated by the 0x113f sync. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DS_0_0` | `const uint DS_0_0` | | -| `JM_0_0` | `const uint JM_0_0` | | -| `SQ_0_0` | `const uint SQ_0_0` | | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, CvfLzMethod method, int level)` | Compresses one cluster. Returns the payload (4-byte method header + token stream, padded to a 2-byte word), or `null` if it would not be smaller than the raw cluster (caller stores raw instead). | -| `Decompress` | `static byte[] Decompress(byte[] payload, int inLen, int outLen)` | Decompresses a cluster payload to exactly `outLen` bytes. | -| `Encode` | `static byte[] Encode(ReadOnlySpan data, CvfLzMethod method, int level)` | Encodes a cluster with the given method, always returning the payload (4-byte header + token stream), or `null` for `Stored` / unsupported methods. The caller decides whether the result fits the cluster's sector budget. | - -#### `CvfLzMethod` - -Compression methods for the MS-DOS DoubleSpace/DriveSpace CVF cluster codec family, byte-compatible with the dmsdos driver's `ds_dec`/`jm_dec`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Stored` | `0` | | -| `Ds` | `1` | | -| `Jm` | `2` | | -| `Auto` | `3` | | -| `Sq` | `4` | | -| `Sd4` | `5` | | - -#### `Sd4Codec` - -Genuine Stacker 4 (SD-4, cluster header `0x0081`) per-cluster codec, byte-compatible with the dmsdos `sd4_decomp` decoder. SD-4 is a bespoke dynamic-Huffman format: a helper Huffman table (table1) encodes the 0x150 code-lengths of the main table (table2), which then Huffman-codes the data. We emit an all-literals SD-4 stream — table2 is a 256-symbol Huffman over the cluster's byte frequencies (genuine entropy compression), with no LZ reps/prog tokens; the decoder terminates on output-full. The bitstream is MSB-first packed into little-endian 16-bit words; Huffman codes are canonical (first-code-per-length, not bit-reversed) exactly as `sd4b_rdhufi` builds them. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static byte[] Decode(byte[] payload, int inLen, int outLen)` | | -| `Encode` | `static byte[] Encode(ReadOnlySpan data)` | | - -### Namespace `Compression.Registry.Layout` - -[`DefragSortField`](#defragsortfield) · [`DefragSortKey`](#defragsortkey) · [`FilterExpression`](#filterexpression) · [`FilterFileContext`](#filterfilecontext) · [`IFileFilter`](#ifilefilter) · [`IFilterFileContext`](#ifilterfilecontext) · [`LayoutTemplate`](#layouttemplate) · [`LayoutTemplateResolver`](#layouttemplateresolver) · [`LayoutZone`](#layoutzone) · [`LeftoverStrategy`](#leftoverstrategy) · [`RangeSpec`](#rangespec) · [`ResolvedFilePlacement`](#resolvedfileplacement) · [`SortDirection`](#sortdirection) - -#### `DefragSortField` - -File-metadata fields the layout-template sorter can order files by. Mirrors the fields available on `IFilterFileContext`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Name` | `0` | File name (final path segment), ordinal compare. | -| `Path` | `1` | Full path, ordinal compare. | -| `Extension` | `2` | File extension including leading dot, ordinal-ignore-case compare. | -| `Size` | `3` | File size in bytes. | -| `LastModified` | `4` | Last-modified timestamp. Null sorts last. | -| `LastAccessed` | `5` | Last-accessed timestamp. Null sorts last. | -| `Created` | `6` | Created timestamp. Null sorts last. | -| `Attributes` | `7` | Attribute bitmask. Files with attributes > 0 sort first ascending — useful for clustering system / hidden / read-only files apart from the bulk. | - -#### `DefragSortKey` - -One ordering rule applied within a `LayoutZone`. A zone may list several keys; they are applied in order with later keys breaking ties of earlier ones. Round-trippable via `Parse` and `ToString`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefragSortKey` | `DefragSortKey(DefragSortField Field, SortDirection Direction)` | One ordering rule applied within a `LayoutZone`. A zone may list several keys; they are applied in order with later keys breaking ties of earlier ones. Round-trippable via `Parse` and `ToString`. | -| `Direction` | `SortDirection Direction { get; init; }` | | -| `Field` | `DefragSortField Field { get; init; }` | | -| `Parse` | `static DefragSortKey Parse(string s)` | Parses a textual sort key. Accepted forms (whitespace-insensitive, case-insensitive on identifiers): `name` — defaults to ascending.`name asc` / `name ascending``lastModified desc` / `last_modified descending``size desc` Identifier matching accepts `camelCase`, `snake_case`, `kebab-case`, and the enum's own ToString form. | -| `ToString` | `override string ToString()` | | - -#### `FilterExpression` - -Parses a tiny predicate language into an `IFileFilter`. Grammar (case-insensitive identifiers, whitespace skipped between tokens):Functions:`quartile(p)` — p-th percentile (0..1) of the file set, resolved dynamically per the field on the LHS.`now()` — current UTC time.`today()` — current UTC date at midnight.`days(n)` / `hours(n)` / `minutes(n)` — durations (subtract from now() / today()).`date("yyyy-MM-dd")` — explicit literal.Error reporting: parse errors include the source offset of the failing token, e.g. `"unknown field 'foobar' at position 7"`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Parse` | `static IFileFilter Parse(string expression)` | Parses `expression` into an `IFileFilter`. Compiled filters are cached by string identity — passing the same string twice returns the same filter instance. | - -#### `FilterFileContext` - -Plain DTO implementation of `IFilterFileContext` used by callers that build the filter context up front rather than wrapping a live source. - -Implements `IEquatable`, `IFilterFileContext`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FilterFileContext` | `FilterFileContext()` | | -| `AllCreatedTimes` | `IReadOnlyList AllCreatedTimes { get; init; }` | | -| `AllLastAccessedTimes` | `IReadOnlyList AllLastAccessedTimes { get; init; }` | | -| `AllLastModifiedTimes` | `IReadOnlyList AllLastModifiedTimes { get; init; }` | | -| `AllSizes` | `IReadOnlyList AllSizes { get; init; }` | | -| `Attributes` | `uint Attributes { get; init; }` | | -| `Created` | `DateTime? Created { get; init; }` | | -| `Extension` | `string Extension { get; init; }` | | -| `LastAccessed` | `DateTime? LastAccessed { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Path` | `string Path { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `IFileFilter` - -A compiled filter expression. Created via `Parse`. Returns `true` when a file matches the expression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Matches` | `bool Matches(IFilterFileContext file)` | Evaluates the filter against `file`. | - -#### `IFilterFileContext` - -View of one file's metadata used by a `IFileFilter` and by the layout-template sorter. Implementations are read-only and may expose `null` for fields the underlying source can't supply (e.g. classic FAT lacks atime; classic ProDOS lacks access timestamps entirely). Filters comparing a missing field always evaluate to `false`. The `All*` properties give a filter access to the population statistics so functions like `quartile(0.75)` can resolve to the correct percentile for the field being compared. They MUST contain the same number of entries as the file set being filtered and MUST be the same instance across calls within a single resolve operation — the filter caches percentile computations by reference. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AllCreatedTimes` | `IReadOnlyList AllCreatedTimes { get; }` | All creation times across the file set. Used by quartile() on the Created field. | -| `AllLastAccessedTimes` | `IReadOnlyList AllLastAccessedTimes { get; }` | All last-accessed times across the file set. Used by quartile() on the LastAccessed field. | -| `AllLastModifiedTimes` | `IReadOnlyList AllLastModifiedTimes { get; }` | All last-modified times across the file set. Used by quartile() on the LastModified field. | -| `AllSizes` | `IReadOnlyList AllSizes { get; }` | All sizes across the file set. Used by quartile() on the Size field. | -| `Attributes` | `uint Attributes { get; }` | Attribute bitmask (filesystem-specific encoding); 0 when none. | -| `Created` | `DateTime? Created { get; }` | Creation timestamp (UTC), or null when unavailable. | -| `Extension` | `string Extension { get; }` | Extension including leading dot, lower-case. Empty when none. | -| `LastAccessed` | `DateTime? LastAccessed { get; }` | Last-accessed timestamp (UTC), or null when unavailable. | -| `LastModified` | `DateTime? LastModified { get; }` | Last-modified timestamp (UTC), or null when unavailable. | -| `Name` | `string Name { get; }` | File name (final path segment). | -| `Path` | `string Path { get; }` | Full path, '/'-separated. Empty string when not nested. | -| `Size` | `long Size { get; }` | Logical file size in bytes (sum of extent lengths). | - -#### `LayoutTemplate` - -A reusable layout description: a named collection of `LayoutZone`s plus a strategy for leftover files. Round-trippable to / from JSON via `ToJson` and `FromJson`. Example JSON: - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LayoutTemplate` | `LayoutTemplate()` | | -| `LeftoverStrategyText` | `string LeftoverStrategyText { get; init; }` | What to do with files matching no zone. Stored as text (`"fill_gaps"` or `"append_at_end"`) so the JSON format stays human-readable, but the canonical accessor is `LeftoverStrategy`. | -| `LeftoverStrategy` | `LeftoverStrategy LeftoverStrategy { get; }` | Parsed form of `LeftoverStrategyText`. | -| `MetadataZone` | `MetadataZone MetadataZone { get; init; }` | Metadata zone placement; defaults to `Unchanged`. | -| `Name` | `string Name { get; init; }` | Human-readable template name (used in UI / logs). | -| `Zones` | `IReadOnlyList Zones { get; init; }` | Ordered list of zones. Zones may overlap; first match wins. | -| `FromJson` | `static LayoutTemplate FromJson(string json)` | Parses a layout template from JSON. Throws `FormatException` when required fields are missing or any embedded expression fails to parse. | -| `Load` | `static LayoutTemplate Load(string path)` | Loads a template from a file on disk. | -| `Save` | `void Save(string path)` | Saves the template to `path` as indented JSON. | -| `ToJson` | `string ToJson()` | Serialises to indented JSON. | - -#### `LayoutTemplateResolver` - -Resolves a `LayoutTemplate` against a real file set into a concrete placement plan (one `ResolvedFilePlacement` per input file). The first zone whose `Filter` matches a file wins; unmatched files are placed per `LeftoverStrategy`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LeftoverZoneName` | `const string LeftoverZoneName` | Pseudo-zone name used for files matching no template zone. | -| `Resolve` | `static IReadOnlyList Resolve(LayoutTemplate template, IReadOnlyList files, long imageSize)` | Resolves `template` against `files` and an image of size `imageSize`. The output preserves the input `files` ordering (`FileIndex` matches the input position) — callers iterate the result, group by ZoneName / SortIndex, and emit moves accordingly. | - -#### `LayoutZone` - -One zone within a `LayoutTemplate`: a byte-range region that holds files matching `Filter`, in the order specified by `SortBy`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LayoutZone` | `LayoutZone()` | | -| `Filter` | `string Filter { get; init; }` | Optional filter expression parsed by `Parse`. `null` = no filter (every file matches; in practice the first zone catches everything). | -| `Name` | `string Name { get; init; }` | Human-readable zone name (used in UI / logs). | -| `Range` | `string Range { get; init; }` | Range expression resolved by `Parse`: `"0%-5%"`, `"0-1MB"`, `"[16384, 32768)"`, etc. | -| `SortBy` | `IReadOnlyList SortBy { get; init; }` | Sort keys applied within this zone (later keys break ties of earlier ones). Empty list = no explicit ordering; files keep their input order. | - -#### `LeftoverStrategy` - -Strategy for files that match no `LayoutZone` in a `LayoutTemplate`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `FillGaps` | `0` | Place leftover files in the gaps between zones (default). | -| `AppendAtEnd` | `1` | Place leftover files after the last zone. | - -#### `RangeSpec` - -A byte-range expression for a `LayoutZone`. Either both `StartFraction`/`EndFraction` are set (percent form: `0%-5%`) or both `StartBytes`/`EndBytes` are set (absolute form: `10MB-50MB`). Open-ended ranges (`5%-`, `-50%`, `1024-+`) resolve to the image bounds. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RangeSpec` | `RangeSpec(double? StartFraction, double? EndFraction, long? StartBytes, long? EndBytes)` | A byte-range expression for a `LayoutZone`. Either both `StartFraction`/`EndFraction` are set (percent form: `0%-5%`) or both `StartBytes`/`EndBytes` are set (absolute form: `10MB-50MB`). Open-ended ranges (`5%-`, `-50%`, `1024-+`) resolve to the image bounds. | -| `EndBytes` | `long? EndBytes { get; init; }` | End (exclusive) in bytes, or null if percent. | -| `EndFraction` | `double? EndFraction { get; init; }` | End (exclusive) as a 0..1 fraction of the image, or null if absolute. | -| `StartBytes` | `long? StartBytes { get; init; }` | Start in bytes, or null if percent. | -| `StartFraction` | `double? StartFraction { get; init; }` | Start as a 0..1 fraction of the image, or null if absolute. | -| `Parse` | `static RangeSpec Parse(string s)` | Parses a textual range. Accepted forms (case-insensitive, whitespace-insensitive): `0%-5%` — percent form, end exclusive.`10MB-50MB` — absolute form with KB/MB/GB/TB suffix.`[1024, 2048)` — bracket form, supports half-open semantics.`[1024, 2048]` — closed form treated as half-open at end+1.`5%-` / `10MB-` — open-ended (to image end).`-50%` / `-1MB` — open-started (from image origin).`1024-+` — synonymous with `1024-`. | -| `Resolve` | `ValueTuple Resolve(long imageSize)` | Resolves the spec into concrete byte bounds against an image of size `imageSize`. End is clamped to `imageSize`. Returns a half-open interval [start, end). | -| `ToString` | `override string ToString()` | | - -#### `ResolvedFilePlacement` - -One file's resolved placement: which zone it belongs to, the zone's concrete byte bounds, and its rank within the zone after sorting. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ResolvedFilePlacement` | `ResolvedFilePlacement(int FileIndex, string ZoneName, long ZoneStart, long ZoneEnd, int SortIndex)` | One file's resolved placement: which zone it belongs to, the zone's concrete byte bounds, and its rank within the zone after sorting. | -| `FileIndex` | `int FileIndex { get; init; }` | Index into the input file list passed to `Resolve`. | -| `SortIndex` | `int SortIndex { get; init; }` | 0-based rank within the zone after sort keys have been applied. | -| `ZoneEnd` | `long ZoneEnd { get; init; }` | Exclusive byte end of the zone. | -| `ZoneName` | `string ZoneName { get; init; }` | Resolved zone name. Pseudo-zones for unmatched files use `""`. | -| `ZoneStart` | `long ZoneStart { get; init; }` | Inclusive byte start of the zone. | - -#### `SortDirection` - -Sort order for a `DefragSortKey`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Ascending` | `0` | Ascending (smallest / earliest first). | -| `Descending` | `1` | Descending (largest / most-recent first). | - -### Namespace `Compression.Registry.Streaming` - -[`BoundedEntryStream`](#boundedentrystream) · [`BoundedWriteStream`](#boundedwritestream) · [`DeferredLengthWriteStream`](#deferredlengthwritestream) · [`ReadOnlyStreamSlice`](#readonlystreamslice) · [`StreamingArchiveInput`](#streamingarchiveinput) - -#### `BoundedEntryStream` - -A read-only `Stream` whose `Read` never produces more than `LogicalSize` bytes regardless of the underlying stream's state. Reads past the bound return 0 (EOF). Seek targets are clamped to the range `[0, LogicalSize]`. Disposes the underlying stream when `leaveOpen=false`. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BoundedEntryStream` | `BoundedEntryStream(Stream inner, long logicalSize, bool leaveOpen = true)` | Creates a bounded view of `inner` capped at `logicalSize` bytes. The current position of `inner` is treated as the bounded view's position 0. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `IsBoundedToSize` | `bool IsBoundedToSize { get; }` | Sentinel property used by callers to assert that an `OpenEntry` override actually returned a bounded stream rather than a raw decoder. Always `true` by construction. | -| `Length` | `override long Length { get; }` | | -| `LogicalSize` | `long LogicalSize { get; }` | The logical entry size — the absolute ceiling on bytes this stream will ever produce, regardless of the underlying stream. | -| `Position` | `override long Position { get; set; }` | Position within the bounded view — always equal to the number of bytes consumed via `Read`. Setting the position clamps to `[0, LogicalSize]`. | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(Span buffer)` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `BoundedWriteStream` - -A write-only `Stream` bounded to exactly `LogicalSize` bytes. Writes past the bound throw `InvalidOperationException`; disposing while the underwrite count is less than `LogicalSize` (and the writer was not explicitly cancelled) also throws. Together these enforce that the caller of `CreateFileEntry(name, length)` produces exactly the declared number of bytes — overrun is caught at the moment of the offending `Write`; underrun is caught on close so the archive committer can refuse a torn entry. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BoundedWriteStream` | `BoundedWriteStream(Stream inner, long logicalSize, bool leaveOpen = true)` | Creates a bounded write view over `inner` capped at `logicalSize` bytes. The wrapper enforces the bound regardless of what `inner` does. | -| `BytesWritten` | `long BytesWritten { get; }` | Number of bytes already written through this wrapper. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `IsBoundedToSize` | `bool IsBoundedToSize { get; }` | Sentinel property used by callers to assert that the bounded write contract is in effect. Always `true` by construction. | -| `Length` | `override long Length { get; }` | | -| `LogicalSize` | `long LogicalSize { get; }` | The declared entry size — exactly the number of bytes the caller must write. Overrun throws on `Write`; underrun throws on `Dispose` unless `Cancel` was called first. | -| `Position` | `override long Position { get; set; }` | Position within the bounded view — always equal to the number of bytes written through this wrapper. Setting the position is not supported. | -| `Cancel` | `void Cancel()` | Cancels the bound check on dispose. After calling this, disposing the stream with fewer than `LogicalSize` bytes written will NOT throw — useful when the writer is being torn down due to a caller-side failure and the underrun is expected. | -| `CreateBuffered` | `static BoundedWriteStream CreateBuffered(long logicalSize, Action onCommit)` | Convenience ctor: buffers writes into an internal `MemoryStream` and invokes `onCommit` with the buffered bytes when the stream is disposed at exactly `logicalSize` bytes. | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `WriteByte` | `override void WriteByte(byte value)` | | -| `Write` | `override void Write(ReadOnlySpan buffer)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `DeferredLengthWriteStream` - -A write-only `Stream` for sources whose length is NOT known up-front. Buffers writes into a `MemoryStream` until they cross `SpillThresholdBytes`, then spills to a temp file and switches further writes to it. On `Dispose`, fires a commit callback with the accumulated byte count plus a `Func` that re-opens the buffered content for reading; the temp file (if any) is best-effort deleted when the consumer disposes the re-opened stream. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DeferredLengthWriteStream` | `DeferredLengthWriteStream(Action> onClose, long spillThresholdBytes = -1, string spillDirectory = null)` | Creates a new deferred-length write stream. | -| `DefaultSpillThresholdBytes` | `const long DefaultSpillThresholdBytes` | Default spill threshold = 256 MiB (mirrors `InMemoryProcessing.ThresholdBytes / 8`: at 2 GiB ceiling that's 256 MiB per stream so several can coexist before exhausting RAM). Compression.Registry cannot reference Compression.Lib, so this constant is duplicated here — keep the values in sync if the lib-side ceiling changes. | -| `BytesWritten` | `long BytesWritten { get; }` | Number of bytes written so far through this stream (in-memory + spilled). | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `HasSpilled` | `bool HasSpilled { get; }` | True if the stream has spilled to disk; false if still entirely in-memory. | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `SpillPath` | `string SpillPath { get; }` | The path of the spill file, or `null` if the stream has not yet spilled. Exposed for diagnostics / tests. | -| `SpillThresholdBytes` | `long SpillThresholdBytes { get; }` | The configured spill threshold. Writes that would push the total count above this value trigger a switch to a temp file. | -| `Cancel` | `void Cancel()` | Cancels the commit callback: the buffered content is discarded and the spill file (if any) is deleted on dispose. The callback registered via the constructor will NOT fire. | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Finalize` | `protected override void Finalize()` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `WriteByte` | `override void WriteByte(byte value)` | | -| `Write` | `override void Write(ReadOnlySpan buffer)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `ReadOnlyStreamSlice` - -A seekable, read-only window into a base `Stream` exposing the half-open byte range `[, + )`. Reads past the bound return 0; seek targets are clamped to `[0, Length]`. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ReadOnlyStreamSlice` | `ReadOnlyStreamSlice(Stream inner, long origin, long length, bool leaveOpen = true)` | Creates a new read-only slice `[origin, origin+length)`. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Inner` | `Stream Inner { get; }` | The underlying stream the slice maps onto. | -| `Length` | `override long Length { get; }` | | -| `Origin` | `long Origin { get; }` | The absolute byte offset of the slice within `Inner`. | -| `Position` | `override long Position { get; set; }` | Position within the slice — clamped to `[0, Length]`. | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(Span buffer)` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `StreamingArchiveInput` - -Describes a single streaming input for an archive write: a name, its size (so two-pass writers can plan layout/geometry up front), whether it is a directory placeholder, and a factory that opens its bytes as a `Stream` on demand. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StreamingArchiveInput` | `StreamingArchiveInput(string Name, long Size, bool IsDirectory, Func OpenStream)` | Describes a single streaming input for an archive write: a name, its size (so two-pass writers can plan layout/geometry up front), whether it is a directory placeholder, and a factory that opens its bytes as a `Stream` on demand. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | When true, no `OpenStream` is required and the entry represents a directory placeholder in the target. | -| `Name` | `string Name { get; init; }` | The entry's archive name (path-like, forward-slash). | -| `OpenStream` | `Func OpenStream { get; init; }` | Factory that returns the entry's bytes as a `Stream` — typically a `BoundedEntryStream`. Ignored when `IsDirectory` is `true`. | -| `Size` | `long Size { get; init; }` | The entry's logical byte size, used by two-pass writers to compute geometry before any data is read. `0` for directory placeholders. | +Every public and protected member of all 550 types, generated from the built assembly and its XML documentation, is in [REFERENCE.md](https://github.com/Hawkynt/CompressionWorkbench/blob/main/Compression.Core/REFERENCE.md). diff --git a/Hawkynt.FileFormats.Archives/README.md b/Hawkynt.FileFormats.Archives/README.md index 77a7837aa..efcf80803 100644 --- a/Hawkynt.FileFormats.Archives/README.md +++ b/Hawkynt.FileFormats.Archives/README.md @@ -615,14291 +615,7 @@ This package is built against the repository's shared Core version. Consume a mu -### Namespace `CompressionWorkbench.FileFormat.Ani` - -[`AniFormatDescriptor`](#aniformatdescriptor) · [`AniReader`](#anireader) · [`AniReader.AniFile`](#anireaderanifile) · [`AniReader.AnimationHeader`](#anireaderanimationheader) · [`AniWriter`](#aniwriter) - -#### `AniFormatDescriptor` - -Pseudo-archive descriptor for Windows animated cursor (`.ani`) files. Each ANI frame is a complete CUR file; the descriptor unpacks each frame and then further unpacks each CUR's sub-images using the CWB ICO/CUR reader, so every extracted sub-image keeps its native on-disk encoding (PNG or DIB) and is named with a matching `.png` / `.bmp` extension. References: `https://en.wikipedia.org/wiki/ANI_(file_format)` — RIFF 'ACON' animated-cursor structureMicrosoft Windows multimedia SDK — RIFF container and 'anih' header documentation - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AniFormatDescriptor` | `AniFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM creation: emits a RIFF "ACON" container whose `LIST "fram"` holds one `icon` chunk per input. Each input must already be a valid CUR (or ICO) file — the writer copies its bytes verbatim and does not synthesise cursor images from arbitrary input data. The first 4 bytes of every input are checked for the ICO/CUR magic (00 00 01 00 or 00 00 02 00); inputs that don't match are rejected so the writer never produces structurally invalid frames. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AniReader` - -Reader for Windows animated cursor (`.ani`) files. ANI is a RIFF container with the form type `"ACON"`; the animation data lives in a `LIST "fram"` chunk that contains one `"icon"` subchunk per frame, each a full CUR file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AniReader` | `AniReader()` | | -| `Read` | `static AniFile Read(ReadOnlySpan data)` | | - -#### `AniReader.AniFile` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AniFile` | `AniFile(AnimationHeader Header, IReadOnlyList Frames, IReadOnlyList Rates, IReadOnlyList Sequence, string Title, string Artist)` | | -| `Artist` | `string Artist { get; init; }` | | -| `Frames` | `IReadOnlyList Frames { get; init; }` | | -| `Header` | `AnimationHeader Header { get; init; }` | | -| `Rates` | `IReadOnlyList Rates { get; init; }` | | -| `Sequence` | `IReadOnlyList Sequence { get; init; }` | | -| `Title` | `string Title { get; init; }` | | - -#### `AniReader.AnimationHeader` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AnimationHeader` | `AnimationHeader(uint CbSize, uint NumFrames, uint NumSteps, uint Width, uint Height, uint BitsPerPixel, uint NumPlanes, uint DefaultJiffiesPerStep, uint Flags)` | | -| `BitsPerPixel` | `uint BitsPerPixel { get; init; }` | | -| `CbSize` | `uint CbSize { get; init; }` | | -| `DefaultJiffiesPerStep` | `uint DefaultJiffiesPerStep { get; init; }` | | -| `Flags` | `uint Flags { get; init; }` | | -| `Height` | `uint Height { get; init; }` | | -| `NumFrames` | `uint NumFrames { get; init; }` | | -| `NumPlanes` | `uint NumPlanes { get; init; }` | | -| `NumSteps` | `uint NumSteps { get; init; }` | | -| `Width` | `uint Width { get; init; }` | | - -#### `AniWriter` - -WORM writer for Windows animated cursor (.ani) RIFF containers. Each input is expected to be a complete CUR (or ICO) file; the writer wraps the inputs in the canonical RIFF "ACON" structure with a 36-byte `anih` animation header and a `LIST "fram"` chunk of `icon` subchunks — one per input frame. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AniWriter` | `AniWriter()` | | -| `Write` | `static void Write(Stream output, IReadOnlyList frames, IReadOnlyList rates = null, IReadOnlyList sequence = null, string title = null, string artist = null, uint defaultJiffies = 6)` | Writes an ANI animated cursor to `output`. Each frame is taken verbatim from `frames` (expected to be CUR file bytes). When `rates` is non-empty the per-step durations override the header's default jiffies; when `sequence` is non-empty the steps replay frames in a non-linear order. | - -### Namespace `CompressionWorkbench.FileFormat.Ico` - -[`CurFormatDescriptor`](#curformatdescriptor) · [`IcoFormatDescriptor`](#icoformatdescriptor) · [`IcoInPlaceModifier`](#icoinplacemodifier) · [`IcoReader`](#icoreader) · [`IcoReader.Bundle`](#icoreaderbundle) · [`IcoReader.IconEntry`](#icoreadericonentry) · [`IcoWriter`](#icowriter) · [`IcoWriter.Image`](#icowriterimage) - -#### `CurFormatDescriptor` - -Pseudo-archive descriptor for Windows CUR cursor bundles. Same on-disk layout as ICO with the type field set to 2 — directory-entry planes/bitcount fields encode hotspot X/Y instead of plane count and bit depth. References: `https://en.wikipedia.org/wiki/ICO_(file_format)` — Wikipedia — documents ICONDIR / ICONDIRENTRY including the CUR hotspot reuse of the planes/bitcount fields"The evolution of the ICO file format" — Raymond Chen, The Old New Thing (Microsoft DevBlogs) series - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveWriteConstraints`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CurFormatDescriptor` | `CurFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `IcoFormatDescriptor` - -Pseudo-archive descriptor for Windows ICO/CUR icon bundles. Each embedded image (PNG or DIB) is exposed as its own archive entry; creating a bundle from PNG/BMP inputs is supported. References: `https://en.wikipedia.org/wiki/ICO_(file_format)` — Wikipedia — documents the ICONDIR / ICONDIRENTRY directory and PNG/DIB payloads"The evolution of the ICO file format" — Raymond Chen, The Old New Thing (Microsoft DevBlogs) series - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveWriteConstraints`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IcoFormatDescriptor` | `IcoFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends one or more new images (PNG or BMP file paths) into the existing ICO bundle in place. Routed through `AddImage`. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries (matching the reader's computed display name, e.g. `icon_00_32x32x32.png`) from the bundle in place. Routed through `RemoveImage`. | - -#### `IcoInPlaceModifier` - -In-place modifier for Windows ICO/CUR icon bundles. Performs Add / Remove against the existing ICONDIR header + ICONDIRENTRY table at the head of the image, and the per-image payloads packed after it. No full rebuild, no fresh re-encoding: the payload bytes of every untouched image are preserved byte-identically, only their absolute file offsets change as the directory grows or shrinks. Layout reminders (LE throughout): Offsets 0..5: ICONDIR (reserved=0 / type=1 or 2 / count).Offsets 6..6+16*count: ICONDIRENTRY table, 16 bytes each.Payloads follow the directory in the order their dir entries reference them via the (size, offset) fields at +8/+12.Add appends a new ICONDIRENTRY at the end of the directory and the new payload at the end of the file. The first existing payload is shifted by 16 bytes (the new directory entry's width); every existing entry's offset field is patched accordingly. Image content bytes are copied verbatim.Remove deletes the named entry's payload bytes from the file and collapses its 16-byte directory slot. Surviving entries' offset fields are patched to compensate for the removed bytes. Removed payload bytes are physically wiped from the image — no forensic recovery.Out of scope: same-size in-place replacement (the existing reader surfaces images by index — replacement is "remove old + add new" which changes the index but keeps the bundle valid).Spec source: Microsoft ICO/CUR documentation (devblogs.microsoft.com "The evolution of the ICO file format") + ICONDIR / ICONDIRENTRY in winuser.h. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddImage` | `static void AddImage(Stream archive, byte[] image)` | Appends `image` (PNG or BMP bytes — same input rules as `IcoWriter`) to `archive`. The directory entry is emitted in the same encoding the writer would have produced for a from-scratch bundle. Existing image payloads are shifted by 16 bytes to make room for the new directory entry; their byte content is unchanged. | -| `RemoveImage` | `static void RemoveImage(Stream archive, string entryName)` | Removes the image with the given `entryName` (matching the reader's computed display name, e.g. `icon_00_32x32x32.png`) from the bundle. The directory slot collapses, the payload bytes are physically deleted from the file, and surviving payload offsets are patched down to reflect the freed 16+payload byte savings. | - -#### `IcoReader` - -Reader for Windows ICO/CUR icon-bundle files. Each embedded image is exposed as a standalone PNG (when the entry is already PNG-encoded) or BMP (when the entry is a DIB — BITMAPFILEHEADER is reconstructed and the AND-mask half of the height is stripped so the BMP renders correctly in standard viewers). - -| Member | Signature | Summary | -| --- | --- | --- | -| `IcoReader` | `IcoReader()` | | -| `Read` | `static Bundle Read(ReadOnlySpan data)` | | - -#### `IcoReader.Bundle` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Bundle` | `Bundle(bool IsCursor, IReadOnlyList Entries)` | | -| `Entries` | `IReadOnlyList Entries { get; init; }` | | -| `IsCursor` | `bool IsCursor { get; init; }` | | - -#### `IcoReader.IconEntry` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IconEntry` | `IconEntry(int Index, int Width, int Height, int BitsPerPixel, int HotspotX, int HotspotY, bool IsPng, string Name, byte[] Data)` | | -| `BitsPerPixel` | `int BitsPerPixel { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Height` | `int Height { get; init; }` | | -| `HotspotX` | `int HotspotX { get; init; }` | | -| `HotspotY` | `int HotspotY { get; init; }` | | -| `Index` | `int Index { get; init; }` | | -| `IsPng` | `bool IsPng { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Width` | `int Width { get; init; }` | | - -#### `IcoWriter` - -Writes Windows ICO bundles. Inputs are individual image files (PNG or BMP). PNG payloads are stored verbatim (Vista+ supports embedded PNG in ICO). BMP payloads are converted back to icon-style DIBs: BITMAPFILEHEADER stripped, biHeight doubled, and a zero AND-mask appended so legacy parsers stay happy. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IcoWriter` | `IcoWriter()` | | -| `BuildCur` | `static byte[] BuildCur(IReadOnlyList images)` | | -| `BuildIco` | `static byte[] BuildIco(IReadOnlyList images)` | | - -#### `IcoWriter.Image` - -Single image to embed. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Image` | `Image(byte[] Data)` | Single image to embed. | -| `Data` | `byte[] Data { get; init; }` | | - -### Namespace `FileFormat.Ace` - -[`AceEntry`](#aceentry) · [`AceFormatDescriptor`](#aceformatdescriptor) · [`AceReader`](#acereader) · [`AceWriter`](#acewriter) - -#### `AceEntry` - -Represents a file entry in an ACE archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceEntry` | `AceEntry()` | | -| `Attributes` | `uint Attributes { get; set; }` | Gets or sets the file attributes. | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `CompressionType` | `int CompressionType { get; set; }` | Gets or sets the compression type (0=store, 1=ACE 1.0, 2=ACE 2.0). | -| `Crc32` | `uint Crc32 { get; set; }` | Gets or sets the CRC-32 of the original data. | -| `DictionaryBits` | `int DictionaryBits { get; set; }` | Gets or sets the dictionary bits (10-22). | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name. | -| `Flags` | `ushort Flags { get; set; }` | Gets or sets the file header flags. | -| `IsEncrypted` | `bool IsEncrypted { get; }` | Gets whether the file is encrypted. | -| `IsSolid` | `bool IsSolid { get; }` | Gets whether this entry is part of a solid block. | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last modification time. | -| `OriginalSize` | `long OriginalSize { get; set; }` | Gets or sets the original (uncompressed) size in bytes. | -| `Quality` | `int Quality { get; set; }` | Gets or sets the compression quality/level. | - -#### `AceFormatDescriptor` - -ACE archive (Marcel Lemke / WinAce) — proprietary high-ratio DOS/Windows compressor of the late 1990s. References: `https://github.com/droe/acefile` — acefile — open-source ACE 1.0/2.0 reader/extractor, the de-facto format reference`https://en.wikipedia.org/wiki/ACE_(compressed_file_format)` — format overview and historyWinAce / unacev2.dll (Marcel Lemke) — the original closed-source implementation; no official spec was ever published - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceFormatDescriptor` | `AceFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the ACE archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the ACE archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single ACE entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's original size. | - -#### `AceReader` - -Reads entries from an ACE archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceReader` | `AceReader(Stream stream, bool leaveOpen = false, string password = null)` | Initializes a new `AceReader` from a stream. | -| `Comment` | `string Comment { get; }` | Gets the archive comment, if present. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the archive. | -| `HasRecoveryRecord` | `bool HasRecoveryRecord { get; }` | Gets whether this archive has a recovery record. | -| `IsSolid` | `bool IsSolid { get; }` | Gets whether this is a solid archive. | -| `Version` | `byte Version { get; }` | Gets the ACE version. | -| `Dispose` | `void Dispose()` | | -| `ExtractEntry` | `byte[] ExtractEntry(AceEntry entry)` | Extracts the data for an entry. | -| `VerifyRecoveryRecord` | `bool VerifyRecoveryRecord()` | Verifies the recovery record against the archive's file data. Returns `true` if the parity matches. | - -#### `AceWriter` - -Creates ACE archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AceWriter` | `AceWriter(int dictionaryBits = 15, string password = null, bool solid = false, bool recoveryRecord = false, int compressionType = 1, int subMode = 0)` | Initializes a new `AceWriter`. | -| `Comment` | `string Comment { get; set; }` | Gets or sets the archive comment. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, string password = null)` | Creates an ACE archive split into multiple volumes. | -| `ToArray` | `byte[] ToArray()` | Creates an ACE archive as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the archive to a stream. | - -### Namespace `FileFormat.Afs` - -[`AfsConstants`](#afsconstants) · [`AfsEntry`](#afsentry) · [`AfsFormatDescriptor`](#afsformatdescriptor) · [`AfsReader`](#afsreader) · [`AfsWriter`](#afswriter) - -#### `AfsConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Alignment` | `const int Alignment` | | -| `HeaderSize` | `const int HeaderSize` | | -| `IndexEntrySize` | `const int IndexEntrySize` | | -| `Magic` | `static readonly byte[] Magic` | | -| `MaxNameLength` | `const int MaxNameLength` | | -| `MetadataNameSize` | `const int MetadataNameSize` | | -| `MetadataPointerSize` | `const int MetadataPointerSize` | | -| `MetadataRecordSize` | `const int MetadataRecordSize` | | - -#### `AfsEntry` - -Represents a single file entry in a Sega AFS archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AfsEntry` | `AfsEntry()` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | Gets the entry's last-modified timestamp from the metadata block, or null if absent. | -| `Name` | `string Name { get; init; }` | Gets the entry name (synthesized as "file_NNNN.bin" if metadata is absent). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry's data within the archive. | -| `Size` | `long Size { get; init; }` | Gets the entry's data length in bytes. | - -#### `AfsFormatDescriptor` - -Sega AFS archive ("AFS\0" magic) — audio/data container used by Dreamcast, PS2 and GameCube era titles. References: `https://github.com/MaikelChan/AFSPacker` — AFSPacker — open-source AFS extractor/creator, the de-facto format referenceThe container was never documented by Sega/CRI; the offset-table layout was recovered by the game-modding community - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AfsFormatDescriptor` | `AfsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AfsReader` - -Reads entries from a Sega AFS (Athena File System) archive — Dreamcast/PS2/GameCube games. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AfsReader` | `AfsReader(Stream stream, bool leaveOpen = false)` | Initializes a new `AfsReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries discovered in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AfsEntry entry)` | Extracts the raw bytes for a single entry. | - -#### `AfsWriter` - -Creates a Sega AFS (Athena File System) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AfsWriter` | `AfsWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `AfsWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data, DateTime? lastModified = null)` | Adds a file entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive to the underlying stream and finalizes the file layout. | - -### Namespace `FileFormat.AlZip` - -[`AlZipEntry`](#alzipentry) · [`AlZipFormatDescriptor`](#alzipformatdescriptor) · [`AlZipModifier`](#alzipmodifier) · [`AlZipReader`](#alzipreader) · [`AlZipWriter`](#alzipwriter) - -#### `AlZipEntry` - -Represents a single file entry in an ALZip (.alz) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlZipEntry` | `AlZipEntry()` | | -| `Attributes` | `byte Attributes { get; init; }` | File attributes byte. | -| `CompressedSize` | `long CompressedSize { get; init; }` | Compressed size in bytes. | -| `Crc32` | `uint Crc32 { get; init; }` | CRC-32 checksum of uncompressed data. | -| `FileName` | `string FileName { get; init; }` | File name (path within archive). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether this entry is a directory. | -| `LastModified` | `DateTime? LastModified { get; init; }` | Last modification date. | -| `MethodName` | `string MethodName { get; }` | Human-readable method name. | -| `Method` | `int Method { get; init; }` | Compression method: Store(0), Bzip2(1), Deflate(2). | -| `OriginalSize` | `long OriginalSize { get; init; }` | Uncompressed size in bytes. | - -#### `AlZipFormatDescriptor` - -ALZ archive — the proprietary container of ESTsoft's ALZip (Korean shareware archiver). References: `http://kippler.com/win/unalz/` — unalz — open-source ALZ extractor, the de-facto format reference`https://en.wikipedia.org/wiki/ALZip` — application backgroundThe format is proprietary (ESTsoft); no official specification was published - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlZipFormatDescriptor` | `AlZipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ALZ archive. Uses `AlZipModifier` — Add appends a new entry over the trailing CLZ end marker; Remove walks the entry chain and shifts trailing bytes. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the ALZ archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the ALZ archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `AlZipModifier`. | - -#### `AlZipModifier` - -Random-access in-place modifier for ALZ archives. Add appends a new entry over the trailing CLZ end-of-archive marker, then rewrites the marker. Remove walks the local-header chain, locates the named entry, and shifts trailing bytes forward to compact (ALZ has no central directory, so compaction is required). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream alz, string name, byte[] data, DateTime? lastModified = null)` | Appends a file to the archive at the position of the existing CLZ end marker, then writes a new end marker. Walks the entry chain once to locate the marker. | -| `RemoveFile` | `static bool RemoveFile(Stream alz, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, optionally wipes its bytes, then shifts trailing bytes forward to compact. | - -#### `AlZipReader` - -Reads ALZip (.alz) archive files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlZipReader` | `AlZipReader(Stream stream, bool leaveOpen = false)` | Creates a new ALZip reader over the given stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | File entries in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AlZipEntry entry)` | Extracts the raw (decompressed) data for the given entry. | - -#### `AlZipWriter` - -Creates ALZip (.alz) archive files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlZipWriter` | `AlZipWriter(Stream stream, bool leaveOpen = false)` | Creates a new ALZip writer over the given stream. | -| `AddDirectory` | `void AddDirectory(string dirName)` | Adds a directory entry to the archive. | -| `AddFile` | `void AddFile(string fileName, byte[] data)` | Adds a file to the archive with deflate compression. | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.Ampk` - -[`AmpkEntry`](#ampkentry) · [`AmpkFormatDescriptor`](#ampkformatdescriptor) · [`AmpkReader`](#ampkreader) · [`AmpkWriter`](#ampkwriter) - -#### `AmpkEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `AmpkEntry` | `AmpkEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `AmpkFormatDescriptor` - -AMPK (Amiga Pack) archive with LZHUF-compressed members. References: Haruhiko Okumura's `lzhuf.c` (1988/89) — the LZSS + adaptive-Huffman codec AMPK members use`https://aminet.net` — Aminet — the Amiga software archive distributing the original packer; the container layout itself is undocumented - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AmpkFormatDescriptor` | `AmpkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AmpkReader` - -Reads AMPK (Amiga Pack) archives. Uses LZHUF compression (similar to LhA). Format: "AMPK" magic, then file entries with 4-byte name length, name, sizes, and LZH compressed data. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AmpkReader` | `AmpkReader(Stream stream, bool leaveOpen = false)` | | -| `AmpkMagic` | `static readonly byte[] AmpkMagic` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AmpkEntry entry)` | | - -#### `AmpkWriter` - -Creates AMPK archives with stored (uncompressed) files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AmpkWriter` | `AmpkWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.AndroidBundle` - -[`AndroidBundleFormatDescriptor`](#androidbundleformatdescriptor) - -#### `AndroidBundleFormatDescriptor` - -Archive view of an Android App Bundle (`.aab`) or split-APK set (`.apks`). The underlying container is a ZIP; this descriptor re-exposes its entries with the split-APK semantics surfaced in the path: `base/` sub-tree → `base/...` (verbatim).`splits/*.apk` top-level APKs → kept at `splits/*.apk`.`BundleConfig.pb` → kept at root. The actual content is a ZIP, so detection is extension-based; at the raw-magic level this still looks like any other PK-signed ZIP and the Zip / Apk descriptors would also match if routed by magic. This descriptor intentionally declares a lower detection confidence for the ZIP local-file header so Zip/Apk win on ambiguous inputs. References: `https://developer.android.com/guide/app-bundle` — official Android App Bundle documentation`https://github.com/google/bundletool` — bundletool — the canonical .aab / .apks tool`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE APPNOTE — the underlying ZIP container spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AndroidBundleFormatDescriptor` | `AndroidBundleFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing bundle. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written; pre-existing entries stay byte-identical. The synthetic `metadata.ini` extraction artifact is a derived view and is skipped. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a fresh Android App Bundle (`.aab`) by delegating to `ZipWriter`. Entry paths are written verbatim; callers are responsible for naming entries with the AAB split-aware structure (`base/`, `splits/`, `BundleConfig.pb`). If the caller does not supply a `BundleConfig.pb`, a minimal placeholder protobuf is appended so the produced archive carries the mandatory configuration entry. | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (AAB/APKS is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (AAB/APKS is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The synthetic `metadata.ini` entry is materialised on the fly from `BundleConfig.pb`; all other entries delegate to the inner `ZipReader` and are wrapped in a `BoundedEntryStream` sized to the entry's uncompressed length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries via `ZipModifier`. The synthetic `metadata.ini` extraction artifact is a derived view and is skipped. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the bundle: gaps between entries not covered by a live extent in the ZIP layout map. Local headers, entry data, the central directory and EOCD are live and preserved. Cluster-tip wiping is N/A (ZIP packs entries back to back with no per-file slack). | - -### Namespace `FileFormat.AndroidOta` - -[`AndroidOtaFormatDescriptor`](#androidotaformatdescriptor) · [`AndroidOtaWriter`](#androidotawriter) - -#### `AndroidOtaFormatDescriptor` - -Android A/B OTA payload (`payload.bin`) — the Chromium Autoupdate (`CrAU`) container used by Android over-the-air updates. The payload embeds a protobuf `DeltaArchiveManifest` plus a metadata signature and data blobs. Protobuf parsing is intentionally out of scope: this descriptor surfaces the structural regions (manifest bytes, signature bytes, data blob) as raw entries so callers can drive their own parsers downstream. References: `https://source.android.com/docs/core/ota` — Android OTA documentation (A/B payload updates)`https://android.googlesource.com/platform/system/update_engine/` — update_engine source; `update_metadata.proto` defines the CrAU payload - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AndroidOtaFormatDescriptor` | `AndroidOtaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM create — emits a CrAU payload with a minimal manifest, optional signature, and concatenated data blobs from the inputs. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AndroidOtaWriter` - -WORM writer for Android A/B OTA payload (`CrAU`) containers. Emits a structurally valid 24-byte header followed by a minimal `DeltaArchiveManifest` protobuf, an optional metadata signature blob, and a payload blob. The manifest is intentionally tiny — a single `block_size = 4096` field — so the output round-trips through our reader without forcing the writer to embed a full protobuf emitter. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultBlockSize` | `const uint DefaultBlockSize` | Default block size advertised in the synthesised manifest. | -| `DefaultVersion` | `const ulong DefaultVersion` | Default major payload version emitted when none is requested. | -| `Magic` | `static ReadOnlySpan Magic { get; }` | Magic bytes that introduce every OTA payload. | -| `Write` | `static void Write(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Writes an OTA payload from `inputs`. Recognised input names — chosen to round-trip our own `Extract` output — are `manifest.pb`, `metadata_signature.bin` and `data.bin`. Any other inputs are concatenated into the data region in the order they appear. | - -### Namespace `FileFormat.ApLib` - -[`ApLibFormatDescriptor`](#aplibformatdescriptor) · [`ApLibStream`](#aplibstream) - -#### `ApLibFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApLibFormatDescriptor` | `ApLibFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `ApLibStream` - -Provides static methods for compressing and decompressing data using the aPLib algorithm with an AP32 framed container format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses data from `input` and writes an AP32-format stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an AP32-format stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Apk` - -[`ApkFormatDescriptor`](#apkformatdescriptor) - -#### `ApkFormatDescriptor` - -Android application package (.apk) — a ZIP container holding the manifest, DEX bytecode, resources and native libraries. References: `https://developer.android.com/guide/components/fundamentals` — Android application fundamentals (APK packaging)`https://en.wikipedia.org/wiki/Apk_(file_format)` — format overview`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE APPNOTE — the underlying ZIP container spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApkFormatDescriptor` | `ApkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing APK archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (APK is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (APK is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.ApkNativeLibs` - -[`ApkNativeLibsFormatDescriptor`](#apknativelibsformatdescriptor) - -#### `ApkNativeLibsFormatDescriptor` - -Alternative view over an Android APK that surfaces only its packaged native libraries (`lib//*.so`) as archive entries under `native_libs//*.so`. Intentionally not registered for magic detection (all magic signatures are zero-confidence); the caller must route here explicitly, e.g. `cwb list --format ApkNativeLibs foo.apk`. References: `https://developer.android.com/ndk/guides/abis` — Android ABI management — defines the per-ABI native-library directory layout inside an APK`https://en.wikipedia.org/wiki/Apk_(file_format)` — APK container overview - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApkNativeLibsFormatDescriptor` | `ApkNativeLibsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a fresh APK-shaped ZIP containing only the native libraries supplied in `inputs`. Incoming entry paths may use either the underlying `lib//*.so` form or the rewritten `native_libs//*.so` view — the latter is unrewrap-ed back to `lib/` before being added to the inner ZIP so the produced archive is a standard split-APK fragment loadable by any APK tool. Entries that don't end in `.so` are written verbatim. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single rewritten native-lib entry as a bounded stream. The caller's `entryName` uses the synthetic `native_libs//*.so` view; we reverse the rewrite back to the underlying `lib//*.so` ZIP entry, decode it, and wrap the bytes in a `BoundedEntryStream` sized to the entry's uncompressed length. | - -### Namespace `FileFormat.AppImage` - -[`AppImageFormatDescriptor`](#appimageformatdescriptor) · [`AppImageWriter`](#appimagewriter) - -#### `AppImageFormatDescriptor` - -Descriptor for Linux AppImage executables. An AppImage is an ELF stub followed immediately (or after alignment padding) by a SquashFS v4 filesystem image holding the application payload. Types 1 and 2 are distinguished by the magic bytes `AI\x01` / `AI\x02` placed at ELF offset 8 (inside the `EI_PAD` region of `e_ident`). The descriptor surfaces: A synthetic `metadata.ini` with AppImage type, runtime offset, and architecture.Every SquashFS entry, prefixed with `filesystem/`. References: `https://github.com/AppImage/AppImageSpec` — AppImage format specification (type 1 and type 2)`https://appimage.org` — project site`https://en.wikipedia.org/wiki/AppImage` — background - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppImageFormatDescriptor` | `AppImageFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Capabilities supported by this descriptor. | -| `Category` | `FormatCategory Category { get; }` | This format describes an archive container. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | Compound extensions are not used by this format. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Preferred extension (case-sensitive on Linux filesystems). | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Human-readable name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Extensions recognised as AppImage files. | -| `Family` | `AlgorithmFamily Family { get; }` | Algorithmic family. | -| `Id` | `string Id { get; }` | Unique format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | Magic-byte signatures. The AppImage spec puts `AI\x01` or `AI\x02` at file offset 8 — inside the ELF `EI_PAD` area. Either marker combined with the leading `\x7FELF` uniquely identifies an AppImage. | -| `Methods` | `IReadOnlyList Methods { get; }` | Method labels are filled in at read time from the SquashFS compression id. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a TAR-compound format. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates a fresh AppImage at `output` by emitting a minimal ELF type-2 stub followed by a SquashFS image holding `inputs`. The `filesystem/` prefix and the synthetic `metadata.ini` entry produced by the reader's listing view are stripped automatically so a List→Extract→Create round trip keeps the original filesystem layout. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | Extracts the synthetic `metadata.ini` plus every SquashFS entry to `outputDir`, retaining the `filesystem/` prefix. | -| `List` | `List List(Stream stream, string password)` | Lists a synthetic `metadata.ini` entry plus every SquashFS entry from the appended filesystem, each prefixed with `filesystem/`. | - -#### `AppImageWriter` - -Writer for Linux AppImage type 2 files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppImageWriter` | `AppImageWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `AppImageWriter` targeting `stream`. | -| `AppImageType` | `const byte AppImageType` | AppImage type marker (1 or 2). Type 2 is the only modern format. | -| `StubSize` | `const int StubSize` | Size of the embedded minimal ELF64 stub in bytes. | -| `AddDirectory` | `void AddDirectory(string path)` | Adds an explicit directory entry to the AppImage's SquashFS payload. | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file entry to the AppImage's SquashFS payload. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Emits the ELF stub followed by the SquashFS image holding the queued entries. | - -### Namespace `FileFormat.AppleSingle` - -[`AppleDoubleFormatDescriptor`](#appledoubleformatdescriptor) · [`AppleSingleFormatDescriptor`](#applesingleformatdescriptor) · [`AppleSingleInPlaceModifier`](#applesingleinplacemodifier) · [`AppleSingleReader`](#applesinglereader) · [`AppleSingleReader.Container`](#applesinglereadercontainer) · [`AppleSingleReader.Entry`](#applesinglereaderentry) · [`AppleSingleWriter`](#applesinglewriter) - -#### `AppleDoubleFormatDescriptor` - -Pseudo-archive descriptor for AppleDouble (RFC 1740) sidecar files — the resource fork + Finder metadata Macs leave alongside files when copied to non-HFS filesystems (commonly named `._foo`). Same on-disk layout as AppleSingle but the data fork lives in the sibling file rather than this one. References: `https://www.rfc-editor.org/rfc/rfc1740` — RFC 1740 — carries the AppleSingle/AppleDouble format description as an appendixApple "AppleSingle/AppleDouble Formats for Foreign Files Developer's Note" (1990) — the defining vendor document`https://en.wikipedia.org/wiki/AppleSingle_and_AppleDouble_formats` — format overview - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDoubleFormatDescriptor` | `AppleDoubleFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AppleSingleFormatDescriptor` - -Pseudo-archive descriptor for AppleSingle (RFC 1740) container files. Each entry id (data fork, resource fork, Finder info, dates, real name, …) is surfaced as a separate archive entry plus a metadata.ini summary. References: `https://www.rfc-editor.org/rfc/rfc1740` — RFC 1740 — carries the AppleSingle/AppleDouble format description as an appendixApple "AppleSingle/AppleDouble Formats for Foreign Files Developer's Note" (1990) — the defining vendor document`https://en.wikipedia.org/wiki/AppleSingle_and_AppleDouble_formats` — format overview - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleSingleFormatDescriptor` | `AppleSingleFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by id) entries inside an existing AppleSingle container. Routes through `AppleSingleInPlaceModifier` so untouched payload byte-content survives the operation. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a fresh AppleSingle container from the supplied inputs. Input archive names are mapped to entry ids via `EntryIdForName`; the synthetic `metadata.ini` entry the descriptor surfaces on read is silently dropped during create — it isn't a real AppleSingle entry. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single AppleSingle entry as a bounded read-only stream. Each entry's decoded byte buffer is wrapped in a `BoundedEntryStream` sized to its logical length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing AppleSingle container. Routes through `AppleSingleInPlaceModifier` — payload bytes are zero-wiped and the 12-byte directory slot is compacted out. | - -#### `AppleSingleInPlaceModifier` - -In-place modifier for AppleSingle (RFC 1740) containers. Supports Add / Replace / Remove against the 12-byte entry-directory slots and the per-entry payload area that follows them. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddEntry` | `static void AddEntry(Stream archive, uint entryId, byte[] data)` | Appends a brand-new entry id at the end of the directory. | -| `RemoveEntry` | `static bool RemoveEntry(Stream archive, uint entryId)` | Removes the entry with the given id. The payload range is zero-wiped and the 12-byte directory slot is compacted out by shifting trailing slots forward. | -| `ReplaceEntry` | `static void ReplaceEntry(Stream archive, uint entryId, byte[] data)` | Replaces or adds the given entry id with new payload bytes. When the id already exists the previous payload range is zero-wiped first. | - -#### `AppleSingleReader` - -Reader for Apple's AppleSingle and AppleDouble container formats (RFC 1740). AppleSingle bundles data fork, resource fork, and Finder metadata into one file; AppleDouble splits the data fork off and stores everything else in a sibling file (the `._foo` companions Macs leave on non-HFS filesystems). Both share an identical entry-table layout. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleSingleReader` | `AppleSingleReader()` | | -| `MagicDouble` | `const uint MagicDouble` | | -| `MagicSingle` | `const uint MagicSingle` | | -| `DecodeRealName` | `static string DecodeRealName(byte[] data)` | Decodes the embedded "real_name" entry as a UTF-8 (or MacRoman ASCII) string. | -| `EntryDescription` | `static string EntryDescription(uint id)` | Returns the human-readable entry text when the entry id is documented. | -| `EntryName` | `static string EntryName(uint id)` | Maps an AppleSingle/AppleDouble entry id to a stable display name. | -| `Read` | `static Container Read(ReadOnlySpan data)` | | - -#### `AppleSingleReader.Container` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Container` | `Container(bool IsDouble, uint Version, IReadOnlyList Entries)` | | -| `Entries` | `IReadOnlyList Entries { get; init; }` | | -| `IsDouble` | `bool IsDouble { get; init; }` | | -| `Version` | `uint Version { get; init; }` | | - -#### `AppleSingleReader.Entry` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entry` | `Entry(uint EntryId, string Name, byte[] Data)` | | -| `Data` | `byte[] Data { get; init; }` | | -| `EntryId` | `uint EntryId { get; init; }` | | -| `Name` | `string Name { get; init; }` | | - -#### `AppleSingleWriter` - -Writer for Apple's AppleSingle (RFC 1740) container format. Emits the canonical 26-byte header followed by an `N×12-byte` entry directory and the per-entry payloads at contiguous offsets behind the directory. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Build` | `static byte[] Build(IReadOnlyList> entries)` | Serializes the given entries into a single AppleSingle byte buffer. Entries appear in caller-supplied order, both in the directory and in the data area immediately after it. The 16-byte filler block is left zero (RFC 1740 v2 convention). | -| `EntryIdForName` | `static uint EntryIdForName(string name)` | Maps a stable display name (the same one `EntryName` emits) back to the AppleSingle entry id. Unknown names following the `entry_NNNNN.bin` shape recover their numeric id; anything else throws. | - -### Namespace `FileFormat.Appx` - -[`AppxFormatDescriptor`](#appxformatdescriptor) - -#### `AppxFormatDescriptor` - -Windows app package (.appx/.msix) — ZIP-based container with AppxManifest.xml, block map and package signature. References: `https://learn.microsoft.com/en-us/windows/msix/` — MSIX/APPX packaging documentation`https://en.wikipedia.org/wiki/APPX` — format overview`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE APPNOTE — the underlying ZIP container spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppxFormatDescriptor` | `AppxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing APPX archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (APPX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (APPX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Ar` - -[`ArConstants`](#arconstants) · [`ArEntry`](#arentry) · [`ArFormatDescriptor`](#arformatdescriptor) · [`ArModifier`](#armodifier) · [`ArReader`](#arreader) · [`ArWriter`](#arwriter) · [`ArWriter.StreamingMember`](#arwriterstreamingmember) - -#### `ArConstants` - -Constants for the Unix ar archive format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EntryHeaderSize` | `const int EntryHeaderSize` | Size in bytes of each entry header. | -| `GlobalHeaderSize` | `const int GlobalHeaderSize` | Size in bytes of the global archive header. | -| `GnuLongNamePrefix` | `const char GnuLongNamePrefix` | Prefix for a GNU long filename reference (e.g. "/12"). | -| `GnuStringTableName` | `const string GnuStringTableName` | GNU extended filename table entry name ("//"). | -| `MaxInlineNameLength` | `const int MaxInlineNameLength` | Maximum filename length that fits directly in the 16-byte name field (15 usable characters + '/' terminator). | -| `PaddingByte` | `const byte PaddingByte` | Padding byte appended after entry data when the data length is odd. | -| `EntryMagic` | `static ReadOnlySpan EntryMagic { get; }` | The two-byte magic that terminates every entry header: "`\n" (0x60, 0x0A). | -| `GlobalMagic` | `static ReadOnlySpan GlobalMagic { get; }` | Global archive header: "!\n" (8 bytes). | - -#### `ArEntry` - -Represents a single file entry in a Unix ar archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArEntry` | `ArEntry()` | | -| `DataOffset` | `long DataOffset { get; set; }` | Byte offset of this entry's data within the archive. | -| `DataSize` | `long DataSize { get; set; }` | Length of this entry's data, which may exceed what `Data` can hold. | -| `Data` | `byte[] Data { get; set; }` | Gets or sets the raw file data. | -| `FileMode` | `int FileMode { get; set; }` | Gets or sets the file permission mode (octal, e.g. 0o100644). | -| `GroupId` | `int GroupId { get; set; }` | Gets or sets the numeric group ID. | -| `IsDataLoaded` | `bool IsDataLoaded { get; }` | True when `Data` holds the entry's bytes. False for an entry too large to materialise, whose bytes must be read via `ArReader.CopyEntryTo` using `DataOffset` and `DataSize`. | -| `ModifiedTime` | `DateTimeOffset ModifiedTime { get; set; }` | Gets or sets the last-modification time of the entry. | -| `Name` | `string Name { get; set; }` | Gets or sets the filename of the entry. | -| `OwnerId` | `int OwnerId { get; set; }` | Gets or sets the numeric owner (user) ID. | - -#### `ArFormatDescriptor` - -Unix ar archive — the static-library (.a) and .deb outer container with 60-byte ASCII member headers. References: `ar(5)` man page (4.4BSD / FreeBSD) — the de-facto format definition (ar was never standardized by POSIX)`https://en.wikipedia.org/wiki/Ar_(Unix)` — format overview incl. the GNU and BSD long-name extensions - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArFormatDescriptor` | `ArFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing AR archive. Uses `ArModifier` for true random-access I/O — Add is O(touched bytes) (append at EOF after a quick header walk); Remove is O(image-size-after-target) because AR has no central directory and trailing entries must be shifted. | -| `CreateFromStreams` | `void CreateFromStreams(Stream target, IEnumerable inputs, FormatCreateOptions options)` | Large-file-safe streaming variant of `Create`. The 60-byte ar member header encodes the payload size before the payload, so the pre-known `Size` drives the header and the payload is copied in 64 KB chunks via `WriteStreaming` — peak memory is bounded by the copy buffer regardless of member size. AR has no directory concept, so directory inputs are skipped exactly as `Create` does via `FilesOnly`. Output is byte-identical to `Create` for the same file inputs (default `ArEntry` metadata: Unix-epoch mtime, uid/gid 0, mode 0644). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the AR archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the AR archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single AR entry as a bounded read-only `Stream`. AR stores each entry's bytes uncompressed and the reader pre-loads them into `Data`; the bounded wrapper sizes the view to the entry's data length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing AR archive. Uses `ArModifier` for in-place compaction. | - -#### `ArModifier` - -Random-access in-place modifier for Unix ar archives. Add appends a new entry at EOF — touches only the new entry's bytes plus a quick header chain walk to find the end. Remove walks the header chain to locate the target, then shifts trailing bytes forward to close the gap (necessary because AR has no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream ar, string name, byte[] data)` | Appends a regular file entry. Walks the existing header chain to find EOF, writes the new 60-byte header + data + alignment pad, and truncates the stream to the new length. | -| `RemoveFile` | `static bool RemoveFile(Stream ar, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. The trailing portion of the file is shifted forward to close the gap (AR has no central directory; readers walk headers sequentially, so we must compact). | - -#### `ArReader` - -Reads entries from a Unix ar archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArReader` | `ArReader(Stream stream, bool leaveOpen = false)` | Initializes a new `ArReader` and parses the archive. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries present in the archive. | -| `CopyEntryTo` | `void CopyEntryTo(ArEntry entry, Stream destination)` | Copies `entry`'s bytes to `destination`, reading them from the archive when the entry was too large to materialise. | -| `Dispose` | `void Dispose()` | | - -#### `ArWriter` - -Writes a Unix ar archive to a stream. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArWriter` | `ArWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `ArWriter`. | -| `Dispose` | `void Dispose()` | | -| `WriteStreaming` | `void WriteStreaming(IReadOnlyList members)` | Writes all `members` to the stream as a complete ar archive, streaming each member's payload from its `OpenData` factory in bounded 64 KB chunks rather than buffering it into RAM. The ar header encodes each member's size before its payload, so the pre-known `Size` drives the header; the GNU string table for overlong names is built from the names alone in a first pass. | -| `Write` | `void Write(IReadOnlyList entries)` | Writes all `entries` to the stream as a complete ar archive, using the GNU extended filename format for names longer than `MaxInlineNameLength` characters. | - -#### `ArWriter.StreamingMember` - -Describes a single streaming ar member: its metadata plus a pre-known payload size and an on-demand source stream. Used by `WriteStreaming` so multi-GB members never materialize in RAM. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StreamingMember` | `StreamingMember(string Name, long Size, Func OpenData, DateTimeOffset ModifiedTime, int OwnerId = 0, int GroupId = 0, int FileMode = 33188)` | Describes a single streaming ar member: its metadata plus a pre-known payload size and an on-demand source stream. Used by `WriteStreaming` so multi-GB members never materialize in RAM. | -| `FileMode` | `int FileMode { get; init; }` | The file permission mode (octal). | -| `GroupId` | `int GroupId { get; init; }` | The numeric group ID. | -| `ModifiedTime` | `DateTimeOffset ModifiedTime { get; init; }` | The member's modification time. | -| `Name` | `string Name { get; init; }` | The member name. | -| `OpenData` | `Func OpenData { get; init; }` | Factory that opens the member's payload stream. | -| `OwnerId` | `int OwnerId { get; init; }` | The numeric owner (user) ID. | -| `Size` | `long Size { get; init; }` | The member's logical byte size. | - -### Namespace `FileFormat.Arc` - -[`ArcCompressionMethod`](#arccompressionmethod) · [`ArcConstants`](#arcconstants) · [`ArcEntry`](#arcentry) · [`ArcFormatDescriptor`](#arcformatdescriptor) · [`ArcModifier`](#arcmodifier) · [`ArcReader`](#arcreader) · [`ArcWriter`](#arcwriter) - -#### `ArcCompressionMethod` - -Compression methods supported by the ARC archive writer. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Stored` | `2` | No compression — data is stored as-is (method 2). | -| `Packed` | `3` | ARC run-length encoding using 0x90 as the repeat marker (method 3). | -| `Squeezed` | `4` | Static Huffman coding (method 4). | -| `Crunched5` | `5` | LZW 9-12 bits with RLE pre-pass (method 5). | -| `Crunched6` | `6` | LZW 9-12 bits, no clear code, no RLE (method 6). | -| `Crunched7` | `7` | LZW 9-12 bits with clear code, no RLE (method 7). | -| `Crunched` | `8` | LZW with 9-13 bit codes and dynamic clear codes (method 8). | -| `Squashed` | `9` | LZW with 9-13 bit codes, no RLE pre-pass (method 9). | - -#### `ArcConstants` - -Constants for the ARC archive format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FileNameLength` | `const int FileNameLength` | Length of the filename field in the header (13 bytes, null-terminated). | -| `LzwMaxBits` | `const int LzwMaxBits` | Maximum bits for LZW codes in method 8/9. | -| `LzwMinBits` | `const int LzwMinBits` | Minimum bits for LZW codes (initial code width). | -| `Magic` | `const byte Magic` | Magic byte that begins every ARC entry header. | -| `MethodCrunched5` | `const byte MethodCrunched5` | Method 5: Crunched — LZW 9-12 bits (not supported). | -| `MethodCrunched6` | `const byte MethodCrunched6` | Method 6: Crunched — LZW 9-12 bits, no RLE (not supported). | -| `MethodCrunched7` | `const byte MethodCrunched7` | Method 7: Crunched — LZW 9-12 bits, new hash (not supported). | -| `MethodCrunched8` | `const byte MethodCrunched8` | Method 8: Crunched — LZW 9-13 bits, dynamic reset. | -| `MethodEndOfArchive` | `const byte MethodEndOfArchive` | Method code that marks the end of the archive. | -| `MethodPacked` | `const byte MethodPacked` | Method 3: Packed — ARC run-length encoding (RLE) using 0x90 as the repeat marker. | -| `MethodSquashed` | `const byte MethodSquashed` | Method 9: Squashed — LZW 9-13 bits, no RLE. | -| `MethodSqueezed` | `const byte MethodSqueezed` | Method 4: Squeezed — Huffman coding (not supported). | -| `MethodStoredOld` | `const byte MethodStoredOld` | Method 1: Stored (old format, no original-size field in header). | -| `MethodStored` | `const byte MethodStored` | Method 2: Stored (new format, original-size field present). | -| `NewHeaderSize` | `const int NewHeaderSize` | Size of the new-style entry header in bytes (methods 2+, includes original-size field). | -| `OldHeaderSize` | `const int OldHeaderSize` | Size of the old-style entry header in bytes (method 1, no original-size field). | -| `RleMarker` | `const byte RleMarker` | The RLE repeat marker byte used by ARC's Packed (method 3) format. | - -#### `ArcEntry` - -Represents the metadata for a single entry in an ARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArcEntry` | `ArcEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `Crc16` | `ushort Crc16 { get; set; }` | Gets or sets the CRC-16 of the uncompressed data. | -| `DosDate` | `ushort DosDate { get; set; }` | Gets or sets the MS-DOS date stamp. | -| `DosTime` | `ushort DosTime { get; set; }` | Gets or sets the MS-DOS time stamp. | -| `FileName` | `string FileName { get; set; }` | Gets or sets the filename stored in the archive (up to 12 characters). | -| `LastModified` | `DateTimeOffset LastModified { get; set; }` | Gets the last modified time decoded from the MS-DOS date/time fields, or `MinValue` if the fields are zero. | -| `Method` | `byte Method { get; set; }` | Gets or sets the compression method code. | -| `OriginalSize` | `uint OriginalSize { get; set; }` | Gets or sets the uncompressed (original) size in bytes. | - -#### `ArcFormatDescriptor` - -ARC archive (System Enhancement Associates, 1985) — one of the first PC compression container formats. References: `https://github.com/hyc/arc` — SEA ARC source (GPL continuation maintained by Howard Chu) — the reference implementation`https://en.wikipedia.org/wiki/ARC_(file_format)` — format history - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArcFormatDescriptor` | `ArcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ARC archive. Uses `ArcModifier` — Add appends Stored before the EOA marker; Remove walks the entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the ARC archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the ARC archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ArcModifier`. | - -#### `ArcModifier` - -Random-access in-place modifier for ARC archives (System Enhancement Associates / PKARC). ARC archives are a chain of variable-size entry blocks terminated by an end-of-archive marker (magic 0x1A followed by method byte 0x00). Add appends a new Stored (method 2) entry just before the EOA marker; Remove walks the entry chain, locates the target, and shifts trailing bytes forward to compact (ARC has no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream arc, string name, byte[] data)` | Appends a Stored (method 2) entry to the archive. Walks the existing entry chain to find the EOA marker, writes a new entry block in its place, then re-writes the EOA marker. I/O cost is one full sequential entry walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream arc, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact. | - -#### `ArcReader` - -Reads entries sequentially from an ARC archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArcReader` | `ArcReader(Stream stream, bool leaveOpen = false)` | Initializes a new `ArcReader` from a stream containing ARC archive data. | -| `Dispose` | `void Dispose()` | | -| `GetNextEntry` | `ArcEntry GetNextEntry()` | Reads the next entry header from the archive. | -| `ReadEntryData` | `byte[] ReadEntryData()` | Decompresses and returns the data for the current entry. | - -#### `ArcWriter` - -Creates an ARC archive by writing entries sequentially to a stream. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArcWriter` | `ArcWriter(Stream stream, ArcCompressionMethod defaultMethod = 2, bool leaveOpen = false)` | Initializes a new `ArcWriter`. | -| `AddEntry` | `void AddEntry(string fileName, ReadOnlySpan data, ArcCompressionMethod method, DateTimeOffset lastModified = null)` | Adds a file entry to the archive using a specific compression method. | -| `AddEntry` | `void AddEntry(string fileName, ReadOnlySpan data, DateTimeOffset lastModified = null)` | Adds a file entry to the archive using the writer's default compression method. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, ArcCompressionMethod method = 2)` | Creates an ARC archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the end-of-archive marker and flushes the stream. | - -### Namespace `FileFormat.Arj` - -[`ArjConstants`](#arjconstants) · [`ArjEntry`](#arjentry) · [`ArjFormatDescriptor`](#arjformatdescriptor) · [`ArjLayoutMap`](#arjlayoutmap) · [`ArjModifier`](#arjmodifier) · [`ArjReader`](#arjreader) · [`ArjWriter`](#arjwriter) - -#### `ArjConstants` - -Constants for the ARJ archive format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArchiverVersion` | `const byte ArchiverVersion` | Archiver version number written into archive headers. | -| `FileTypeBinary` | `const byte FileTypeBinary` | File type: binary file. | -| `FileTypeComment` | `const byte FileTypeComment` | File type: comment/archive header. | -| `FileTypeDirectory` | `const byte FileTypeDirectory` | File type: directory. | -| `FileTypeText` | `const byte FileTypeText` | File type: text file. | -| `FirstHeaderMinSize` | `const int FirstHeaderMinSize` | Minimum length of the first-header section (bytes 4 through 33 inclusive, before filename). | -| `FirstHeaderOffset` | `const int FirstHeaderOffset` | Byte offset within the basic header where the first-header section begins (byte 4). The CRC of the basic header is computed over this section. | -| `FlagBackup` | `const byte FlagBackup` | ARJ flag: backup flag (from backup software). | -| `FlagExtFile` | `const byte FlagExtFile` | ARJ flag: extended file information present. | -| `FlagGarbled` | `const byte FlagGarbled` | ARJ flag: garbled (encrypted). | -| `FlagPathSep` | `const byte FlagPathSep` | ARJ flag: path translated (directory separators converted). | -| `FlagVolume` | `const byte FlagVolume` | ARJ flag: volume continuation. | -| `HeaderId` | `const ushort HeaderId` | The two-byte magic number that marks the start of every ARJ header (0xEA60, little-endian). | -| `MethodCompressed1` | `const byte MethodCompressed1` | Compression method 1: compressed (LZ77+Huffman, primary). | -| `MethodCompressed2` | `const byte MethodCompressed2` | Compression method 2: compressed (alternate). | -| `MethodCompressed3` | `const byte MethodCompressed3` | Compression method 3: compressed (alternate). | -| `MethodStoreFast` | `const byte MethodStoreFast` | Compression method 4: store (no-compression, fastest). | -| `MethodStore` | `const byte MethodStore` | Compression method 0: store (no compression). | -| `MinVersionToExtract` | `const byte MinVersionToExtract` | Minimum archiver version required to extract (stored method only). | -| `OsAmiga` | `const byte OsAmiga` | Host OS: Amiga. | -| `OsApple2E` | `const byte OsApple2E` | Host OS: Apple IIe. | -| `OsDos` | `const byte OsDos` | Host OS: MS-DOS. | -| `OsMacOs` | `const byte OsMacOs` | Host OS: Mac OS. | -| `OsOs2` | `const byte OsOs2` | Host OS: OS/2. | -| `OsPrimos` | `const byte OsPrimos` | Host OS: PRIMOS. | -| `OsUnix` | `const byte OsUnix` | Host OS: UNIX. | -| `OsWindows` | `const byte OsWindows` | Host OS: Windows 95/NT. | - -#### `ArjEntry` - -Represents a single entry (file or directory) within an ARJ archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjEntry` | `ArjEntry()` | | -| `Comment` | `string Comment { get; set; }` | Gets or sets the file comment. | -| `CompressedSize` | `uint CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `Crc32` | `uint Crc32 { get; set; }` | Gets or sets the CRC-32 of the original (uncompressed) data. | -| `FileMode` | `ushort FileMode { get; set; }` | Gets or sets the file access mode (MS-DOS attribute bits). | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name (may include a relative path). | -| `FileType` | `byte FileType { get; set; }` | Gets or sets the file type. | -| `Flags` | `byte Flags { get; set; }` | Gets or sets the ARJ flags byte. | -| `HostOs` | `byte HostOs { get; set; }` | Gets or sets the host OS on which the file was archived. | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets whether this entry represents a directory. | -| `LastModified` | `DateTime LastModified { get; }` | Gets the last modification time decoded from the MS-DOS timestamp. Returns `MinValue` if the timestamp is invalid. | -| `Method` | `byte Method { get; set; }` | Gets or sets the compression method. | -| `MsdosTimestamp` | `uint MsdosTimestamp { get; set; }` | Gets or sets the last modification timestamp in MS-DOS format. | -| `OriginalSize` | `uint OriginalSize { get; set; }` | Gets or sets the original (uncompressed) size in bytes. | - -#### `ArjFormatDescriptor` - -ARJ archive (Robert K. Jung, 1991) — DOS-era compressor known for solid multi-volume support. References: ARJ `TECHNOTE.TXT` — the official format description shipped with the ARJ distribution`https://arj.sourceforge.net` — ARJ for Unix — open-source continuation`https://en.wikipedia.org/wiki/ARJ` — format history - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjFormatDescriptor` | `ArjFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ARJ archive. Uses `ArjModifier` — Add appends Stored before the EOA marker; Remove walks the entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the ARJ archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the ARJ archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single ARJ entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's original size. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ArjModifier`. | - -#### `ArjLayoutMap` - -Walks an ARJ archive and emits the byte-level layout: main archive header, each entry header, compressed data, and the end-of-archive marker. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `ArjModifier` - -Random-access in-place modifier for ARJ archives. Add appends a new entry just before the end-of-archive marker (a header with basicHeaderSize == 0). Remove walks the entry chain, locates the target, and shifts trailing bytes forward to compact (ARJ has no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream arj, string name, byte[] data)` | Appends a Stored entry to the archive. Walks the existing entry chain to find the EOA marker, writes a new entry block in its place, then re-writes the EOA marker. I/O cost is one full sequential entry walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream arj, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact. | - -#### `ArjReader` - -Reads entries from an ARJ archive stream. Supports extraction of stored entries (methods 0 and 4). Compressed methods (1–3) are detected but extraction is not supported. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjReader` | `ArjReader(Stream stream, bool leaveOpen = false)` | Initializes a new `ArjReader` and reads the archive index. | -| `ArjReader` | `ArjReader(Stream stream, string password, bool leaveOpen = false)` | Opens an ARJ archive with an optional password for garbled (encrypted) entries. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries found in the archive (both files and directories, excluding the main archive comment header). | -| `Dispose` | `void Dispose()` | | -| `ExtractEntry` | `byte[] ExtractEntry(ArjEntry entry)` | Extracts the data for the specified entry and verifies its CRC-32. | - -#### `ArjWriter` - -Creates ARJ archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArjWriter` | `ArjWriter(byte method = 0, string password = null)` | Initializes a new `ArjWriter`. | -| `ArchiveComment` | `string ArchiveComment { get; set; }` | Gets or sets the comment embedded in the main archive header. | -| `AddDirectory` | `void AddDirectory(string dirName)` | Adds a directory entry to the archive. | -| `AddFile` | `void AddFile(string fileName, byte[] data, DateTime lastModified = null)` | Adds a file entry to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, byte method = 0, string password = null)` | Creates an ARJ archive split into multiple volumes. | -| `ToArray` | `byte[] ToArray()` | Creates the archive as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the archive to the specified stream. | - -### Namespace `FileFormat.Avi` - -[`AviFormatDescriptor`](#aviformatdescriptor) · [`AviLayoutMap`](#avilayoutmap) · [`AviOptimizer`](#avioptimizer) · [`AviReader`](#avireader) · [`AviReader.ChunkEntry`](#avireaderchunkentry) · [`AviReader.ParsedAvi`](#avireaderparsedavi) · [`AviReader.Track`](#avireadertrack) - -#### `AviFormatDescriptor` - -Exposes an AVI file as an archive: `FULL.avi`, one entry per demuxed stream (video blob with codec-FourCC extension, audio blob as either a synthesised WAV for PCM or raw bytes for compressed codecs), and `metadata.ini` with FourCC/dimensions/duration info. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFileInternalChunkMover`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AviFormatDescriptor` | `AviFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `AviLayoutMap` - -Walks an AVI (RIFF) file's top-level chunk structure and emits `DefragBlockInfo` tiles. The RIFF header is MetadataReserved, hdrl is MetadataReserved, each chunk in movi is Used (named by stream type), and idx1 is MetadataReserved. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream file)` | | - -#### `AviOptimizer` - -AVI optimizer that moves the idx1 (index) chunk before the movi (data) list, enabling faster seeking. Patches idx1 offsets to account for the positional change. Analogous to MP4 fast-start (moov before mdat). - -Implements `IFileInternalChunkMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AviOptimizer` | `AviOptimizer()` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `AviReader` - -RIFF/AVI container demuxer. Walks the tree — `RIFF` → `AVI ` → both `LIST/hdrl` (`avih` + one `LIST/strl` per stream) and `LIST/movi` (the actual chunk data, 4-char stream-id prefixed). Tracks are returned with their FourCC, BITMAPINFOHEADER / WAVEFORMATEX payload, and a concatenation of sample bytes plus individual frame chunks in `Chunks`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AviReader` | `AviReader()` | | -| `Read` | `ParsedAvi Read(ReadOnlySpan data)` | | - -#### `AviReader.ChunkEntry` - -One movi chunk belonging to a track (a single video frame or audio packet). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChunkEntry` | `ChunkEntry(string ChunkId, byte[] Data)` | One movi chunk belonging to a track (a single video frame or audio packet). | -| `ChunkId` | `string ChunkId { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | - -#### `AviReader.ParsedAvi` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ParsedAvi` | `ParsedAvi(int Width, int Height, uint MicroSecPerFrame, uint TotalFrames, IReadOnlyList Tracks)` | | -| `Height` | `int Height { get; init; }` | | -| `MicroSecPerFrame` | `uint MicroSecPerFrame { get; init; }` | | -| `TotalFrames` | `uint TotalFrames { get; init; }` | | -| `Tracks` | `IReadOnlyList Tracks { get; init; }` | | -| `Width` | `int Width { get; init; }` | | - -#### `AviReader.Track` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Track` | `Track(int Index, string StreamType, uint Handler, byte[] Format, int Width, int Height, int AudioChannels, int AudioSampleRate, int AudioBitsPerSample, int AudioFormatTag, int AudioBlockAlign, byte[] Data, IReadOnlyList Chunks)` | | -| `AudioBitsPerSample` | `int AudioBitsPerSample { get; init; }` | | -| `AudioBlockAlign` | `int AudioBlockAlign { get; init; }` | | -| `AudioChannels` | `int AudioChannels { get; init; }` | | -| `AudioFormatTag` | `int AudioFormatTag { get; init; }` | | -| `AudioSampleRate` | `int AudioSampleRate { get; init; }` | | -| `Chunks` | `IReadOnlyList Chunks { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Format` | `byte[] Format { get; init; }` | | -| `Handler` | `uint Handler { get; init; }` | | -| `Height` | `int Height { get; init; }` | | -| `Index` | `int Index { get; init; }` | | -| `StreamType` | `string StreamType { get; init; }` | | -| `Width` | `int Width { get; init; }` | | - -### Namespace `FileFormat.Ba2` - -[`Ba2Entry`](#ba2entry) · [`Ba2FormatDescriptor`](#ba2formatdescriptor) · [`Ba2Reader`](#ba2reader) · [`Ba2Writer`](#ba2writer) · [`BethesdaLookup3`](#bethesdalookup3) - -#### `Ba2Entry` - -One file record inside a BA2 GNRL archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ba2Entry` | `Ba2Entry()` | | -| `DirHash` | `uint DirHash { get; init; }` | Lookup3 hash of the lowercase directory portion (no leading/trailing slash). | -| `Ext` | `string Ext { get; init; }` | Up to 4 ASCII characters of the lowercase extension, no leading dot, trimmed of trailing NULs. | -| `Flags` | `uint Flags { get; init; }` | Per-record flags. Typically 0 for GNRL archives. | -| `NameHash` | `uint NameHash { get; init; }` | Lookup3 hash of the lowercase basename without extension. | -| `Name` | `string Name { get; init; }` | Full relative path with backslash separators, e.g. `textures\effects\smoke01.dds`. | -| `Offset` | `long Offset { get; init; }` | Absolute byte offset where this file's payload starts in the archive. | -| `PackedSize` | `long PackedSize { get; init; }` | Compressed byte length, or 0 when the file is stored uncompressed. | -| `Size` | `long Size { get; init; }` | Original (uncompressed) byte length. | - -#### `Ba2FormatDescriptor` - -Bethesda Archive v2 (BA2, "BTDX" magic) — asset archive introduced with Fallout 4 (GNRL general and DX10 texture variants). References: `https://github.com/Guekka/bsa` — bsa — maintained open-source C++ library reading/writing BSA and BA2BA2 layout documented by the xEdit/BSArch project and the Fallout 4 modding community — Bethesda never published a spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ba2FormatDescriptor` | `Ba2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `Ba2Reader` - -Reads a BA2 (Bethesda Archive v2) GNRL archive — Fallout 4 / Skyrim SE / Starfield (v1). DX10 texture archives are not supported by this reader. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ba2Reader` | `Ba2Reader(Stream stream, bool leaveOpen = false)` | Parses the BA2 header, validates GNRL type, and loads all records and names. | -| `Entries` | `IReadOnlyList Entries { get; }` | All file records, in archive order. | -| `Version` | `uint Version { get; }` | BA2 archive version (1 = FO4/SSE; 7/8 are Starfield variants). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(Ba2Entry entry)` | Returns the decompressed payload of the given entry. When `PackedSize` is 0 the file is stored verbatim; otherwise it is a zlib stream of `PackedSize` bytes. | - -#### `Ba2Writer` - -Builds a BA2 GNRL archive (BTDX v1). DX10 texture archives are not produced by this writer. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ba2Writer` | `Ba2Writer(Stream stream, bool leaveOpen = false, bool compress = true)` | | -| `AddEntry` | `void AddEntry(string path, byte[] data)` | Buffers an entry to be written on Finish/Dispose. `path` is normalised to backslash separators. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Flushes all buffered entries to the output stream and writes the BA2 header, records, payloads, and name table. | - -#### `BethesdaLookup3` - -Bob Jenkins' lookup3 hash, byte-stream variant. Bethesda hashes BA2 directory and basename strings with this function over the lowercase UTF-8 (effectively ASCII) bytes of the path component. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HashLower` | `static uint HashLower(string text)` | Hashes the lowercase ASCII form of `text`. Used for both directory and basename hashes. | -| `Hash` | `static uint Hash(ReadOnlySpan bytes)` | Hashes the given UTF-8/ASCII bytes with lookup3 (initval = 0). | - -### Namespace `FileFormat.Balz` - -[`BalzFormatDescriptor`](#balzformatdescriptor) · [`BalzStream`](#balzstream) - -#### `BalzFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BalzFormatDescriptor` | `BalzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BalzStream` - -BALZ: ROLZ compressor by Ilya Muravyov. Format: 4-byte big-endian uncompressed size, then arithmetic-coded ROLZ bitstream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Bcm` - -[`BcmFormatDescriptor`](#bcmformatdescriptor) · [`BcmStream`](#bcmstream) - -#### `BcmFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcmFormatDescriptor` | `BcmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BcmStream` - -BCM: Ilya Muravyov's BWT + MTF + Context Mixing compressor. Format: 4-byte magic "BCM!" (raw), then all data (block sizes, BWT primary index, bytes, EOF marker, CRC32) encoded through an arithmetic coder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Big` - -[`BigEntry`](#bigentry) · [`BigFormatDescriptor`](#bigformatdescriptor) · [`BigReader`](#bigreader) · [`BigWriter`](#bigwriter) - -#### `BigEntry` - -Represents a single file entry in a BIG archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BigEntry` | `BigEntry()` | | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the absolute byte offset of the entry data within the archive stream. | -| `Path` | `string Path { get; init; }` | Gets the full path of the entry within the archive, using forward slashes. | -| `Size` | `int Size { get; init; }` | Gets the uncompressed size of the entry data in bytes. | - -#### `BigFormatDescriptor` - -EA BIG/BIGF archive — resource container used across Electronic Arts titles (Command & Conquer generation and later). References: `https://wiki.multimedia.cx/index.php/Electronic_Arts_Formats` — MultimediaWiki — community documentation of EA container formatsFinalBIG and the EA modding community's unpackers — de-facto references; EA never published a spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BigFormatDescriptor` | `BigFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `BigReader` - -Reads entries from an EA Games BIG archive (BIGF or BIG4 variant). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BigReader` | `BigReader(Stream stream, bool leaveOpen = false)` | Initializes a new `BigReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive. | -| `IsBig4` | `bool IsBig4 { get; }` | Gets whether this archive uses the BIG4 (little-endian) variant. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(BigEntry entry)` | Extracts the raw data for a given entry. | - -#### `BigWriter` - -Writes entries to an EA Games BIG archive (BIGF variant, big-endian offsets/sizes). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BigWriter` | `BigWriter(Stream output, bool leaveOpen = false)` | Initializes a new `BigWriter` targeting the given stream. | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalises and writes the complete BIGF archive to the output stream. | - -### Namespace `FileFormat.BinHex` - -[`BinHexFormatDescriptor`](#binhexformatdescriptor) · [`BinHexReader`](#binhexreader) · [`BinHexWriter`](#binhexwriter) - -#### `BinHexFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinHexFormatDescriptor` | `BinHexFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BinHexReader` - -Decodes BinHex 4.0 (.hqx) encoded streams back to their original Mac binary form. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinHexReader` | `BinHexReader()` | | -| `Decode` | `static ValueTuple Decode(Stream input)` | Decodes a BinHex 4.0 encoded stream and returns the file components. | - -#### `BinHexWriter` - -Encodes files into BinHex 4.0 (.hqx) text format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinHexWriter` | `BinHexWriter()` | | -| `Write` | `static void Write(Stream output, string fileName, byte[] dataFork, byte[] resourceFork = null, string fileType = "TEXT", string fileCreator = "ttxt")` | Writes a BinHex 4.0 encoded file to the output stream. | - -### Namespace `FileFormat.BriefLz` - -[`BriefLzFormatDescriptor`](#brieflzformatdescriptor) · [`BriefLzStream`](#brieflzstream) - -#### `BriefLzFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BriefLzFormatDescriptor` | `BriefLzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BriefLzStream` - -Provides static methods for compressing and decompressing data using the BriefLZ algorithm with a blzpack container format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses data from `input` and writes a blzpack-format stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a blzpack-format stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Brotli` - -[`BrotliFormatDescriptor`](#brotliformatdescriptor) · [`BrotliStream`](#brotlistream) - -#### `BrotliFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BrotliFormatDescriptor` | `BrotliFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Compression quality, the single knob the Brotli encoder exposes: `Uncompressed` (store), `Fast`, `Default`, and `Best` (deepest LZ77 search). The optimizer searches these to find the smallest output for the given input. The encoder derives the LZ77 window (lgwin) automatically from the input length, so there is no separate window knob to expose. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BrotliStream` - -Provides Brotli compression and decompression as a stream wrapper (RFC 7932). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses data to Brotli format using the clean-room LZ77+Huffman encoder, falling back to uncompressed meta-blocks when LZ77 wouldn't produce smaller output. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, BrotliCompressionLevel level)` | Compresses data to Brotli format at the specified compression level. | -| `Compress` | `static byte[] Compress(Stream input)` | Compresses data from a stream to Brotli format. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses Brotli data from the given byte span. | -| `Decompress` | `static byte[] Decompress(Stream input)` | Decompresses Brotli data from the given stream. | - -### Namespace `FileFormat.Bsa` - -[`BsaEntry`](#bsaentry) · [`BsaFormatDescriptor`](#bsaformatdescriptor) · [`BsaReader`](#bsareader) · [`BsaReader.BsaFormat`](#bsareaderbsaformat) · [`BsaWriter`](#bsawriter) - -#### `BsaEntry` - -Entry in a BSA/BA2 archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BsaEntry` | `BsaEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `FileName` | `string FileName { get; init; }` | | -| `FolderPath` | `string FolderPath { get; init; }` | | -| `FullPath` | `string FullPath { get; }` | Full path: folder\filename | -| `IsCompressed` | `bool IsCompressed { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `OriginalSize` | `long OriginalSize { get; init; }` | | - -#### `BsaFormatDescriptor` - -Bethesda Softworks Archive (BSA) — asset archive used by The Elder Scrolls (Morrowind through Skyrim) and Fallout 3 / New Vegas. References: `https://en.uesp.net/wiki/Oblivion_Mod:BSA_File_Format` — UESP — BSA v103/v104 format documentation`https://en.uesp.net/wiki/Skyrim_Mod:Archive_File_Format` — UESP — Skyrim-era v104/v105 archive documentation`https://en.uesp.net/wiki/Morrowind_Mod:BSA_File_Format` — UESP — Morrowind v100 variant - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BsaFormatDescriptor` | `BsaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `BsaReader` - -Reads Bethesda Softworks Archive (BSA) files. Supports TES3 (Morrowind), TES4/FO3/SSE (Oblivion through Skyrim SE), and BA2 (Fallout 4/76). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BsaReader` | `BsaReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Format` | `BsaFormat Format { get; }` | | -| `Extract` | `byte[] Extract(BsaEntry entry)` | Extracts entry data. | - -#### `BsaReader.BsaFormat` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Tes3` | `0` | | -| `Tes4` | `1` | | -| `Ba2` | `2` | | - -#### `BsaWriter` - -Creates BSA archives in TES4 format (version 105, Skyrim SE compatible). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BsaWriter` | `BsaWriter(Stream stream, bool leaveOpen = false, bool compress = false)` | | -| `AddFile` | `void AddFile(string path, byte[] data)` | | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | | - -### Namespace `FileFormat.Bsc` - -[`BscFormatDescriptor`](#bscformatdescriptor) · [`BscStream`](#bscstream) - -#### `BscFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BscFormatDescriptor` | `BscFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `BscStream` - -BSC (libbsc) stream implementation. File layout: [0..3] magic "bsc1" (0x62 0x73 0x63 0x31) [4..7] int32 LE: block count Per block: BSC_BLOCK_HEADER (10 bytes): [0..7] int64 LE: blockOffset [8] int8: recordSize [9] int8: sortingContexts Internal header (28 bytes = 7 × int32 LE): blockSize, dataSize, mode, index, adler32_data, adler32_compressed, adler32_header Compressed payload bytes - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Bzip2` - -[`Bzip2BuildingBlock`](#bzip2buildingblock) · [`Bzip2FormatDescriptor`](#bzip2formatdescriptor) · [`Bzip2Stream`](#bzip2stream) - -#### `Bzip2BuildingBlock` - -Exposes bzip2 as a benchmarkable building block. Produces a complete bzip2 stream ("BZh" signature, block-size digit, one or more Burrows-Wheeler blocks and the stream footer carrying the combined CRC), so the payload is self-terminating and no extra uncompressed-size header is prepended. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Bzip2BuildingBlock` | `Bzip2BuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `Bzip2FormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IFormatValidator`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Bzip2FormatDescriptor` | `Bzip2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Block size 1..9 in units of 100 KB (1 = 100 KB blocks, 9 = 900 KB blocks). A larger block lets the Burrows-Wheeler transform see more context at once, which only helps once the input is bigger than the block. The optimizer searches these to find the smallest output for the given input. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `Bzip2Stream` - -Stream for reading and writing bzip2 format data. - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Bzip2Stream` | `Bzip2Stream(Stream stream, CompressionStreamMode mode, int blockSize100k = 9, bool leaveOpen = false)` | Initializes a new `Bzip2Stream`. | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | - -### Namespace `FileFormat.Cab` - -[`CabCompressionType`](#cabcompressiontype) · [`CabConstants`](#cabconstants) · [`CabEntry`](#cabentry) · [`CabFormatDescriptor`](#cabformatdescriptor) · [`CabLayoutMap`](#cablayoutmap) · [`CabReader`](#cabreader) · [`CabWriter`](#cabwriter) - -#### `CabCompressionType` - -Compression types used in the CFFOLDER `typeCompress` field. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No compression — data is stored verbatim. | -| `MsZip` | `1` | MSZIP compression (Deflate with 32 KB blocks). | -| `Quantum` | `2` | Quantum compression. | -| `Lzx` | `3` | LZX compression — reader uses `LzxDecompressor`, writer uses `BB_Lzx`. | - -#### `CabConstants` - -Constants for the Microsoft Cabinet (CAB) file format (MS-CAB-COMPRESS). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AttribArchive` | `const ushort AttribArchive` | File attribute: modified since last backup (archive bit). | -| `AttribHidden` | `const ushort AttribHidden` | File attribute: hidden. | -| `AttribReadOnly` | `const ushort AttribReadOnly` | File attribute: read-only. | -| `AttribSystem` | `const ushort AttribSystem` | File attribute: system file. | -| `AttribUtf8` | `const ushort AttribUtf8` | File attribute: UTF-8 name encoding. | -| `DataFixedSize` | `const int DataFixedSize` | Size of the fixed part of a CFDATA structure (before compressed data). | -| `FileFixedSize` | `const int FileFixedSize` | Size of the fixed part of a CFFILE structure (before the name). | -| `FlagNextCabinet` | `const ushort FlagNextCabinet` | Cabinet flags: bit 1 — next cabinet present. | -| `FlagPrevCabinet` | `const ushort FlagPrevCabinet` | Cabinet flags: bit 0 — previous cabinet present. | -| `FlagReserveFields` | `const ushort FlagReserveFields` | Cabinet flags: bit 2 — reserve fields present. | -| `FolderSize` | `const int FolderSize` | Size of the CFFOLDER structure in bytes (fixed fields only). | -| `HeaderSize` | `const int HeaderSize` | Size of the CFHEADER structure in bytes (fixed fields only). | -| `VersionMajor` | `const byte VersionMajor` | Cabinet version major number. | -| `VersionMinor` | `const byte VersionMinor` | Cabinet version minor number. | -| `Signature` | `static ReadOnlySpan Signature { get; }` | CAB file signature: "MSCF" (0x4D, 0x53, 0x43, 0x46). | - -#### `CabEntry` - -Represents a file entry stored inside a Microsoft Cabinet (CAB) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Attributes` | `ushort Attributes { get; }` | Gets the file attribute flags. | -| `Date` | `ushort Date { get; }` | Gets the MS-DOS encoded date field. | -| `FileName` | `string FileName { get; }` | Gets the name of the file as stored in the archive. | -| `FolderIndex` | `ushort FolderIndex { get; }` | Gets the zero-based index of the folder that contains this file. | -| `FolderOffset` | `uint FolderOffset { get; }` | Gets the uncompressed byte offset of this file within its folder. | -| `LastModified` | `DateTime? LastModified { get; }` | Gets the last-modified date/time derived from the MS-DOS date and time fields. Returns `null` when the encoded value is invalid. | -| `Time` | `ushort Time { get; }` | Gets the MS-DOS encoded time field. | -| `UncompressedSize` | `uint UncompressedSize { get; }` | Gets the uncompressed size of the file in bytes. | - -#### `CabFormatDescriptor` - -Microsoft Cabinet (CAB) archive — CFHEADER/CFFOLDER/CFFILE structures with MSZIP/Quantum/LZX-compressed folders. References: [MS-CAB]: Cabinet File Format — Microsoft Open Specifications`https://www.cabextract.org.uk/libmspack/` — libmspack — maintained open-source CAB implementation`https://en.wikipedia.org/wiki/Cabinet_(file_format)` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CabFormatDescriptor` | `CabFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the CAB in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the CAB per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single CAB entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's uncompressed size. | - -#### `CabLayoutMap` - -Walks CAB CFHEADER, CFFOLDER entries, CFFILE entries, and CFDATA blocks to emit the byte-level layout of the cabinet archive as `DefragBlockInfo` tiles. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `CabReader` - -Reads and extracts files from a Microsoft Cabinet (CAB) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CabReader` | `CabReader(Stream stream, bool leaveOpen = false)` | Opens a CAB archive from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of file entries in the cabinet. | -| `Dispose` | `void Dispose()` | | -| `ExtractEntry` | `byte[] ExtractEntry(CabEntry entry)` | Extracts the content of `entry` and returns it as a byte array. | - -#### `CabWriter` - -Creates Microsoft Cabinet (CAB) archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CabWriter` | `CabWriter(CabCompressionType compressionType = 1, DeflateCompressionLevel deflateLevel = 6, int lzxWindowBits = 15, int quantumWindowBits = 15)` | Initializes a new `CabWriter`. | -| `CabinetIndex` | `ushort CabinetIndex { get; set; }` | Gets or sets the zero-based cabinet index within its set. Defaults to 0. | -| `SetId` | `ushort SetId { get; set; }` | Gets or sets the cabinet set identifier. Defaults to 0. | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? lastModified = null, ushort attributes = 32)` | Adds a file to the cabinet. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, CabCompressionType compressionType = 1)` | Creates a CAB archive split into multiple volumes. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the complete cabinet archive to `output`. | - -### Namespace `FileFormat.Cbr` - -[`CbrFormatDescriptor`](#cbrformatdescriptor) - -#### `CbrFormatDescriptor` - -Comic book archive — a RAR container of sequentially named page images, conventionally suffixed .cbr. References: `https://en.wikipedia.org/wiki/Comic_book_archive` — the .cbr/.cbz naming convention`https://www.rarlab.com/technote.htm` — RAR 5.x technote — the underlying container format - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CbrFormatDescriptor` | `CbrFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) pages inside an existing CBR archive. Delegates to the RAR in-place editors (CBR is a RAR variant): a pure add of new names takes the genuine byte-additive append (`RarInPlaceAdder`), a same-name update excises the old block first (`RarInPlaceRemover`). Any case the in-place path cannot serve byte-additively falls back to the verified extract -> re-create rebuild. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to RAR (CBR is a RAR variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to RAR (CBR is a RAR variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named pages. Non-solid FILE blocks are excised by the genuine in-place remover (`RarInPlaceRemover`); anything it cannot serve byte-additively falls back to the verified extract -> re-create rebuild. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: gaps not covered by a live extent in the RAR layout map (markers, block headers, packed data and ENDARC are live and preserved). Cluster-tip wiping is N/A (RAR packs blocks back to back). | - -### Namespace `FileFormat.Cbz` - -[`CbzFormatDescriptor`](#cbzformatdescriptor) - -#### `CbzFormatDescriptor` - -Comic book archive — a ZIP container of sequentially named page images, conventionally suffixed .cbz. References: `https://en.wikipedia.org/wiki/Comic_book_archive` — the .cbr/.cbz naming convention`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE APPNOTE — the underlying ZIP container spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CbzFormatDescriptor` | `CbzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing CBZ archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (CBZ is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (CBZ is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Chm` - -[`ChmEntry`](#chmentry) · [`ChmFormatDescriptor`](#chmformatdescriptor) · [`ChmReader`](#chmreader) · [`ChmWriter`](#chmwriter) - -#### `ChmEntry` - -Represents a single entry (file) within a CHM archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChmEntry` | `ChmEntry()` | | -| `Offset` | `long Offset { get; init; }` | The byte offset of this entry within its content section. | -| `Path` | `string Path { get; init; }` | The full path of the entry within the CHM. | -| `Section` | `int Section { get; init; }` | The content section index (0 = uncompressed, 1 = LZX compressed). | -| `Size` | `long Size { get; init; }` | The uncompressed size of the entry in bytes. | - -#### `ChmFormatDescriptor` - -Microsoft Compiled HTML Help (CHM) — ITSF/ITSP container with LZX-compressed content sections. References: Matthew Russotto's "Microsoft's HTML Help (.chm) format" — the classic unofficial specification (russotto.net)`https://www.cabextract.org.uk/libmspack/` — libmspack — maintained open-source CHM decoder`https://en.wikipedia.org/wiki/Microsoft_Compiled_HTML_Help` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChmFormatDescriptor` | `ChmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the CHM archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the CHM archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `ChmReader` - -Read-only reader for Microsoft Compiled HTML Help (.chm) files. Supports section 0 (uncompressed) and section 1 (LZX-compressed) entries. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChmReader` | `ChmReader(Stream stream)` | Opens and parses the CHM directory from `stream`. The stream must remain open for the lifetime of this reader. | -| `Entries` | `IReadOnlyList Entries { get; }` | All directory entries found in the CHM. | -| `Extract` | `byte[] Extract(ChmEntry entry)` | Extracts the raw bytes for the given `entry`. | - -#### `ChmWriter` - -Writes a Microsoft Compiled HTML Help (.chm) file. Supports two modes: Stored (default): all files go into section 0 (uncompressed).LZX: files are LZX-compressed into section 1 with a reset table. Internal meta-entries (ControlData, ResetTable, Content) live in section 0. Both modes roundtrip through `ChmReader`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChmWriter` | `ChmWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output, bool useLzx = false)` | | - -### Namespace `FileFormat.Cmix` - -[`CmixFormatDescriptor`](#cmixformatdescriptor) · [`CmixStream`](#cmixstream) - -#### `CmixFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CmixFormatDescriptor` | `CmixFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `CmixStream` - -cmix file format by Byron Knoll. Format: Byte 0: bit7=dict flag (0), bits 0-6 = upper 7 bits of 39-bit file size Bytes 1-4: lower 32 bits of file size (big-endian) If size >= 10000: 32-byte vocabulary bitmap Then: arithmetic-coded bitstream (order-0 adaptive model, bit-tree 255 nodes) - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Collada` - -[`ColladaFormatDescriptor`](#colladaformatdescriptor) - -#### `ColladaFormatDescriptor` - -Collada (.dae) — an XML interchange format from the Khronos Group for 3D assets. Root element is `` with the `xmlns` typically set to `http://www.collada.org/2005/11/COLLADASchema`. Top-level children are `library_*` elements (geometries, images, materials, effects, animations, visual_scenes …) plus `asset` and `scene`. We surface the full document, a `metadata.ini` summary (version + library counts), and one `library_*.xml` fragment per top-level library. References: `https://www.khronos.org/collada/` — Khronos COLLADA portal — specification downloadsISO/IEC 17506:2012 — COLLADA 1.5 as an international standard`https://en.wikipedia.org/wiki/COLLADA` — format overview - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ColladaFormatDescriptor` | `ColladaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Read-only archive capabilities. | -| `Category` | `FormatCategory Category { get; }` | Archive category. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | No compound extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default extension. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Display name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Known extensions. | -| `Family` | `AlgorithmFamily Family { get; }` | Archive family. | -| `Id` | `string Id { get; }` | Format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | XML content-sniffing magic: ` Methods { get; }` | Stored only. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a tar compound format. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.CompactPro` - -[`CompactProEntry`](#compactproentry) · [`CompactProFormatDescriptor`](#compactproformatdescriptor) · [`CompactProReader`](#compactproreader) · [`CompactProWriter`](#compactprowriter) - -#### `CompactProEntry` - -Represents a single entry in a Compact Pro (.cpt) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompactProEntry` | `CompactProEntry()` | | -| `CreatedDate` | `DateTime CreatedDate { get; init; }` | Gets or sets the creation date. | -| `DataForkCompressedSize` | `uint DataForkCompressedSize { get; init; }` | Gets or sets the compressed data fork size in bytes. | -| `DataForkCrc` | `ushort DataForkCrc { get; init; }` | Gets or sets the CRC-16 of the decompressed data fork. | -| `DataForkMethod` | `byte DataForkMethod { get; init; }` | Gets or sets the compression method for the data fork. | -| `DataForkSize` | `uint DataForkSize { get; init; }` | Gets or sets the uncompressed data fork size in bytes. | -| `FileCreator` | `uint FileCreator { get; init; }` | Gets or sets the Mac four-character creator code. | -| `FileName` | `string FileName { get; init; }` | Gets or sets the filename (up to 63 characters). | -| `FileType` | `uint FileType { get; init; }` | Gets or sets the Mac four-character file type code (e.g. 0x54455854 for 'TEXT'). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets or sets whether this entry is a directory. | -| `ModifiedDate` | `DateTime ModifiedDate { get; init; }` | Gets or sets the modification date. | -| `ResourceForkCompressedSize` | `uint ResourceForkCompressedSize { get; init; }` | Gets or sets the compressed resource fork size in bytes. | -| `ResourceForkCrc` | `ushort ResourceForkCrc { get; init; }` | Gets or sets the CRC-16 of the decompressed resource fork. | -| `ResourceForkMethod` | `byte ResourceForkMethod { get; init; }` | Gets or sets the compression method for the resource fork. | -| `ResourceForkSize` | `uint ResourceForkSize { get; init; }` | Gets or sets the uncompressed resource fork size in bytes. | - -#### `CompactProFormatDescriptor` - -Compact Pro archive (Bill Goodman / Cyclos) — classic-Mac compressor that rivaled StuffIt in the early 1990s. References: `https://github.com/MacPaw/XADMaster` — The Unarchiver's XADMaster — open-source Compact Pro reader`https://en.wikipedia.org/wiki/Compact_Pro` — format history - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompactProFormatDescriptor` | `CompactProFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the Compact Pro archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the Compact Pro archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single Compact Pro entry as a bounded read-only stream. The reader produces the decoded data-fork bytes; the matched bytes are wrapped in a `BoundedEntryStream` sized to the data fork's logical length. | - -#### `CompactProReader` - -Reads entries from a Compact Pro (.cpt) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompactProReader` | `CompactProReader(Stream stream, bool leaveOpen = false)` | Opens a Compact Pro archive from the given stream and parses the entry directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of file entries found in the archive. | -| `Dispose` | `void Dispose()` | | -| `ExtractResourceFork` | `byte[] ExtractResourceFork(CompactProEntry entry)` | Extracts and decompresses the resource fork of the specified entry. | -| `Extract` | `byte[] Extract(CompactProEntry entry)` | Extracts and decompresses the data fork of the specified entry. | - -#### `CompactProWriter` - -Creates a Compact Pro (.cpt) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompactProWriter` | `CompactProWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `CompactProWriter`. | -| `AddDirectory` | `void AddDirectory(string name)` | Begins a new directory in the archive. Must be paired with `EndDirectory`. | -| `AddFile` | `void AddFile(string name, byte[] data, byte[] resourceFork = null, DateTime? modified = null)` | Adds a file entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `EndDirectory` | `void EndDirectory()` | Ends the current directory. Must be paired with a prior `AddDirectory` call. | - -### Namespace `FileFormat.Compress` - -[`CompressFormatDescriptor`](#compressformatdescriptor) · [`CompressStream`](#compressstream) - -#### `CompressFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressFormatDescriptor` | `CompressFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `CompressStream` - -Stream for reading and writing Unix compress (.Z) format data. Uses LZW compression with variable-width codes (9-16 bits) in LSB-first order. - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressStream` | `CompressStream(Stream stream, CompressionStreamMode mode, int maxBits = 16, bool blockMode = true, bool leaveOpen = false)` | Initializes a new `CompressStream`. | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | - -### Namespace `FileFormat.Cpio` - -[`CpioEntry`](#cpioentry) · [`CpioFormatDescriptor`](#cpioformatdescriptor) · [`CpioModifier`](#cpiomodifier) · [`CpioReader`](#cpioreader) · [`CpioWriter`](#cpiowriter) - -#### `CpioEntry` - -Represents a single entry in a cpio archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpioEntry` | `CpioEntry()` | | -| `Checksum` | `uint Checksum { get; set; }` | Gets or sets the CRC-32 checksum (for CRC format only). | -| `DevMajor` | `uint DevMajor { get; set; }` | Gets or sets the device major number. | -| `DevMinor` | `uint DevMinor { get; set; }` | Gets or sets the device minor number. | -| `FileSize` | `long FileSize { get; set; }` | Gets or sets the file size in bytes. | -| `Gid` | `uint Gid { get; set; }` | Gets or sets the owner GID. | -| `Inode` | `uint Inode { get; set; }` | Gets or sets the inode number. | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets whether this entry is a directory. | -| `IsRegularFile` | `bool IsRegularFile { get; }` | Gets whether this entry is a regular file. | -| `IsSymlink` | `bool IsSymlink { get; }` | Gets whether this entry is a symbolic link. | -| `Mode` | `uint Mode { get; set; }` | Gets or sets the file mode (permissions + type). | -| `ModificationTime` | `uint ModificationTime { get; set; }` | Gets or sets the modification time (Unix timestamp). | -| `Name` | `string Name { get; set; }` | Gets or sets the file name. | -| `NumLinks` | `uint NumLinks { get; set; }` | Gets or sets the number of hard links. | -| `RDevMajor` | `uint RDevMajor { get; set; }` | Gets or sets the rdev major number (for device files). | -| `RDevMinor` | `uint RDevMinor { get; set; }` | Gets or sets the rdev minor number (for device files). | -| `Uid` | `uint Uid { get; set; }` | Gets or sets the owner UID. | - -#### `CpioFormatDescriptor` - -cpio archive — Unix copy-in/copy-out container (binary, portable-ASCII odc and newc variants). References: `https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html` — POSIX pax — defines the cpio interchange headers`cpio(5)` man page (libarchive / FreeBSD) — documents the binary, odc, newc and crc variants`https://en.wikipedia.org/wiki/Cpio` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpioFormatDescriptor` | `CpioFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files via `CpioModifier`. | -| `CreateFromStreams` | `void CreateFromStreams(Stream target, IEnumerable inputs, FormatCreateOptions options)` | Large-file-safe streaming variant of `Create`. The cpio "new" ASCII header encodes each member's size before its payload, so the pre-known `Size` lets the writer emit the header and then copy the payload in 64 KB chunks via `AddStreamingFile` — peak memory is bounded by the copy buffer regardless of member size. Inode allocation, headers, and padding match `Create` byte-for-byte for the same inputs. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the CPIO archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the CPIO archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single CPIO entry as a bounded read-only `Stream`. CPIO stores each entry uncompressed; the reader's `ReadAll` walk surfaces (entry, byte[]) tuples which the bounded wrapper sizes to the entry's file size. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries via `CpioModifier`. | - -#### `CpioModifier` - -Random-access in-place modifier for CPIO archives (newc/odc "070701"/"070702"). Add appends a new entry just before the trailer — touches only the new entry's bytes plus the (small) trailer rewrite. Remove walks the entry chain to locate the target, then shifts trailing bytes forward to close the gap (necessary because CPIO has no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream cpio, string name, byte[] data)` | Appends a regular file entry. Walks the existing entry chain to find the trailer entry, writes the new header + data + padding in its place, then re-writes the trailer and truncates to the new length. | -| `RemoveFile` | `static bool RemoveFile(Stream cpio, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. The trailing portion of the file is shifted forward to close the gap (CPIO has no central directory; readers walk entries sequentially, so we must compact). | - -#### `CpioReader` - -Reads entries from a cpio archive in the "new" (SVR4) ASCII format. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpioReader` | `CpioReader(Stream stream, bool leaveOpen = false)` | Initializes a new `CpioReader` from a stream. | -| `CopyCurrentEntryData` | `void CopyCurrentEntryData(Stream destination)` | Copies the current entry's data to `destination` (or discards it when null) and consumes the 4-byte alignment padding. | -| `Dispose` | `void Dispose()` | | -| `ReadAll` | `List> ReadAll()` | Reads all entries from the archive. | -| `ReadEntry` | `CpioEntry ReadEntry(out byte[] data)` | Reads the next entry from the archive. | -| `ReadNextHeader` | `CpioEntry ReadNextHeader()` | Reads the next entry's header, leaving the stream positioned at its data. Returns null at the trailer. Pair with `CopyCurrentEntryData`, which must be called before the next header even for skipped entries so the reader stays aligned. | - -#### `CpioWriter` - -Creates a cpio archive in the "new" (SVR4) ASCII format. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpioWriter` | `CpioWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `CpioWriter`. | -| `AddDirectory` | `void AddDirectory(string name, uint mode = 16877)` | Adds a directory entry. | -| `AddFile` | `void AddFile(string name, ReadOnlySpan data, uint mode = 33188)` | Adds a file entry. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Stream data, uint mode = 33188)` | Adds a file entry whose payload is streamed from `data` in bounded 64 KB chunks rather than buffered into RAM. The cpio "new" header encodes the file size before the payload, so the pre-known `size` is written into the header, then exactly `size` bytes are copied, then the 4-byte alignment pad. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the trailer and finishes the archive. | - -### Namespace `FileFormat.Crate` - -[`CrateFormatDescriptor`](#crateformatdescriptor) - -#### `CrateFormatDescriptor` - -Descriptor for a Rust crate package (`.crate`) — a gzipped TAR containing a single `name-version/` top-level directory with a `Cargo.toml` and the crate's source files. References: `https://doc.rust-lang.org/cargo/reference/registries.html#publish` — registry publish API, defining what a `.crate` upload contains`https://doc.rust-lang.org/cargo/` — The Cargo Book (the `cargo package` command produces these archives) - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrateFormatDescriptor` | `CrateFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates a Rust crate package (`.crate`) at `output` containing `inputs`. A canonical `/` top-level directory is enforced: | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Crunch` - -[`CrunchConstants`](#crunchconstants) · [`CrunchFormatDescriptor`](#crunchformatdescriptor) · [`CrunchStream`](#crunchstream) - -#### `CrunchConstants` - -Constants for the CP/M Crunch compression format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Magic1` | `const byte Magic1` | First magic byte (0x76). | -| `Magic2` | `const byte Magic2` | Second magic byte (0xFE). | -| `MaxBits` | `const int MaxBits` | Maximum LZW code width (12 bits). | -| `MinBits` | `const int MinBits` | Minimum LZW code width (9 bits). | - -#### `CrunchFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrunchFormatDescriptor` | `CrunchFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `CrunchStream` - -Stream for reading and writing CP/M Crunch (.?Z?) format data. Uses LZW compression with variable-width codes (9-12 bits) in MSB-first order. - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrunchStream` | `CrunchStream(Stream stream, CompressionStreamMode mode, string originalName = null, bool leaveOpen = false)` | Initializes a new `CrunchStream`. | -| `OriginalName` | `string OriginalName { get; }` | Gets the original filename stored in the Crunch header (only set during decompression). | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | - -### Namespace `FileFormat.Crx` - -[`CrxFormatDescriptor`](#crxformatdescriptor) - -#### `CrxFormatDescriptor` - -Chrome extension package (CRX3) — "Cr24" magic + version + protobuf SignedData header followed by the ZIP payload. References: `https://chromium.googlesource.com/chromium/src/+/main/components/crx_file/` — Chromium crx_file component — `crx3.proto` defines the header`https://developer.chrome.com/docs/extensions` — Chrome extensions documentation portal - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrxFormatDescriptor` | `CrxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: strips the CRX envelope, defrags the inner ZIP, then re-emits. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: strips the CRX envelope, defrags the inner ZIP, then re-emits. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | - -### Namespace `FileFormat.Csc` - -[`CscFormatDescriptor`](#cscformatdescriptor) · [`CscStream`](#cscstream) - -#### `CscFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CscFormatDescriptor` | `CscFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `CscStream` - -CSC: Context Stream Compression by Fu Siyuan. Format: 10-byte big-endian property header + 4-byte uncompressed size, then range-coded LZ77. Header layout: uint32 dict_size | uint24 csc_blocksize | uint24 raw_blocksize | uint32 actual_size - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Deb` - -[`DebCompression`](#debcompression) · [`DebConstants`](#debconstants) · [`DebEntry`](#debentry) · [`DebFormatDescriptor`](#debformatdescriptor) · [`DebReader`](#debreader) · [`DebWriter`](#debwriter) - -#### `DebCompression` - -Specifies the compression algorithm used for tar members inside a .deb package. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Gzip` | `0` | Gzip compression (.tar.gz). This is the traditional default. | -| `Xz` | `1` | XZ compression (.tar.xz). | -| `Zstd` | `2` | Zstandard compression (.tar.zst). | -| `Bzip2` | `3` | BZip2 compression (.tar.bz2). | - -#### `DebConstants` - -Constants for the Debian package (.deb) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ControlPrefix` | `const string ControlPrefix` | Prefix for the control archive member name. | -| `DataPrefix` | `const string DataPrefix` | Prefix for the data archive member name. | -| `VersionMemberName` | `const string VersionMemberName` | Name of the version member in the ar archive. | -| `VersionString` | `const string VersionString` | Expected content of the debian-binary member. | - -#### `DebEntry` - -Represents a file entry extracted from a Debian package's data archive. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DebEntry` | `DebEntry(string Path, byte[] Data, bool IsDirectory)` | Represents a file entry extracted from a Debian package's data archive. | -| `Data` | `byte[] Data { get; init; }` | The file contents, or empty for directories. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether this entry is a directory. | -| `Path` | `string Path { get; init; }` | The file path within the package. | - -#### `DebFormatDescriptor` - -Debian binary package (.deb) — an ar archive holding debian-binary, control.tar.* and data.tar.*. References: `deb(5)` man page (dpkg) — the authoritative format description`https://www.debian.org/doc/debian-policy/` — Debian Policy Manual — binary package requirements`https://en.wikipedia.org/wiki/Deb_(file_format)` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DebFormatDescriptor` | `DebFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts the data.tar entries and rebuilds the .deb package. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts the data.tar entries and rebuilds the .deb package. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single DEB entry as a bounded read-only stream. DEB stores its payload inside an inner compressed `data.tar.*` (gz/xz/zst/bz2); the reader already materialises each entry's bytes during enumeration, so the override wraps the matched entry's bytes in a `BoundedEntryStream` sized to its logical length — block padding and adjacent entries cannot leak. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `DebReader` - -Reads Debian package (.deb) files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DebReader` | `DebReader(Stream stream)` | Opens a .deb package from a seekable stream. | -| `RawEntries` | `IReadOnlyList RawEntries { get; }` | Gets the raw ar archive entries. | -| `Dispose` | `void Dispose()` | | -| `GetControlText` | `string GetControlText()` | Gets the control file text (the "control" file inside control.tar.*). | -| `ReadControlEntries` | `IReadOnlyList ReadControlEntries()` | Extracts control metadata files from the control.tar.* member. | -| `ReadDataEntries` | `IReadOnlyList ReadDataEntries()` | Extracts data files from the data.tar.* member. | - -#### `DebWriter` - -Writes Debian package (.deb) files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DebWriter` | `DebWriter(Stream output, DebCompression compression = 0)` | Initializes a new `DebWriter` writing to the given stream. | -| `Write` | `void Write(IReadOnlyList controlFiles, IReadOnlyList dataFiles)` | Writes a complete .deb package. | - -### Namespace `FileFormat.Density` - -[`DensityFormatDescriptor`](#densityformatdescriptor) · [`DensityStream`](#densitystream) · [`DensityStream.Algorithm`](#densitystreamalgorithm) - -#### `DensityFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DensityFormatDescriptor` | `DensityFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `DensityStream` - -Density compression with three algorithms: Chameleon (fastest), Cheetah (balanced), Lion (best ratio). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output, Algorithm algorithm = 2)` | Compresses data with the specified algorithm. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses density-compressed data. | - -#### `DensityStream.Algorithm` - -Compression algorithm. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Chameleon` | `1` | Hash-based direct replacement. Fastest, lowest ratio. | -| `Cheetah` | `2` | Dual-hash with predictions. Balanced speed/ratio. | -| `Lion` | `3` | LZ + entropy coding. Best ratio, still fast. | - -### Namespace `FileFormat.Dicom` - -[`DicomDirFormatDescriptor`](#dicomdirformatdescriptor) · [`DicomFormatDescriptor`](#dicomformatdescriptor) - -#### `DicomDirFormatDescriptor` - -DICOMDIR (DICOM Part 10 chapter 8, "Media Storage Directory") — a DICOM file whose payload is a directory index referencing sibling DICOM files on the same medium. Surfaced as a pseudo-archive: one entry per referenced sibling (resolved relative to the DICOMDIR's own file location), plus a `metadata.ini` summary of the patient / study / series hierarchy. Detection: DICM preamble at offset 128 plus presence of tag (0004,1220) DirectoryRecordSequence. Filename on media is usually "DICOMDIR" with no extension, occasionally `.dcmdir`. References: `https://dicom.nema.org/medical/dicom/current/output/chtml/part10/chapter_8.html` — DICOM PS3.10 chapter 8, "Media Storage Directory" (the defining spec)`https://www.dicomstandard.org/` — the DICOM standard home (NEMA/MITA)`https://en.wikipedia.org/wiki/DICOM` — format overview - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DicomDirFormatDescriptor` | `DicomDirFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | List + extract, multi-entry. | -| `Category` | `FormatCategory Category { get; }` | Archive category — surfaces referenced sibling DICOM files. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | No compound extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default extension (uncommon — usually the file is simply named DICOMDIR). | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Display name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Known extensions. The canonical filename is "DICOMDIR" without extension, so we leave this list intentionally narrow and rely on magic + content sniffing. | -| `Family` | `AlgorithmFamily Family { get; }` | Archive family. | -| `Id` | `string Id { get; }` | Format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | DICM at offset 128 (same as DICOM). Detection further refined by List() parsing. | -| `Methods` | `IReadOnlyList Methods { get; }` | Stored only. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a tar compound format. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `DicomFormatDescriptor` - -Medical DICOM (Part 10) file surfaced as a read-only archive. Walks the data elements (Explicit VR for the file meta, then either Explicit or Implicit VR Little Endian for the body depending on the transfer syntax) and emits the full file, a metadata summary, a per-element tag dump, the raw PixelData payload (or encapsulated fragments), and any overlay data. Does not decode JPEG-compressed pixel data — fragments are surfaced verbatim. References: `https://dicom.nema.org/medical/dicom/current/output/html/part10.html` — DICOM PS3.10 — Media Storage and File Format (the Part 10 file layout parsed here)`https://www.dicomstandard.org` — DICOM standard portal`https://en.wikipedia.org/wiki/DICOM` — format overview - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DicomFormatDescriptor` | `DicomFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.DiskDoubler` - -[`DiskDoublerEntry`](#diskdoublerentry) · [`DiskDoublerFormatDescriptor`](#diskdoublerformatdescriptor) · [`DiskDoublerReader`](#diskdoublerreader) · [`DiskDoublerWriter`](#diskdoublerwriter) - -#### `DiskDoublerEntry` - -Represents a single compressed file stored in a DiskDoubler file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DiskDoublerEntry` | `DiskDoublerEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Gets the compressed size in bytes. | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the absolute byte offset of the compressed data within the source stream. | -| `IsDataFork` | `bool IsDataFork { get; init; }` | Gets whether this entry represents the data fork (as opposed to the resource fork). | -| `Method` | `int Method { get; init; }` | Gets the compression method ID (0 = stored, 1 = RLE, 3 = LZC variant, others = proprietary). | -| `Name` | `string Name { get; init; }` | Gets the original filename. | -| `OriginalSize` | `long OriginalSize { get; init; }` | Gets the original (uncompressed) size in bytes. | - -#### `DiskDoublerFormatDescriptor` - -DiskDoubler compressed file (Salient Software, 1989-1993) — classic-Mac per-file compressor. References: `https://github.com/MacPaw/XADMaster` — The Unarchiver's XADMaster — open-source DiskDoubler decoder`https://en.wikipedia.org/wiki/DiskDoubler` — format history - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DiskDoublerFormatDescriptor` | `DiskDoublerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single DiskDoubler entry as a bounded read-only stream. The reader produces the decoded data; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's original length. | - -#### `DiskDoublerReader` - -Reads the header of a DiskDoubler compressed file and provides access to its data and resource fork entries. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DiskDoublerReader` | `DiskDoublerReader(Stream stream, bool leaveOpen = false)` | Opens a DiskDoubler compressed file from the given stream and parses its header. | -| `HeaderSize` | `const int HeaderSize` | Size of the fixed-length DiskDoubler file header in bytes. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries parsed from the DiskDoubler file header. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DiskDoublerEntry entry)` | Extracts the data for the specified entry. | - -#### `DiskDoublerWriter` - -Writes a DiskDoubler stored (method 0) file. Takes a single data fork payload; resource fork is empty. Roundtrips through `DiskDoublerReader`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DiskDoublerWriter` | `DiskDoublerWriter()` | | -| `SetFile` | `void SetFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Dms` - -[`DmsFormatDescriptor`](#dmsformatdescriptor) · [`DmsHeader`](#dmsheader) · [`DmsReader`](#dmsreader) · [`DmsTrack`](#dmstrack) · [`DmsWriter`](#dmswriter) - -#### `DmsFormatDescriptor` - -Amiga Disk Masher System (DMS) — track-based floppy-disk archiver ubiquitous in the Amiga scene. References: xDMS by Andre R. de la Rocha — open-source DMS extractor and de-facto format reference`https://en.wikipedia.org/wiki/Disk_Masher_System` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmsFormatDescriptor` | `DmsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts the disk image then re-emits the DMS file. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts the disk image then re-emits the DMS file. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `DmsHeader` - -Represents the 56-byte file header of a DMS archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmsHeader` | `DmsHeader()` | | -| `CompressionMode` | `ushort CompressionMode { get; init; }` | Overall compression mode used. | -| `CpuSpeed` | `ushort CpuSpeed { get; init; }` | CPU speed indicator. | -| `CpuType` | `ushort CpuType { get; init; }` | CPU type that created the archive. | -| `CreatedDay` | `ushort CreatedDay { get; init; }` | Creation day (Amiga date format). | -| `CreatedMinute` | `ushort CreatedMinute { get; init; }` | Creation minute within the day. | -| `CreatedTick` | `ushort CreatedTick { get; init; }` | Creation tick within the minute (50ths of a second). | -| `CreatorVersion` | `ushort CreatorVersion { get; init; }` | Creator version number. | -| `DiskType` | `ushort DiskType { get; init; }` | Disk type (0 = standard Amiga DD). | -| `From` | `ushort From { get; init; }` | First track number in the archive. | -| `HighTrack` | `ushort HighTrack { get; init; }` | High track number (valid range end). | -| `InfoFlags` | `uint InfoFlags { get; init; }` | Info flags (bit 0 = locked, bit 1 = noDMS, bit 4 = has info text, etc.). | -| `LowTrack` | `ushort LowTrack { get; init; }` | Low track number (valid range start). | -| `Magic` | `uint Magic { get; init; }` | Magic number (should be 0x444D5321 = "DMS!"). | -| `NeededVersion` | `ushort NeededVersion { get; init; }` | Minimum version needed to extract. | -| `PackedSize` | `uint PackedSize { get; init; }` | Total packed (compressed) data size. | -| `To` | `ushort To { get; init; }` | Last track number in the archive. | -| `UnpackedSize` | `uint UnpackedSize { get; init; }` | Total unpacked (uncompressed) data size. | - -#### `DmsReader` - -Reads and extracts tracks from an Amiga DMS (Disk Masher System) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmsReader` | `DmsReader(Stream stream, bool leaveOpen = false)` | Initializes a new `DmsReader` and parses the archive. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the track entries present in the archive. | -| `Header` | `DmsHeader Header { get; }` | Gets the file header. | -| `Dispose` | `void Dispose()` | | -| `ExtractDisk` | `byte[] ExtractDisk()` | Extracts the entire disk image by concatenating all decompressed tracks in order. | -| `Extract` | `byte[] Extract(DmsTrack track)` | Extracts and decompresses the data for the given track. | - -#### `DmsTrack` - -Represents a track entry within a DMS archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmsTrack` | `DmsTrack()` | | -| `CompressedCrc` | `ushort CompressedCrc { get; init; }` | CRC-16 of the compressed data. | -| `CompressedSize` | `ushort CompressedSize { get; init; }` | Size of the compressed track data in bytes. | -| `CompressionMode` | `byte CompressionMode { get; init; }` | Compression mode used for this track. | -| `DataOffset` | `long DataOffset { get; init; }` | Offset in the stream where the compressed track data starts. | -| `Flags` | `byte Flags { get; init; }` | Flags byte. | -| `TrackNumber` | `ushort TrackNumber { get; init; }` | Track number. | -| `UncompressedCrc` | `ushort UncompressedCrc { get; init; }` | CRC-16 of the uncompressed data. | -| `UncompressedSize` | `ushort UncompressedSize { get; init; }` | Size of the uncompressed track data in bytes (normally 11264 for a cylinder). | - -#### `DmsWriter` - -Creates an Amiga DMS (Disk Masher System) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmsWriter` | `DmsWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `DmsWriter`. | -| `Dispose` | `void Dispose()` | | -| `WriteDisk` | `void WriteDisk(byte[] diskImage, int compressionMode = 0, int trackSize = 11264)` | Convenience method: splits a disk image into tracks and writes all of them. | -| `WriteHeader` | `void WriteHeader(DmsHeader header)` | Writes the 56-byte file header. Must be called before writing any tracks. The header will be updated on dispose with correct track ranges and sizes. | -| `WriteTrack` | `void WriteTrack(int trackNumber, byte[] data, int compressionMode = 0)` | Compresses and writes one track to the archive. | - -### Namespace `FileFormat.Docx` - -[`DocxFormatDescriptor`](#docxformatdescriptor) - -#### `DocxFormatDescriptor` - -Office Open XML word-processing document (.docx) — an OPC/ZIP package per ECMA-376 / ISO/IEC 29500. References: `https://ecma-international.org/publications-and-standards/standards/ecma-376/` — ECMA-376 — Office Open XML file formats`https://en.wikipedia.org/wiki/Office_Open_XML` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DocxFormatDescriptor` | `DocxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing DOCX archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (DOCX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (DOCX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Dxf` - -[`DxfFormatDescriptor`](#dxfformatdescriptor) - -#### `DxfFormatDescriptor` - -AutoCAD Drawing Exchange Format (ASCII variant). Content is a stream of group-code / value pairs on alternating lines: the numeric group code (e.g. 0 for an entity type, 2 for a name, 10 for an X coordinate) on one line and its value on the next. The document is divided into sections bracketed by `0/SECTION` … `0/ENDSEC` pairs; known sections are `HEADER`, `CLASSES`, `TABLES`, `BLOCKS`, `ENTITIES`, `OBJECTS`, and the document terminates with `0/EOF`. Binary DXF is proprietary and ignored here. References: Autodesk "DXF Reference" — the official group-code documentation published with each AutoCAD release`https://en.wikipedia.org/wiki/AutoCAD_DXF` — format overview - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DxfFormatDescriptor` | `DxfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Read-only archive capabilities. | -| `Category` | `FormatCategory Category { get; }` | Archive category. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | No compound extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default extension. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Display name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Known extensions. | -| `Family` | `AlgorithmFamily Family { get; }` | Archive family. | -| `Id` | `string Id { get; }` | Format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | No reliable binary magic; ASCII DXF starts with a group code (typically " 0") and is extension-primary. | -| `Methods` | `IReadOnlyList Methods { get; }` | Stored only. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a tar compound format. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Dzip` - -[`DzipEntry`](#dzipentry) · [`DzipFormatDescriptor`](#dzipformatdescriptor) · [`DzipLzss`](#dziplzss) · [`DzipReader`](#dzipreader) · [`DzipWriter`](#dzipwriter) - -#### `DzipEntry` - -Represents a single entry in a Bloodlines DZIP archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DzipEntry` | `DzipEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Gets the on-disk size of the entry data in bytes. | -| `CompressionFlag` | `byte CompressionFlag { get; init; }` | Gets the compression flag (0 = stored, non-zero = LZSS-compressed). | -| `Name` | `string Name { get; init; }` | Gets the entry path (forward-slash separated, e.g. "materials/test.vmt"). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry's data within the archive stream. | -| `Size` | `long Size { get; init; }` | Gets the uncompressed (original) size of the entry data in bytes. | - -#### `DzipFormatDescriptor` - -DZIP v2 archive ("DZIP" magic) used by Vampire: The Masquerade — Bloodlines; stored and LZSS-compressed entries. References: Undocumented Troika Games format; the header/TOC layout was recovered by the Bloodlines modding community's unpacking tools`https://en.wikipedia.org/wiki/Vampire:_The_Masquerade_%E2%80%93_Bloodlines` — background on the game - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DzipFormatDescriptor` | `DzipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `DzipLzss` - -Decoder for the Bloodlines DZIP LZSS variant: 8-bit control byte gates 8 operations (literal byte or 2-byte length-distance reference). Distance is 12 bits (max 4096), match length is 4 bits + 3 (range 3..18). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan compressed, int expectedSize)` | Decompresses a Bloodlines DZIP LZSS stream. | - -#### `DzipReader` - -Reads entries from a Bloodlines DZIP v2 archive (Vampire: The Masquerade — Bloodlines). Handles both stored and LZSS-compressed entries. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DzipReader` | `DzipReader(Stream stream, bool leaveOpen = false)` | Initializes a new `DzipReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the DZIP archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DzipEntry entry)` | Extracts the bytes for a given entry. Decompresses LZSS-compressed entries automatically. | - -#### `DzipWriter` - -Creates a Bloodlines DZIP v2 archive in WORM mode. All entries are written stored (compression flag = 0); LZSS compression is read-only. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DzipWriter` | `DzipWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `DzipWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds a stored entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive to the stream and finalizes it. | - -### Namespace `FileFormat.Ear` - -[`EarFormatDescriptor`](#earformatdescriptor) - -#### `EarFormatDescriptor` - -Java EE / Jakarta EE Enterprise Application aRchive (.ear) — ZIP container with META-INF/application.xml and bundled WAR/JAR modules. References: `https://jakarta.ee/specifications/platform/` — Jakarta EE Platform specification — defines EAR packaging`https://en.wikipedia.org/wiki/EAR_(file_format)` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EarFormatDescriptor` | `EarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing EAR archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (EAR is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (EAR is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Epub` - -[`EpubFormatDescriptor`](#epubformatdescriptor) - -#### `EpubFormatDescriptor` - -EPUB e-book — ZIP-based OCF container with a mimetype entry, META-INF/container.xml and the OPF package document. References: `https://www.w3.org/TR/epub-33/` — EPUB 3.3 — W3C Recommendation (incl. the OCF container)`https://en.wikipedia.org/wiki/EPUB` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EpubFormatDescriptor` | `EpubFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing EPUB archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (EPUB is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (EPUB is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Esd` - -[`EsdFormatDescriptor`](#esdformatdescriptor) - -#### `EsdFormatDescriptor` - -Descriptor for the Microsoft ESD (Electronic Software Download) format — the encrypted-CAB / install-image variant of WIM that the Windows Update service streams down for OS provisioning. References: `https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/wim-and-esd-windows-image-files-overview` — Microsoft's WIM/ESD overviewMicrosoft "Windows Imaging File Format (WIM)" whitepaper — the on-disk header / resource-table spec ESD shares`https://wimlib.net` — open-source WIM/ESD implementation (LZMS, solid resources) - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EsdFormatDescriptor` | `EsdFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits an ESD-flagged WIM file containing `inputs` as uncompressed resources. The standard `WimWriter` is invoked with `CompressionNone`, after which we patch the header's flags field to set `FlagEsdMarker` so the produced file is recognisable as an ESD variant. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Each entry's decoded byte buffer is produced by `BuildEntries` and wrapped in a `BoundedEntryStream` sized to its logical length. | - -### Namespace `FileFormat.ExePackers` - -[`AlienyzeExecutablePackerHandler`](#alienyzeexecutablepackerhandler) · [`AmberExecutablePackerHandler`](#amberexecutablepackerhandler) · [`AplibSectionPackerHandler`](#aplibsectionpackerhandler) · [`AplibSectionPackerHandler.Decoded`](#aplibsectionpackerhandlerdecoded) · [`AsPackExecutablePackerHandler`](#aspackexecutablepackerhandler) · [`AsPackFormatDescriptor`](#aspackformatdescriptor) · [`AsProtectFormatDescriptor`](#asprotectformatdescriptor) · [`BeRoExecutablePackerHandler`](#beroexecutablepackerhandler) · [`BzexeExecutablePackerHandler`](#bzexeexecutablepackerhandler) · [`BzexeFormatDescriptor`](#bzexeformatdescriptor) · [`CrinklerFormatDescriptor`](#crinklerformatdescriptor) · [`DescriptorExecutablePackerHandler`](#descriptorexecutablepackerhandler) · [`EnigmaVirtualBoxExecutablePackerHandler`](#enigmavirtualboxexecutablepackerhandler) · [`EronanaExecutablePackerHandler`](#eronanaexecutablepackerhandler) · [`Exe32packExecutablePackerHandler`](#exe32packexecutablepackerhandler) · [`ExpressorExecutablePackerHandler`](#expressorexecutablepackerhandler) · [`EzuriExecutablePackerHandler`](#ezuriexecutablepackerhandler) · [`FsgExecutablePackerHandler`](#fsgexecutablepackerhandler) · [`FsgFallbackExecutablePackerHandler`](#fsgfallbackexecutablepackerhandler) · [`FsgFormatDescriptor`](#fsgformatdescriptor) · [`GenericAplibPackedPeHandler`](#genericaplibpackedpehandler) · [`GenericNrvPackedPeHandler`](#genericnrvpackedpehandler) · [`GoPackerExecutablePackerHandler`](#gopackerexecutablepackerhandler) · [`GoPackerFormatDescriptor`](#gopackerformatdescriptor) · [`GzexeExecutablePackerHandler`](#gzexeexecutablepackerhandler) · [`GzexeFormatDescriptor`](#gzexeformatdescriptor) · [`HuanExecutablePackerHandler`](#huanexecutablepackerhandler) · [`HuanFormatDescriptor`](#huanformatdescriptor) · [`HxorExecutablePackerHandler`](#hxorexecutablepackerhandler) · [`JdpackExecutablePackerHandler`](#jdpackexecutablepackerhandler) · [`KkrunchyFormatDescriptor`](#kkrunchyformatdescriptor) · [`LzExeFormatDescriptor`](#lzexeformatdescriptor) · [`M0dernP4ckerExecutablePackerHandler`](#m0dernp4ckerexecutablepackerhandler) · [`MPressExecutablePackerHandler`](#mpressexecutablepackerhandler) · [`MPressFormatDescriptor`](#mpressformatdescriptor) · [`MewExecutablePackerHandler`](#mewexecutablepackerhandler) · [`MewFormatDescriptor`](#mewformatdescriptor) · [`MidgetPackExecutablePackerHandler`](#midgetpackexecutablepackerhandler) · [`MinorExecutablePackerHandlerBase`](#minorexecutablepackerhandlerbase) · [`MoleboxExecutablePackerHandler`](#moleboxexecutablepackerhandler) · [`MoleboxIdea`](#moleboxidea) · [`NeoliteExecutablePackerHandler`](#neoliteexecutablepackerhandler) · [`NsPackExecutablePackerHandler`](#nspackexecutablepackerhandler) · [`NsPackFormatDescriptor`](#nspackformatdescriptor) · [`OrigamiExecutablePackerHandler`](#origamiexecutablepackerhandler) · [`OrigamiFormatDescriptor`](#origamiformatdescriptor) · [`PackmanExecutablePackerHandler`](#packmanexecutablepackerhandler) · [`PakkeroExecutablePackerHandler`](#pakkeroexecutablepackerhandler) · [`PapawExecutablePackerHandler`](#papawexecutablepackerhandler) · [`PapawFormatDescriptor`](#papawformatdescriptor) · [`PeCompactExecutablePackerHandler`](#pecompactexecutablepackerhandler) · [`PePackerExecutablePackerHandler`](#pepackerexecutablepackerhandler) · [`PeToyExecutablePackerHandler`](#petoyexecutablepackerhandler) · [`PetiteExecutablePackerHandler`](#petiteexecutablepackerhandler) · [`PetiteFormatDescriptor`](#petiteformatdescriptor) · [`PetiteInflate`](#petiteinflate) · [`PetiteUnpacker`](#petiteunpacker) · [`PetiteUnpacker.PetiteBlock`](#petiteunpackerpetiteblock) · [`PetiteUnpacker.PetiteImage`](#petiteunpackerpetiteimage) · [`PkLiteFormatDescriptor`](#pkliteformatdescriptor) · [`ProtectorExecutablePackerHandlerBase`](#protectorexecutablepackerhandlerbase) · [`PyPePackerExecutablePackerHandler`](#pypepackerexecutablepackerhandler) · [`RlPackExecutablePackerHandler`](#rlpackexecutablepackerhandler) · [`ShrinklerFormatDescriptor`](#shrinklerformatdescriptor) · [`SilentPackerExecutablePackerHandler`](#silentpackerexecutablepackerhandler) · [`SilentPackerFormatDescriptor`](#silentpackerformatdescriptor) · [`SimpleDpackExecutablePackerHandler`](#simpledpackexecutablepackerhandler) · [`SquishyExecutablePackerHandler`](#squishyexecutablepackerhandler) · [`TelockExecutablePackerHandler`](#telockexecutablepackerhandler) · [`ThemidaExecutablePackerHandler`](#themidaexecutablepackerhandler) · [`ThemidaFormatDescriptor`](#themidaformatdescriptor) · [`VmProtectFormatDescriptor`](#vmprotectformatdescriptor) · [`WardExecutablePackerHandler`](#wardexecutablepackerhandler) · [`WinUpackExecutablePackerHandler`](#winupackexecutablepackerhandler) · [`WinUpackFallbackExecutablePackerHandler`](#winupackfallbackexecutablepackerhandler) · [`XorPackerExecutablePackerHandler`](#xorpackerexecutablepackerhandler) · [`YodaByteOp`](#yodabyteop) · [`YodaByteOpKind`](#yodabyteopkind) · [`YodaCrypterExecutablePackerHandler`](#yodacrypterexecutablepackerhandler) · [`YodaCrypterFormatDescriptor`](#yodacrypterformatdescriptor) · [`YodaCrypterStub`](#yodacrypterstub) · [`YodaCrypterStubInfo`](#yodacrypterstubinfo) · [`YodaProtectorExecutablePackerHandler`](#yodaprotectorexecutablepackerhandler) - -#### `AlienyzeExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlienyzeExecutablePackerHandler` | `AlienyzeExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `AmberExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AmberExecutablePackerHandler` | `AmberExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | Amber turns a PE into position-independent shellcode plus an embedded copy of the original image that its reflective loader maps at runtime. When that embedded copy is stored as a plaintext `MZ..PE` (the loader relocates it in place) we carve and validate it as a real PE. When it is XOR/RC4-obscured — the common case — the key lives in the shellcode stub, so we honestly stop at locating the payload-bearing region rather than fabricating a decode. | - -#### `AplibSectionPackerHandler` - -Shared base for Win32 PE packers whose compression core is aPLib (`AplibBuildingBlock`) and which store the original image aPLib-compressed inside one of the PE sections — the FSG / ASPack / PECompact / RLPack family. Detection is packer-specific (section names, embedded literals); recovery is shared: carve each section's raw bytes, attempt an aPLib decode, and accept a candidate only when the stream terminates on a genuine end-of-stream marker and expands, which rejects the false positives a magic-less aPLib stream would otherwise invite. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AplibSectionPackerHandler` | `protected AplibSectionPackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `abstract string DisplayName { get; }` | | -| `Id` | `abstract string Id { get; }` | | -| `PackerLabel` | `protected abstract string PackerLabel { get; }` | Display name of the packer as written into metadata (e.g. "FSG", "ASPack"). | -| `BuildMetadataJson` | `protected byte[] BuildMetadataJson(PackedExecutable packed)` | | -| `DetectPe` | `protected abstract ValueTuple DetectPe(ReadOnlySpan image)` | Packer-specific detection. Returns the match confidence in [0,1] and, on no match, a human-readable reason. Implementations may assume the input is a valid PE (the base checks that first). | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `virtual UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `AplibSectionPackerHandler.Decoded` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decoded` | `Decoded(int Offset, byte[] Compressed, byte[] Data)` | | -| `Compressed` | `byte[] Compressed { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Offset` | `int Offset { get; init; }` | | - -#### `AsPackExecutablePackerHandler` - -Real unpack handler for ASPack (Solodovnikov, 1998+), the long-running Win32 PE compressor whose stub renames a section pair to `.aspack` / `.adata` and embeds the literal `"ASPack"` near the start of the file. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AsPackExecutablePackerHandler` | `AsPackExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `AsPackFormatDescriptor` - -Pseudo-archive descriptor for ASPack-packed Win32 executables. ASPack (Solodovnikov, late 1990s) is a long-running Win32 PE compressor whose unpacker stub renames at least one section to `".aspack"` or `".adata"` and almost always embeds the literal `"ASPack"` somewhere in the first 64 KB of the file. The compression core is ASPack's own LZ77-plus-Huffman stream, not aPLib as is widely repeated; see `AsPackLzDecoder`, which `AsPackExecutablePackerHandler` uses to unpack the image. References: `http://www.aspack.com` — official ASPack site (ASPack Software)`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AsPackFormatDescriptor` | `AsPackFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AsProtectFormatDescriptor` - -Pseudo-archive descriptor for ASProtect-protected Win32 executables. ASProtect (Solodovnikov, 2000+) is the commercial sibling of ASPack — adds anti-debug, code morphing, and registration-key checking on top of the same compressor core. The unpacker stub almost always embeds the ASCII literal `"ASProtect"` (and frequently the legacy banner `"Stripped by ASPACK"`). Section names overlap with ASPack (`.aspack`, `.adata`) so the `"ASProtect"` literal is the reliable distinguishing fingerprint. References: `http://www.aspack.com` — vendor site — ASPack Software publishes both ASPack and ASProtect`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AsProtectFormatDescriptor` | `AsProtectFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `BeRoExecutablePackerHandler` - -Static unpacker for BeRoEXEPacker (Benjamin Rosseaux, "bero^fr") — a Win32 PE packer that replaces the original image with two sections: a BSS-style `packerBY` section covering the whole original image body, and a `bero^fr` section holding the loader stub plus the compressed body. Resources stay in a regenerated `.rsrc`. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BeRoExecutablePackerHandler` | `BeRoExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `BzexeExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BzexeExecutablePackerHandler` | `BzexeExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `BzexeFormatDescriptor` - -Pseudo-archive descriptor for bzexe-style executable wrappers. Like gzexe, bzexe produces a shell script with an embedded compressed member; static unpacking only needs to locate the BZip2 stream and inflate it. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BzexeFormatDescriptor` | `BzexeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `CrinklerFormatDescriptor` - -Pseudo-archive descriptor for Crinkler-packed Win32 executables. Crinkler (Mentor & Blueberry, 2005+) is the de facto 4K Windows executable compressor of the demoscene; it produces extremely small, atypically-laid out PE files (often only 1-2 sections, no real import directory) and embeds the literal string `"Crinkler"` somewhere in the file. References: `https://github.com/runestubbe/Crinkler` — Crinkler source (open-sourced 2020)`http://crinkler.net` — official Crinkler site - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CrinklerFormatDescriptor` | `CrinklerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `DescriptorExecutablePackerHandler` - -A generic adapter that wraps any `IFormatDescriptor` implementing `IArchiveFormatOperations` as an `IExecutablePackerHandler`. This allows us to reuse existing high-quality format descriptors for PE detection/extraction without duplicating their parsing and signature logic. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DescriptorExecutablePackerHandler` | `DescriptorExecutablePackerHandler(IFormatDescriptor descriptor)` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `EnigmaVirtualBoxExecutablePackerHandler` - -Real unpack handler for Enigma Virtual Box corpus outputs. EVB is primarily a file bundler, but the public Packing Box PE corpus variants include `.enigma1`/`.enigma2` sections whose payload is recovered by the shared managed aPLib PE pipeline. Full bundled file-tree extraction remains a separate higher-level target. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EnigmaVirtualBoxExecutablePackerHandler` | `EnigmaVirtualBoxExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | - -#### `EronanaExecutablePackerHandler` - -Static unpacker for the Eronana Packer (github.com/Eronana/packer) — a small educational Win32 PE packer whose section-compression codec is a separate, fully-documented submodule (github.com/Eronana/compressor: a hash-chain LZ77 matcher feeding a canonical Huffman coder). - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EronanaExecutablePackerHandler` | `EronanaExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `Exe32packExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Exe32packExecutablePackerHandler` | `Exe32packExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `ExpressorExecutablePackerHandler` - -eXpressor (CGSoftLabs) — a Win32 PE packer that stores the victim's sections as a chain of raw LZMA1 streams in a single payload section. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExpressorExecutablePackerHandler` | `ExpressorExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `EzuriExecutablePackerHandler` - -Static unpacker for Ezuri (github.com/guitmz/ezuri) ELF crypters. Ezuri appends the AES key, the AES IV and the AES-256-CFB ciphertext of the original ELF directly after its Go loader stub, in the clear: `[stub ELF][32-byte key][16-byte IV][AES-256-CFB ciphertext]`. The loader recovers the original by seeking to the appended key/IV and decrypting the tail, so the key material is fully present in the file and the original executable is recoverable byte-for-byte without running it. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EzuriExecutablePackerHandler` | `EzuriExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `FsgExecutablePackerHandler` - -Real unpack handler for FSG ("Fast, Small, Good") — bart/Xtreeme's minimal aPLib-based Win32 PE compressor (v1.x–2.0, ~2004), identified by the `"FSG!"` marker its ~158-byte stub embeds near the entry point. FSG chose aPLib specifically (LZMA "too big", NRV "too slow"); the shared `AplibSectionPackerHandler` carves the aPLib-compressed section and inflates it. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FsgExecutablePackerHandler` | `FsgExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | Walks FSG's own block list first — the packer concatenates one bare aPLib stream per original section and only the entry-point stub says where they start, which no amount of scanning section boundaries will find. Images whose stub is not the shape `FsgImage` models fall through to the shared aPLib scan. | - -#### `FsgFallbackExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FsgFallbackExecutablePackerHandler` | `FsgFallbackExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `FsgFormatDescriptor` - -Pseudo-archive descriptor for FSG ("Fast Small Good") packed Win32 executables. FSG (xt by bart/CRC, early 2000s) is a tiny PE compressor that typically emits a single-section binary; the unpacker stub embeds the distinctive 4-byte ASCII magic `"FSG!"` usually right at or near the PE entry point. References: FSG by bart/xt — distributed through the packer scene; no official documentation survives`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database (FSG signatures) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FsgFormatDescriptor` | `FsgFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `GenericAplibPackedPeHandler` - -Generic fallback for aPLib-compressed PEs whose specific packer we don't name (JDPack and other aPLib-family stubs, or aPLib output from an unknown tool). Detection is by decode: a PE section that inflates to a cleanly-terminated, expanding aPLib stream is accepted. Registered last and at low confidence so a recognized packer always wins when its marker is present. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GenericAplibPackedPeHandler` | `GenericAplibPackedPeHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | - -#### `GenericNrvPackedPeHandler` - -Generic fallback for PE packers whose payload is a bare NRV stream inside a section. This covers UPX-adjacent historical packers only when the payload is actually recoverable; detection requires a successful inflate to avoid promoting section-name heuristics into fake unpacking. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GenericNrvPackedPeHandler` | `GenericNrvPackedPeHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `GoPackerExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GoPackerExecutablePackerHandler` | `GoPackerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `GoPackerFormatDescriptor` - -Pseudo-archive descriptor for GoPacker executables. GoPacker appends a Zstandard-compressed copy of the original executable, followed by an 8-byte little-endian compressed length and the ASCII footer "LALALALA". - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GoPackerFormatDescriptor` | `GoPackerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `GzexeExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GzexeExecutablePackerHandler` | `GzexeExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `GzexeFormatDescriptor` - -Pseudo-archive descriptor for GNU gzip's gzexe wrapper. gzexe is listed by Packing Box as an ELF packer, but the produced file is a POSIX shell script with an embedded gzip member. Static unpacking is therefore deterministic: find the gzip member, inflate it, and emit the original executable bytes. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GzexeFormatDescriptor` | `GzexeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `HuanExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuanExecutablePackerHandler` | `HuanExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `HuanFormatDescriptor` - -Static unpacker for Huan PE64 loader outputs. Huan embeds the original PE in a .huan section as: original length, encrypted length, AES-128 key, AES-CBC IV, encrypted bytes padded with zeroes to a 16-byte boundary. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HuanFormatDescriptor` | `HuanFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `HxorExecutablePackerHandler` - -Static unpacker for hXOR-Packer (github.com/rurararura/hXOR-Packer, Afif 2012) — an educational Win32 EXE packer/binder. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HxorExecutablePackerHandler` | `HxorExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `MsvcrtRand` | `static int MsvcrtRand(uint seed)` | Reimplementation of the classic MSVCRT rand() linear-congruential generator that hXOR's MinGW build links against: `srand(seed)` sets the 32-bit state directly, and `rand()` advances it once and returns bits 30..16. Verified bit-for-bit against an actual MinGW-w64 build's `rand()`/`srand()` output for several seeds. | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `JdpackExecutablePackerHandler` - -JDPack 1.x (`.jdpack` section) — a Win32 PE packer that leaves the victim's section table in place and replaces individual section byte ranges with compressed blobs, unpacking each of them back over its own virtual address at start-up. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `JdpackExecutablePackerHandler` | `JdpackExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `KkrunchyFormatDescriptor` - -Pseudo-archive descriptor for kkrunchy-packed Win32 executables. kkrunchy (ryg / Farbrausch, ~2003) is the 64K Windows executable compressor used by .kkrieger, fr-08, and most early-2000s Farbrausch 64K intros. Its unpacker stub embeds the literal string `"kkrunchy"` somewhere in the packed file. References: `https://github.com/farbrausch/fr_public` — Farbrausch public source release — includes kkrunchyFabian "ryg" Giesen's kkrunchy write-ups — compressor internals from the author - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `KkrunchyFormatDescriptor` | `KkrunchyFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `LzExeFormatDescriptor` - -Pseudo-archive descriptor for LZEXE-packed DOS executables. Fabrice Bellard's LZEXE (1989) was one of the first widely-distributed DOS exe compressors; the unpacker stub embeds an `"LZ91"` or `"LZ09"` signature near the start of the code section that uniquely identifies it. References: `https://en.wikipedia.org/wiki/LZEXE` — format and tool historyUNLZEXE (Mitugu Kurizono) source — the de-facto documentation of the LZ91/LZ09 stub layout - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzExeFormatDescriptor` | `LzExeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `M0dernP4ckerExecutablePackerHandler` - -Static unpacker for m0dern_p4cker (github.com/n4sm/m0dern_p4cker) ELF64 packers. The packer encrypts the original `.text` section in place with a random single-byte key, copies its assembly stub into the code cave after the executable segment, and repoints `e_entry` at the stub. The stub carries the key and the original entry point as patched `mov` immediates, so both are recoverable statically: the encrypted `.text` is decrypted to the original bytes and the original entry point restored. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `M0dernP4ckerExecutablePackerHandler` | `M0dernP4ckerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MPressExecutablePackerHandler` - -MPRESS (MATCODE Software) packed PE/ELF images. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MPressExecutablePackerHandler` | `MPressExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MPressFormatDescriptor` - -Pseudo-archive descriptor for MPRESS-packed Win32 PE / Linux ELF executables. MPRESS (MATCODE Software, ~2007) emits two characteristic sections named `.MPRESS1` and `.MPRESS2` in PE files; in both PE and ELF builds the unpacker stub also embeds the literal copyright strings `"MPRESS"` / `"MATCODE"` in the first ~64 KB. References: `https://matcode.com/` — MATCODE Software — MPRESS vendor site`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database (MPRESS signatures) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MPressFormatDescriptor` | `MPressFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `MewExecutablePackerHandler` - -Real unpack handler for MEW (Northfox/HCC) — the "smallest PE packer", which folds its whole first stage into the PE headers and marks its output section `MEW`. Stage 1 is aPLib, stage 2 LZMA1; see `MewImage` for the container layout. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MewExecutablePackerHandler` | `MewExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MewFormatDescriptor` - -Pseudo-archive descriptor for MEW-packed Win32 executables. MEW (by Northfox/HCC, early 2000s) is an extremely small Win32 PE compressor. Its unpacker stub renames at least one section so that the name begins with `"MEW"` or `".MEW"` (commonly `MEW`, `MEWF`, `.MEW`). References: MEW 11 SE by Northfox — distributed through the RE scene; no official documentation survives`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database (MEW signatures) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MewFormatDescriptor` | `MewFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `MidgetPackExecutablePackerHandler` - -Detector and payload locator for MidgetPack (github.com/arisada/midgetpack) ELF crypters. MidgetPack appends the AES-encrypted original ELF to a precompiled stub and describes it with an extra `PT_LOAD` program header: the added segment is mapped read/write/execute, starts past the end of the stub, and runs to end-of-file. Because the payload is a whole number of cipher blocks, its length is always a multiple of 16. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MidgetPackExecutablePackerHandler` | `MidgetPackExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MinorExecutablePackerHandlerBase` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MinorExecutablePackerHandlerBase` | `protected MinorExecutablePackerHandlerBase()` | | -| `Capabilities` | `virtual ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `abstract string DisplayName { get; }` | | -| `Id` | `abstract string Id { get; }` | | -| `LiteralSignature` | `protected abstract ReadOnlySpan LiteralSignature { get; }` | | -| `BuildMetadataJson` | `protected byte[] BuildMetadataJson(PackedExecutable packed)` | | -| `Detect` | `virtual DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected abstract bool IsPackerSection(string name)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `virtual UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MoleboxExecutablePackerHandler` - -Static unpacker for MoleBox 2.x (Teggo) — a bundler that packs an application, and optionally a tree of data files, into one executable. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MoleboxExecutablePackerHandler` | `MoleboxExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `MoleboxIdea` - -The IDEA block cipher (Lai/Massey, "IPES", 1991) in the shape MoleBox uses it: 64-bit blocks, a 128-bit key, ECB. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | | -| `ExpandKey` | `static ushort[] ExpandKey(ReadOnlySpan key)` | Builds the 52 encryption subkeys from a 16-byte key. | -| `InvertKey` | `static ushort[] InvertKey(ReadOnlySpan encryption)` | Turns an encryption schedule into the matching decryption one. | -| `ProcessBlock` | `static void ProcessBlock(ReadOnlySpan input, Span output, ReadOnlySpan subkeys)` | Runs one 8-byte block through the cipher with the given schedule. | -| `ProcessEcb` | `static byte[] ProcessEcb(ReadOnlySpan data, ReadOnlySpan subkeys)` | Runs a whole buffer through the cipher in ECB mode; a trailing partial block is left alone. | - -#### `NeoliteExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NeoliteExecutablePackerHandler` | `NeoliteExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `NsPackExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsPackExecutablePackerHandler` | `NsPackExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `NsPackFormatDescriptor` - -Pseudo-archive descriptor for NsPack-packed Win32 executables. NsPack (LiuXingPing, early 2000s) is a Chinese PE compressor whose unpacker stub renames sections to `".nsp0"`, `".nsp1"`, `".nsp2"` (sometimes without the leading dot — `"nsp1"`, `"nsp2"`). Many builds also embed the literal `"NsPack"` in the stub. References: NsPack by North Star / LiuXingPing — commercial distribution ceased; identified via RE-scene documentation`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database (NsPack signatures) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsPackFormatDescriptor` | `NsPackFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `OrigamiExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OrigamiExecutablePackerHandler` | `OrigamiExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `OrigamiFormatDescriptor` - -Static unpacker for Origami .NET assembly wrappers. Origami stores a raw Deflate payload XORed with the managed entry point method name, then patches the loader IL with the payload pointer and payload length. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OrigamiFormatDescriptor` | `OrigamiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PackmanExecutablePackerHandler` - -Real unpack handler for Packman - a Win32 PE compressor that marks its payload section as `.PACKMAN`. The shared aPLib base handles the corpus variant whose section contains a clean aPLib stream. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackmanExecutablePackerHandler` | `PackmanExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | - -#### `PakkeroExecutablePackerHandler` - -Detector for Pakkero (github.com/4w4k3/pakkero) ELF launchers. Pakkero is a Go-based binary obfuscator rather than a size-reducing packer: it generates a launcher, compiles it, strips the result and appends a large block of random bytes past everything the ELF headers describe, so that no two outputs share a layout or a signature. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PakkeroExecutablePackerHandler` | `PakkeroExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `PapawExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PapawExecutablePackerHandler` | `PapawExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `PapawFormatDescriptor` - -Pseudo-archive descriptor for Papaw-packed ELF executables. Papaw appends an obfuscated XZ/LZMA2 payload plus a big-endian footer with original and compressed lengths to an ELF decompressor stub; static unpacking restores the XZ stream and emits the original executable bytes without executing the stub. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PapawFormatDescriptor` | `PapawFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PeCompactExecutablePackerHandler` - -Real unpack handler for PECompact 2 (Bitsum) — an aPLib-capable Win32 PE compressor whose stub carries a `"PEC2"` marker and typically renames sections to `.pec1`/`.pec2`. The shared base attempts an aPLib decode of the packed section (PECompact also supports other codecs via plug-ins, in which case the handler reports the payload as located but not aPLib-decodable). - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PeCompactExecutablePackerHandler` | `PeCompactExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | - -#### `PePackerExecutablePackerHandler` - -Detector/locator for PE-Packer (github.com/czs108/PE-Packer) — an educational Win32 EXE packer. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PePackerExecutablePackerHandler` | `PePackerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `PeToyExecutablePackerHandler` - -Real unpack handler for PE-Toy, a Win32 PE packer whose documented shell layout adds a `.petoy` section and uses an aPLib payload. The shared aPLib base carves and inflates the payload and emits a synthetic rebuilt PE when the decoded image can be mapped. - -Inherits `AplibSectionPackerHandler`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PeToyExecutablePackerHandler` | `PeToyExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `PackerLabel` | `protected override string PackerLabel { get; }` | | -| `DetectPe` | `protected override ValueTuple DetectPe(ReadOnlySpan image)` | | - -#### `PetiteExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PetiteExecutablePackerHandler` | `PetiteExecutablePackerHandler()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | Expands the PEtite block table (see `PetiteUnpacker`). Each original section comes back as its own artifact; imports, relocations and the original entry point are not restored, so the result stays at `PayloadDecompressed`. | - -#### `PetiteFormatDescriptor` - -Pseudo-archive descriptor for Petite-packed Win32 executables. Petite (Ian Luck, 1997) was a popular PE compressor in the late 90s; the unpacker stub embeds a section name beginning with `".petite"` and a literal `"Petite"` ASCII string near the entry point. References: `https://www.un4seen.com/petite/` — official Petite site (Ian Luck / Un4seen Developments)`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PetiteFormatDescriptor` | `PetiteFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PetiteInflate` - -DEFLATE (RFC 1951) decoder for the PEtite dialect: block type 1 carries the dynamic Huffman tables (there is no fixed-table block type), types 2 and 3 are invalid. Written against RFC 1951 and the table constants the PEtite stub stores in clear at the head of its section. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TryInflate` | `static bool TryInflate(ReadOnlySpan input, int start, int expectedSize, out byte[] output)` | | - -#### `PetiteUnpacker` - -Container format of a PEtite-packed Win32 PE, reconstructed from the on-disk layout and the entry stub of the samples themselves. A PEtite image keeps the original section virtual addresses. The packed bytes live in one oversized section mapped at the first original section's RVA; a second section holds the untouched resources; the last section (the one the entry point falls into) holds the loader stub. Right behind the stub code sits a block table that drives unpacking:a record whose first dword has bit 31 set is a descending `rep movsd` — `{0x80000000|dwordCount, sourceEndRva, destinationEndRva}`, 12 bytes — which lifts the packed bytes out of the way of the image that is about to be written over them;any other record is `{sourceRva, decompressedSize, destinationRva, unused}`, 16 bytes, and expands one original section in place. A zero length marks an original section without initialised data and is skipped; a zero source ends the table.The compressed streams are DEFLATE (RFC 1951) with one deviation: the stub has no fixed-Huffman tables, so block type `1` selects the dynamic Huffman tables that standard DEFLATE assigns to type `2`, and types 2 and 3 are rejected. Everything else — LSB-first bit order, the 14-bit HLIT/HDIST/HCLEN header, the code-length alphabet, the length/distance base and extra-bit tables — matches RFC 1951 byte for byte; those five tables are stored verbatim at the head of the stub section and were read from there.Code blocks are additionally stored with relative branch targets converted to absolute ones: scanning forward, every `E8`/`E9` and every `0F 80..0F 8F` has the block offset of its opcode added to the following dword, and the scan then skips the whole instruction. Reversing it subtracts the same offset again. References: `https://www.rfc-editor.org/rfc/rfc1951` — DEFLATE compressed data format`https://www.un4seen.com/petite/` — PEtite (Ian Luck / Un4seen Developments) - -| Member | Signature | Summary | -| --- | --- | --- | -| `ReverseBranchFilter` | `static byte[] ReverseBranchFilter(byte[] block)` | Reverses the absolute-branch-target transform: subtract each opcode's own block offset from the dword that follows it. | -| `TryUnpack` | `static bool TryUnpack(ReadOnlySpan image, long maximumDecompressedSize, out PetiteImage result, out string error)` | | - -#### `PetiteUnpacker.PetiteBlock` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PetiteBlock` | `PetiteBlock(uint SourceRva, uint DestinationRva, byte[] Data, bool BranchFilterReversed)` | | -| `BranchFilterReversed` | `bool BranchFilterReversed { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `DestinationRva` | `uint DestinationRva { get; init; }` | | -| `SourceRva` | `uint SourceRva { get; init; }` | | - -#### `PetiteUnpacker.PetiteImage` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PetiteImage` | `PetiteImage(IReadOnlyList Blocks, byte[] MemoryImage, uint BlockTableRva, uint StubSectionRva)` | | -| `BlockTableRva` | `uint BlockTableRva { get; init; }` | | -| `Blocks` | `IReadOnlyList Blocks { get; init; }` | | -| `MemoryImage` | `byte[] MemoryImage { get; init; }` | | -| `StubSectionRva` | `uint StubSectionRva { get; init; }` | | - -#### `PkLiteFormatDescriptor` - -Pseudo-archive descriptor for PKLITE-packed DOS executables. PKLITE was a commercial DOS exe-compressor by PKWARE (1990); the unpacker stub it prepends carries the distinctive `"PKLITE Copr."` copyright string and a version field at MZ-header offset `0x1C`. References: `https://en.wikipedia.org/wiki/PKLITE` — format and tool historyPKWARE PKLITE documentation (shipped with the product) — describes the compressed-EXE layout and version word at MZ offset 0x1C - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PkLiteFormatDescriptor` | `PkLiteFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `ProtectorExecutablePackerHandlerBase` - -Base for runtime protectors (TELock, Yoda's Protector, the Themida fallback, …) whose original image is only recoverable by executing the anti-debug / code-virtualization stub under emulation. These handlers honestly stay at detection + payload-location and deliberately do not run the generic aPLib/NRV probes: a spuriously "cleanly terminated" stream inside a protector's encrypted body would fabricate a decompression we cannot actually perform. Every result carries an explicit runtime-protector diagnostic so callers never mistake location for unpacking. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ProtectorExecutablePackerHandlerBase` | `protected ProtectorExecutablePackerHandlerBase()` | | -| `Capabilities` | `override ExecutableUnpackCapabilities Capabilities { get; }` | | -| `StaticUnpackObstacle` | `protected virtual string StaticUnpackObstacle { get; }` | Why this handler stops at payload location. The default is the honest answer for a virtualizing protector; handlers whose obstacle is something more specific should say so rather than let a user read "needs emulation" where that is not the reason. | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `PyPePackerExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PyPePackerExecutablePackerHandler` | `PyPePackerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `RlPackExecutablePackerHandler` - -Real unpack handler for RLPack (ap0x) — a Win32 PE packer that stores the original image, section by section, in a `.RLPack` section and inflates it into an adjacent uninitialised `.packed` section at run time. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RlPackExecutablePackerHandler` | `RlPackExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `ShrinklerFormatDescriptor` - -Pseudo-archive descriptor for Shrinkler-packed Amiga binaries — Blueberry's range-coding-based context-mixing exe compressor used by virtually every modern 4K and 64K Amiga demoscene production. The compressor emits a distinctive header containing a magic identifier and the original size. References: `https://github.com/askeksa/Shrinkler` — canonical Shrinkler source (Aske Simon Christensen / Blueberry)Amiga hunk-file structure — AmigaDOS Manual (Bantam, 3rd ed.) documents the HUNK container Shrinkler emits - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinklerFormatDescriptor` | `ShrinklerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `SilentPackerExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SilentPackerExecutablePackerHandler` | `SilentPackerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `SilentPackerFormatDescriptor` - -Static unpacker for Silent_Packer ELF64 XOR section-insertion outputs. This path reverses the loader metadata embedded in the added .dec section: XOR key, encrypted .text virtual address, encrypted .text size, loader virtual address and the relative jump back to the original entry point. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SilentPackerFormatDescriptor` | `SilentPackerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `SimpleDpackExecutablePackerHandler` - -Detector/locator for SimpleDpack (github.com/YuriSizuku/SimpleDpack) — an educational Win32/64 PE packer. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SimpleDpackExecutablePackerHandler` | `SimpleDpackExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `SquishyExecutablePackerHandler` - -squishy (Jake "ferris" Taylor / logicoma, 2016+, `https://logicoma.io/squishy`) is a closed-source Win32 PE compressor purpose-built for demoscene 64K intros. Its own release notes describe an adaptive context-mixing coder ("context modeling" drawing on PAQ and LZMA literature) bootstrapped from "a crinkler-like model", plus a state-based disassembler that transforms jmp/call instructions ahead of coding — the same closed, non-LZ category as Crinkler and kkrunchy, not a publicly specified format. Detection was confirmed against real output from the official releases (squishy-0.1.3, x86, and squishy-0.2.0, x86-64): the packed PE always has exactly one section literally named `logicoma`, and the DOS-stub region ahead of the (deliberately tiny) `e_lfanew` embeds the same "logicoma" text in every build, plus an ASCII-art "squished by ... ferris@logicoma" credit banner starting with 0.2.0. - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SquishyExecutablePackerHandler` | `SquishyExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | squishy's payload is coded by an undocumented, closed context-mixing model — there is no public specification or reference decoder to statically reverse it, so this handler never runs the generic aPLib/NRV probes (a spurious "clean" decode against a context-mixed stream would fabricate a decompression that isn't actually happening). It honestly stops at locating the single named payload section. | - -#### `TelockExecutablePackerHandler` - -Inherits `ProtectorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TelockExecutablePackerHandler` | `TelockExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `ThemidaExecutablePackerHandler` - -Inherits `ProtectorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ThemidaExecutablePackerHandler` | `ThemidaExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `ThemidaFormatDescriptor` - -Pseudo-archive descriptor for Themida / WinLicense protected Win32 executables. Themida (Oreans Technologies, 2003+) is a heavyweight commercial protector that combines virtualization, code mutation, and anti-debug. Detection is best-effort: many builds wipe section names and strip identifying strings, but the literal `"Themida"`, `"ThemidaSDK"`, or `"WinLicense"` is frequently left in the build for licensing/runtime calls. Some builds also leave a `".themida"` section name. References: `https://www.oreans.com/themida.php` — official Themida site (Oreans Technologies)`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ThemidaFormatDescriptor` | `ThemidaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `VmProtectFormatDescriptor` - -Pseudo-archive descriptor for VMProtect-protected Win32 executables. VMProtect (~2003+) is a commercial virtualizing protector that re-routes selected bytecode through a per-build virtual machine. The unpacker stub commonly renames sections to `".vmp0"`, `".vmp1"`, `".vmp2"` and almost always embeds the literal `"VMProtect"` in the build for licensing/runtime calls. References: `https://vmpsoft.com` — official VMProtect site (VMProtect Software)`https://en.wikipedia.org/wiki/VMProtect` — background`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VmProtectFormatDescriptor` | `VmProtectFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `WardExecutablePackerHandler` - -Static unpacker for Ward (github.com/ex0dus-0x/ward) ELF packers. Ward appends the original target ELF verbatim to the end of a clang-built stub and repoints the stub's `PT_NOTE` program header at it (a classic PT_NOTE infection): `p_offset` becomes the stub's original file size and `p_filesz` becomes the original ELF's length. Although Ward's README advertises zlib compression, the current injector discards the compressed buffer and stores the target uncompressed, so the original executable is recovered byte-for-byte by carving the injected note region. - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WardExecutablePackerHandler` | `WardExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `WinUpackExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WinUpackExecutablePackerHandler` | `WinUpackExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `WinUpackFallbackExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WinUpackFallbackExecutablePackerHandler` | `WinUpackFallbackExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -#### `XorPackerExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XorPackerExecutablePackerHandler` | `XorPackerExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `YodaByteOp` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YodaByteOp` | `YodaByteOp(YodaByteOpKind Kind, byte Operand)` | | -| `Kind` | `YodaByteOpKind Kind { get; init; }` | | -| `Operand` | `byte Operand { get; init; }` | | - -#### `YodaByteOpKind` - -The byte-wise operations a Yoda's Crypter decryption loop is built from. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `AddImmediate` | `0` | | -| `SubtractImmediate` | `1` | | -| `XorImmediate` | `2` | | -| `AddCounter` | `3` | | -| `SubtractCounter` | `4` | | -| `XorCounter` | `5` | | -| `RotateLeft` | `6` | | -| `RotateRight` | `7` | | -| `Increment` | `8` | | -| `Decrement` | `9` | | -| `Not` | `10` | | -| `Negate` | `11` | | - -#### `YodaCrypterExecutablePackerHandler` - -Inherits `MinorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YodaCrypterExecutablePackerHandler` | `YodaCrypterExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `Detect` | `override DetectionResult Detect(ReadOnlySpan image)` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | -| `Unpack` | `override UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `YodaCrypterFormatDescriptor` - -Pseudo-archive descriptor for Yoda's Crypter / Yoda's Protector packed Win32 executables. Yoda's Crypter (Ashkbiz Danehkar, early 2000s) is a classic anti-RE crypter whose unpacker stub renames at least one section to `".yC"` or `"yC"` and embeds the literal copyright string `"Yoda's Crypter"` (or simply `"Yoda's"`) somewhere in the file. References: `https://sourceforge.net/projects/yodap/` — Yoda's Protector project (Ashkbiz Danehkar) on SourceForge`https://github.com/horsicq/Detect-It-Easy` — Detect It Easy — maintained packer-detection signature database - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YodaCrypterFormatDescriptor` | `YodaCrypterFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `YodaCrypterStub` - -Static unpacker for Yoda's Crypter protected Win32 images. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TryUnpack` | `static bool TryUnpack(ReadOnlySpan image, out YodaCrypterStubInfo info)` | | -| `Unpack` | `static YodaCrypterStubInfo Unpack(ReadOnlySpan image)` | Peels every Yoda's Crypter layer the image carries. Packing an already packed file just appends a second `yC` section, and the outer walker skips `yC` sections, so the inner stub survives the outer pass intact and the same walk applies again. | - -#### `YodaCrypterStubInfo` - -What `YodaCrypterStub` recovered from a packed image. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YodaCrypterStubInfo` | `YodaCrypterStubInfo(byte[] DecryptedImage, uint? OriginalEntryPoint, IReadOnlyList StubCipher, IReadOnlyList SectionCipher, IReadOnlyList DecryptedSections, IReadOnlyList SkippedSections, uint StubSectionRva)` | What `YodaCrypterStub` recovered from a packed image. | -| `DecryptedImage` | `byte[] DecryptedImage { get; init; }` | | -| `DecryptedSections` | `IReadOnlyList DecryptedSections { get; init; }` | | -| `OriginalEntryPoint` | `uint? OriginalEntryPoint { get; init; }` | | -| `SectionCipher` | `IReadOnlyList SectionCipher { get; init; }` | | -| `SkippedSections` | `IReadOnlyList SkippedSections { get; init; }` | | -| `StubCipher` | `IReadOnlyList StubCipher { get; init; }` | | -| `StubSectionRva` | `uint StubSectionRva { get; init; }` | | - -#### `YodaProtectorExecutablePackerHandler` - -Yoda's Protector locates its payload but does not decode it. - -Inherits `ProtectorExecutablePackerHandlerBase`. Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YodaProtectorExecutablePackerHandler` | `YodaProtectorExecutablePackerHandler()` | | -| `DisplayName` | `override string DisplayName { get; }` | | -| `Id` | `override string Id { get; }` | | -| `LiteralSignature` | `protected override ReadOnlySpan LiteralSignature { get; }` | | -| `StaticUnpackObstacle` | `protected override string StaticUnpackObstacle { get; }` | | -| `IsPackerSection` | `protected override bool IsPackerSection(string name)` | | - -### Namespace `FileFormat.FontCollection` - -[`OtcFormatDescriptor`](#otcformatdescriptor) · [`OtfFormatDescriptor`](#otfformatdescriptor) · [`TtcFormatDescriptor`](#ttcformatdescriptor) · [`TtcReader`](#ttcreader) · [`TtcReader.Member`](#ttcreadermember) · [`TtcWriter`](#ttcwriter) · [`TtfFormatDescriptor`](#ttfformatdescriptor) - -#### `OtcFormatDescriptor` - -Exposes an OpenType Collection (.otc) — same container format as .ttc (same 'ttcf' magic) — as `FULL.otc` + `metadata.ini` + `fonts/_.{otf,ttf}` + `glyphs/_/U+XXXX.svg`. CFF-outline members are recognised but produce no glyph SVGs (recorded in metadata). References: `https://learn.microsoft.com/en-us/typography/opentype/spec/` — OpenType specification — the 'ttcf' collection header is defined in the font-file tables chapter`https://developer.apple.com/fonts/TrueType-Reference-Manual/` — Apple TrueType Reference Manual - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OtcFormatDescriptor` | `OtcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `OtfFormatDescriptor` - -Exposes a single-font .otf as `FULL.otf` + `metadata.ini` + per-glyph SVG entries. OTFs with TrueType outlines ('glyf') split per glyph; OTFs with CFF/CFF2 outlines emit FULL only and record the skip reason in metadata.ini. References: `https://learn.microsoft.com/en-us/typography/opentype/spec/` — OpenType specification (sfnt tables, glyf/CFF outlines)ISO/IEC 14496-22 "Open Font Format" — the same specification as an international standard`https://developer.apple.com/fonts/TrueType-Reference-Manual/` — Apple TrueType Reference Manual — glyf outline encoding - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OtfFormatDescriptor` | `OtfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `TtcFormatDescriptor` - -Exposes a TrueType Collection (.ttc) as an archive with: `FULL.ttc` — verbatim original collection`metadata.ini` — per-font glyph emission stats`fonts/_.{ttf,otf}` — sliced standalone member fonts`glyphs/_/U+XXXX.svg` — per-glyph SVG outlines (TrueType only) References: `https://learn.microsoft.com/en-us/typography/opentype/spec/` — OpenType specification — defines the 'ttcf' TrueType Collection header`https://developer.apple.com/fonts/TrueType-Reference-Manual/` — Apple TrueType Reference Manual — TrueType Collections and glyf outlines - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TtcFormatDescriptor` | `TtcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM creation: bundles one or more standalone TTF/OTF inputs into a TTC v1 collection. Inputs must already be valid SFNT fonts (first 4 bytes match a known sfnt version); the writer rejects anything else so the produced TTC always describes real fonts. The reader's synthetic FULL.ttc, metadata.ini, and any per-glyph SVG outputs are filtered so a list-then-create round-trip recreates the original collection from the per-member font slices. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `TtcReader` - -Slices a TrueType / OpenType collection (.ttc / .otc) into per-member standalone SFNT fonts. Each member font's tables — some of which may be shared across members in the source collection — are copied verbatim into the output; this trades compactness for an output that any font consumer reads without TTC support. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TtcReader` | `TtcReader()` | | -| `Read` | `List Read(ReadOnlySpan data)` | | - -#### `TtcReader.Member` - -One sliced member font. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Member` | `Member(int Index, string Extension, byte[] Data)` | One sliced member font. | -| `Data` | `byte[] Data { get; init; }` | | -| `Extension` | `string Extension { get; init; }` | | -| `Index` | `int Index { get; init; }` | | - -#### `TtcWriter` - -WORM writer for TrueType / OpenType font collections (.ttc / .otc). Bundles one or more standalone SFNT inputs (.ttf or .otf) into a single TTC v1 container per Microsoft OpenType / Apple TTC documentation. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TtcWriter` | `TtcWriter()` | | -| `Write` | `static void Write(Stream output, IReadOnlyList fonts)` | Writes a TTC v1 container bundling `fonts` to `output`. Each member font's bytes are copied verbatim from the input, after a header containing absolute offsets into the concatenated payload. | - -#### `TtfFormatDescriptor` - -Exposes a single-font TrueType .ttf as an archive of `FULL.ttf` + `metadata.ini` + per-glyph SVG files under `glyphs//`. Composite glyphs and CFF/CFF2 outlines are out of scope for this wave; both are recorded in `metadata.ini` with a reason so the gap is visible. References: `https://learn.microsoft.com/en-us/typography/opentype/spec/` — Microsoft OpenType specification (the sfnt table format TrueType shares)`https://developer.apple.com/fonts/TrueType-Reference-Manual/` — Apple TrueType Reference Manual`https://en.wikipedia.org/wiki/TrueType` — Wikipedia overview - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TtfFormatDescriptor` | `TtfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.FreeArc` - -[`FreeArcEntry`](#freearcentry) · [`FreeArcFormatDescriptor`](#freearcformatdescriptor) · [`FreeArcReader`](#freearcreader) · [`FreeArcWriter`](#freearcwriter) - -#### `FreeArcEntry` - -Represents a single file entry within a FreeArc archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreeArcEntry` | `FreeArcEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | The compressed size of the file data in bytes. | -| `Method` | `string Method { get; init; }` | The compression method string (e.g. "storing", "lzma", "freearc"). | -| `Name` | `string Name { get; init; }` | The file name as stored in the archive directory block. | -| `Size` | `long Size { get; init; }` | The uncompressed size of the file in bytes. | - -#### `FreeArcFormatDescriptor` - -Format descriptor for FreeArc compressed archives (.arc). References: `https://github.com/Bulat-Ziganshin/FA` — FreeArc'Next by FreeArc's author, Bulat Ziganshin (the original freearc.org site is defunct)`https://en.wikipedia.org/wiki/FreeArc` — Wikipedia overviewNo formal specification — the archive layout is defined by the original FreeArc sources - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreeArcFormatDescriptor` | `FreeArcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the FreeArc archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the FreeArc archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `FreeArcReader` - -Reads FreeArc archives (.arc). This implementation parses a well-defined binary subset of the FreeArc container format that is produced by `FreeArcWriter` and understood by this reader. Binary layout (all integers are little-endian): 4 bytes — magic "ArC\x01"4 bytes — uint32 archive flags (reserved, currently 0)One or more blocks, each preceded by a 1-byte block type: 0x01 = directory block0x02 = data block0x00 = end-of-archive marker Directory block payload: uint32 — number of file entriesPer entry: uint16 nameLen + UTF-8 name + uint64 size + uint64 compressedSize + uint64 dataOffset + uint16 methodLen + ASCII method Data block payload: uint32 — payload length in bytespayload bytes (concatenated raw file data) - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreeArcReader` | `FreeArcReader(Stream stream, bool leaveOpen = false)` | Initialises a new `FreeArcReader` and parses the archive. | -| `Magic` | `static readonly byte[] Magic` | Magic bytes at the start of every FreeArc archive. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file entries found in the archive directory. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(FreeArcEntry entry)` | Extracts and returns the raw (uncompressed) bytes for the specified entry. | - -#### `FreeArcWriter` - -Builds minimal FreeArc archives (.arc) that can be read by `FreeArcReader`. All files are stored without compression (method "storing"). The writer produces the exact binary layout described in `FreeArcReader`: magic, archive flags, a single directory block, a single data block, and the end-of-archive marker. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreeArcWriter` | `FreeArcWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive being built. | -| `Build` | `byte[] Build()` | Serialises the archive and returns it as a byte array. | - -### Namespace `FileFormat.Freeze` - -[`FreezeFormatDescriptor`](#freezeformatdescriptor) · [`FreezeStream`](#freezestream) - -#### `FreezeFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreezeFormatDescriptor` | `FreezeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `FreezeStream` - -Provides static methods for compressing and decompressing data using the Freeze 2.0 format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses data from `input` and writes a Freeze 2.0 stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a Freeze 2.0 stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Gar` - -[`GarEntry`](#garentry) · [`GarFormatDescriptor`](#garformatdescriptor) · [`GarReader`](#garreader) · [`GarWriter`](#garwriter) - -#### `GarEntry` - -Represents a single file entry in a Nintendo 3DS GAR archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GarEntry` | `GarEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the full filename including extension (e.g. "icon.bclim"). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the file payload from the start of the archive. | -| `Size` | `long Size { get; init; }` | Gets the size of the file payload in bytes. | -| `TypeIndex` | `int TypeIndex { get; init; }` | Gets the index into the file-type table giving this file's extension. | - -#### `GarFormatDescriptor` - -Nintendo 3DS GAR (Generic Asset Resource) archive as used in Tomodachi Life / Animal Crossing-era titles. References: No official specification — proprietary Nintendo-era container, reverse-engineered by the 3DS modding community`https://github.com/FanTranslatorsInternational/Kuriimu2` — Kuriimu2 — fan-translation toolkit covering many 3DS archive containers - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GarFormatDescriptor` | `GarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `GarReader` - -Reads entries from a Nintendo 3DS GAR v5 archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GarReader` | `GarReader(Stream stream, bool leaveOpen = false)` | Initializes a new `GarReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Gets the file-type extension strings indexed by `TypeIndex`. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(GarEntry entry)` | Extracts the raw payload bytes for a given entry. | - -#### `GarWriter` - -Creates a Nintendo 3DS GAR v5 archive from in-memory file inputs. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GarWriter` | `GarWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `GarWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds a file to the archive. The full filename (including extension) is stored; the writer groups files of the same extension into a single type entry on `Finish`. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalizes the archive layout and writes it to the underlying stream. | - -### Namespace `FileFormat.Gem` - -[`GemFormatDescriptor`](#gemformatdescriptor) - -#### `GemFormatDescriptor` - -Descriptor for a Ruby gem package (`.gem`) — a TAR archive whose first three entries are `metadata.gz` (gzipped YAML metadata), `data.tar.gz` (gzipped TAR of the gem contents) and `checksums.yaml.gz`. References: `https://docs.ruby-lang.org/en/3.0/Gem/Format.html` — Gem::Format, the canonical package-layout documentation`https://github.com/rubygems/rubygems` — RubyGems, the reference implementation that reads and writes .gem files`https://guides.rubygems.org/` — RubyGems guides (specification reference, publishing workflow) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GemFormatDescriptor` | `GemFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Gettext` - -[`CatalogEntry`](#catalogentry) · [`MoFormatDescriptor`](#moformatdescriptor) · [`MoReader`](#moreader) · [`MoWriter`](#mowriter) · [`PoFormatDescriptor`](#poformatdescriptor) · [`PoReader`](#poreader) - -#### `CatalogEntry` - -One translatable entry in a gettext catalog. `Context` is null for keyless entries, the msgctxt string otherwise (MO encodes context as `ctx '\x04' msgid`; PO uses a dedicated `msgctxt` line). `MsgIdPlural` / `MsgStrPlural` populate when the entry has plural forms; otherwise plural is null and the single translation is in `MsgStr`. The empty-msgid entry carries the catalog's metadata header (Content-Type, Plural-Forms, …) in `MsgStr`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CatalogEntry` | `CatalogEntry(int Index, string Context, string MsgId, string MsgIdPlural, string MsgStr, IReadOnlyList MsgStrPlural)` | One translatable entry in a gettext catalog. `Context` is null for keyless entries, the msgctxt string otherwise (MO encodes context as `ctx '\x04' msgid`; PO uses a dedicated `msgctxt` line). `MsgIdPlural` / `MsgStrPlural` populate when the entry has plural forms; otherwise plural is null and the single translation is in `MsgStr`. The empty-msgid entry carries the catalog's metadata header (Content-Type, Plural-Forms, …) in `MsgStr`. | -| `Context` | `string Context { get; init; }` | | -| `Index` | `int Index { get; init; }` | | -| `MsgIdPlural` | `string MsgIdPlural { get; init; }` | | -| `MsgId` | `string MsgId { get; init; }` | | -| `MsgStrPlural` | `IReadOnlyList MsgStrPlural { get; init; }` | | -| `MsgStr` | `string MsgStr { get; init; }` | | - -#### `MoFormatDescriptor` - -Exposes a gettext .mo binary catalog as an archive of per-message text files. Entry zero with an empty msgid is the catalog metadata header. References: `https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html` — GNU gettext manual — binary MO file layout`https://www.gnu.org/software/gettext/` — GNU gettext project`https://en.wikipedia.org/wiki/Gettext` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MoFormatDescriptor` | `MoFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM creation: emits an MO catalog where each input becomes one entry. The archive name (sans path + trailing `.txt`) is used as the msgid; the input bytes (decoded as UTF-8) become the msgstr. An empty msgid signals the gettext metadata header and is placed first per the spec. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `ParseInputName` | `static ValueTuple ParseInputName(string archiveName)` | Reverses the reader's `EntryName` sanitisation back into (context, msgid). Format: `NNNN_(ctx__)?LABEL.txt` where `HEADER` represents the empty msgid. Unparseable names fall back to the leaf as the literal msgid. | - -#### `MoReader` - -Parses a GNU gettext .mo binary catalog per https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html. Magic `0x950412DE` (little-endian) or `0xDE120495` (big-endian / swapped). Handles msgctxt (separator U+0004) and plural forms (separator U+0000). - -| Member | Signature | Summary | -| --- | --- | --- | -| `MoReader` | `MoReader()` | | -| `Read` | `List Read(ReadOnlySpan data)` | | - -#### `MoWriter` - -WORM writer for GNU gettext .mo binary catalogs (little-endian, revision 0). Layout follows https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html: 28-byte header, then two parallel descriptor tables (orig + translation), then the two NUL-terminated string pools. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MoWriter` | `MoWriter()` | | -| `MagicLe` | `const uint MagicLe` | Magic for little-endian MO files (per the gettext spec). | -| `Write` | `static void Write(Stream output, IReadOnlyList entries)` | Writes an MO catalog containing `entries`. Each entry's msgid + msgstr are written as UTF-8 NUL-terminated strings. Plural forms (msgid_plural / msgstr[N]) are encoded with NUL separators per the spec. Context (msgctxt) is prefixed onto the msgid with the EOT (U+0004) separator. | - -#### `PoFormatDescriptor` - -Exposes a gettext .po text catalog as an archive of per-message text files. Matches `MoFormatDescriptor`'s entry layout; only the source-parsing path differs. References: `https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html` — GNU gettext manual — PO file syntax`https://www.gnu.org/software/gettext/` — GNU gettext project - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PoFormatDescriptor` | `PoFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PoReader` - -Parses a GNU gettext .po text catalog. Supports msgctxt, msgid / msgid_plural, msgstr / msgstr[n], and multi-line continuation strings. Comment lines (`#`, `#.`, `#:`, `#,`) are ignored. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PoReader` | `PoReader()` | | -| `Read` | `List Read(ReadOnlySpan data)` | | - -### Namespace `FileFormat.Gob` - -[`GobEntry`](#gobentry) · [`GobFormatDescriptor`](#gobformatdescriptor) · [`GobReader`](#gobreader) · [`GobWriter`](#gobwriter) - -#### `GobEntry` - -Represents a single entry in a Lucasarts GOB archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GobEntry` | `GobEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the entry name (relative path with backslash separators, up to 127 ASCII bytes). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry data within the archive. | -| `Size` | `long Size { get; init; }` | Gets the entry data length in bytes (GOB stores files uncompressed). | - -#### `GobFormatDescriptor` - -LucasArts GOB resource archive used by Star Wars: Jedi Knight (Dark Forces II) and Outlaws. References: `https://github.com/luciusDXL/TheForceEngine` — The Force Engine — maintained open reimplementation of the Jedi engine, reads GOB containersNo official specification — community-reverse-engineered LucasArts container - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GobFormatDescriptor` | `GobFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `GobReader` - -Reads entries from a Lucasarts GOB v2 archive (Jedi Knight, Outlaws). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GobReader` | `GobReader(Stream stream, bool leaveOpen = false)` | Initializes a new `GobReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive, in directory order. | -| `Version` | `uint Version { get; }` | Gets the GOB version field as written in the header (typically 0x14 or 0x20). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(GobEntry entry)` | Extracts the raw bytes for a given entry. | - -#### `GobWriter` - -Creates a Lucasarts GOB v2 archive (Jedi Knight, Outlaws). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GobWriter` | `GobWriter(Stream stream, bool leaveOpen = false, uint version = 20)` | Initializes a new `GobWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. Names use backslash separators (e.g. "data\\test.bin"). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive to the stream and finishes writing. | - -### Namespace `FileFormat.GodotPck` - -[`GodotPckFormatDescriptor`](#godotpckformatdescriptor) · [`PckEntry`](#pckentry) · [`PckReader`](#pckreader) · [`PckWriter`](#pckwriter) - -#### `GodotPckFormatDescriptor` - -Godot Engine resource pack (.pck, GDPC container). References: `https://github.com/godotengine/godot` — canonical implementation — the format is defined by core/io/file_access_pack.cpp`https://docs.godotengine.org` — Godot Engine documentation (PCK export and loading) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GodotPckFormatDescriptor` | `GodotPckFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `PckEntry` - -Represents a single file entry in a Godot PCK archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PckEntry` | `PckEntry()` | | -| `Md5` | `byte[] Md5 { get; init; }` | The 16-byte MD5 hash of the file data. | -| `Offset` | `long Offset { get; init; }` | The absolute byte offset within the PCK stream where the file data begins. | -| `Path` | `string Path { get; init; }` | The virtual path of the file (e.g. "res://scenes/main.tscn"). | -| `Size` | `long Size { get; init; }` | The uncompressed size of the file data in bytes. | - -#### `PckReader` - -Reads Godot Engine PCK (resource pack) files. Supports pack_version 1 (Godot 3.x) and pack_version 2 (Godot 4.x). - -| Member | Signature | Summary | -| --- | --- | --- | -| `PckReader` | `PckReader(Stream stream)` | Opens a PCK stream and parses the header and file directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | All file entries found in the PCK directory. | -| `PackVersion` | `uint PackVersion { get; }` | The pack format version (1 = Godot 3.x, 2 = Godot 4.x). | -| `VersionMajor` | `uint VersionMajor { get; }` | The Godot engine major version recorded in the header. | -| `VersionMinor` | `uint VersionMinor { get; }` | The Godot engine minor version recorded in the header. | -| `VersionPatch` | `uint VersionPatch { get; }` | The Godot engine patch version recorded in the header. | -| `Extract` | `byte[] Extract(PckEntry entry)` | Reads and returns the raw bytes for the given entry. | - -#### `PckWriter` - -Writes Godot Engine PCK (resource pack) files in pack_version 1 format (Godot 3.x compatible). The directory is written first, followed by file data, so all offsets can be calculated up-front without seeking back. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PckWriter` | `PckWriter(Stream output, bool leaveOpen = false)` | Creates a new PCK writer that will write to `output`. | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file to the pack. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalises the PCK and flushes all data to the underlying stream. Must be called exactly once; subsequent calls are no-ops. | - -### Namespace `FileFormat.Grp` - -[`GrpEntry`](#grpentry) · [`GrpFormatDescriptor`](#grpformatdescriptor) · [`GrpReader`](#grpreader) · [`GrpWriter`](#grpwriter) - -#### `GrpEntry` - -Entry in a BUILD Engine GRP archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GrpEntry` | `GrpEntry()` | | -| `DataOffset` | `long DataOffset { get; init; }` | Absolute byte offset of the file data within the GRP stream. | -| `Name` | `string Name { get; init; }` | File name, up to 12 characters (null-padded in the on-disk format). | -| `Size` | `int Size { get; init; }` | Uncompressed size of the file data in bytes. | - -#### `GrpFormatDescriptor` - -BUILD engine GRP game resource archive ('KenSilverman' signature + file table), used by Duke Nukem 3D and other BUILD titles. References: `https://moddingwiki.shikadi.net/wiki/GRP_Format` — DOS Game Modding Wiki — GRP format layout`https://advsys.net/ken/build.htm` — Ken Silverman's BUILD engine page (format author)`https://voidpoint.io/terminx/eduke32` — EDuke32 — maintained BUILD engine implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GrpFormatDescriptor` | `GrpFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `GrpReader` - -Reads BUILD Engine GRP archives as used by Duke Nukem 3D, Blood, and Shadow Warrior. Format: 12-byte ASCII magic "KenSilverman", uint32 LE file count, then per-file directory entries (12-byte null-padded name + uint32 LE size), followed immediately by concatenated file data. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GrpReader` | `GrpReader(Stream stream)` | Opens and parses a GRP stream. | -| `Magic` | `const string Magic` | ASCII magic string at offset 0. | -| `Entries` | `IReadOnlyList Entries { get; }` | All entries read from the archive directory. | -| `Extract` | `byte[] Extract(GrpEntry entry)` | Extracts the raw bytes for the given entry. | - -#### `GrpWriter` - -Creates BUILD Engine GRP archives. Call `AddFile` for each file, then `Finish` (or dispose) to flush. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GrpWriter` | `GrpWriter(Stream stream, bool leaveOpen = false)` | Initialises the writer targeting `stream`. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Queues a file for inclusion. The name is truncated to 12 characters if longer. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the complete GRP archive to the underlying stream. | - -### Namespace `FileFormat.Gzip` - -[`GzipConstants`](#gzipconstants) · [`GzipFormatDescriptor`](#gzipformatdescriptor) · [`GzipHeader`](#gzipheader) · [`GzipRawHelper`](#gziprawhelper) · [`GzipStream`](#gzipstream) - -#### `GzipConstants` - -Constants defined by RFC 1952 (GZIP file format). - -| Member | Signature | Summary | -| --- | --- | --- | -| `FlagComment` | `const byte FlagComment` | Flag: comment is present. | -| `FlagExtra` | `const byte FlagExtra` | Flag: extra field is present. | -| `FlagHcrc` | `const byte FlagHcrc` | Flag: header CRC16 is present. | -| `FlagName` | `const byte FlagName` | Flag: original file name is present. | -| `FlagText` | `const byte FlagText` | Flag: file is probably ASCII text. | -| `Magic1` | `const byte Magic1` | GZIP magic number byte 1. | -| `Magic2` | `const byte Magic2` | GZIP magic number byte 2. | -| `MethodDeflate` | `const byte MethodDeflate` | Compression method: Deflate. | -| `OsFat` | `const byte OsFat` | OS code: FAT filesystem (MS-DOS, OS/2, NT/Win32). | -| `OsUnix` | `const byte OsUnix` | OS code: Unix. | -| `OsUnknown` | `const byte OsUnknown` | OS code: unknown. | - -#### `GzipFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IFormatValidator`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GzipFormatDescriptor` | `GzipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The Deflate compression level applied to the GZIP payload. The optimizer searches these tiers to find the smallest output for the input. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `GzipHeader` - -Represents the header of a GZIP member (RFC 1952). - -| Member | Signature | Summary | -| --- | --- | --- | -| `GzipHeader` | `GzipHeader()` | | -| `Comment` | `string Comment { get; set; }` | Gets or sets the comment (if FCOMMENT flag is set). | -| `ExtraField` | `byte[] ExtraField { get; set; }` | Gets or sets the extra field data (if FEXTRA flag is set). | -| `ExtraFlags` | `byte ExtraFlags { get; set; }` | Gets or sets the extra flags (compression level hint). | -| `FileName` | `string FileName { get; set; }` | Gets or sets the original file name (if FNAME flag is set). | -| `Flags` | `byte Flags { get; set; }` | Gets or sets the header flags. | -| `HeaderCrc` | `ushort? HeaderCrc { get; set; }` | Gets or sets the header CRC16 (if FHCRC flag is set). | -| `Method` | `byte Method { get; set; }` | Gets or sets the compression method (always 8 for Deflate). | -| `ModificationTime` | `uint ModificationTime { get; set; }` | Gets or sets the modification time as Unix timestamp. | -| `OperatingSystem` | `byte OperatingSystem { get; set; }` | Gets or sets the operating system code. | -| `Read` | `static GzipHeader Read(Stream stream)` | Reads a GZIP header from the stream. | -| `Write` | `void Write(Stream stream)` | Writes this GZIP header to the stream. | - -#### `GzipRawHelper` - -Low-level helpers for working with raw Deflate bitstreams inside Gzip framing. Enables zero-decompression restreaming between formats sharing the Deflate codec. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Unwrap` | `static ValueTuple Unwrap(ReadOnlySpan gzipData)` | Extracts the raw Deflate bitstream from a Gzip stream without decompressing. Also returns the CRC-32 and original size from the trailer. | -| `Wrap` | `static byte[] Wrap(ReadOnlySpan deflateData, uint crc32, uint originalSize)` | Wraps a raw Deflate bitstream in Gzip framing. The caller provides the CRC-32 and original size (already known from the source format). | -| `Wrap` | `static void Wrap(Stream output, ReadOnlySpan deflateData, uint crc32, uint originalSize)` | Wraps a raw Deflate bitstream in Gzip framing, writing to a stream. | - -#### `GzipStream` - -Stream for reading and writing GZIP format data (RFC 1952). - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GzipStream` | `GzipStream(Stream stream, CompressionStreamMode mode, DeflateCompressionLevel compressionLevel, bool leaveOpen = false)` | Initializes a new `GzipStream` with a specific compression level. | -| `GzipStream` | `GzipStream(Stream stream, CompressionStreamMode mode, bool leaveOpen = false)` | Initializes a new `GzipStream` for decompression. | -| `Crc32Value` | `uint Crc32Value { get; }` | Gets the CRC-32 value of the uncompressed data. | -| `Header` | `GzipHeader Header { get; set; }` | Gets or sets the GZIP header. Set before writing to customize the header. | -| `OriginalSize` | `uint OriginalSize { get; }` | Gets the original (uncompressed) size mod 2^32. | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | - -### Namespace `FileFormat.Ha` - -[`HaEntry`](#haentry) · [`HaFormatDescriptor`](#haformatdescriptor) · [`HaModifier`](#hamodifier) · [`HaReader`](#hareader) · [`HaWriter`](#hawriter) - -#### `HaEntry` - -Represents a single entry in an Ha archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HaEntry` | `HaEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | Gets the compressed size in bytes. | -| `Crc32` | `uint Crc32 { get; init; }` | Gets the CRC-32 (IEEE polynomial) of the uncompressed data. | -| `FileName` | `string FileName { get; init; }` | Gets the filename stored in the archive (may include path with '/' separators). | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets whether this entry is a directory. | -| `LastModified` | `DateTime LastModified { get; init; }` | Gets the last-modification date/time. | -| `Method` | `int Method { get; init; }` | Gets the compression method byte (0=Store, 1=HSC, 2=ASC, 14=Directory). | -| `OriginalSize` | `uint OriginalSize { get; init; }` | Gets the uncompressed size in bytes. | - -#### `HaFormatDescriptor` - -HA archive (Harri Hirvola) with ASC (sliding-window LZ + arithmetic coding) and HSC (context modelling + arithmetic coding) methods. References: HA.DOC shipped with the HA 0.999 archiver (Harri Hirvola) — the canonical format and method descriptionNo online specification — the format is known from the archiver's released source code - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HaFormatDescriptor` | `HaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing HA archive. Uses `HaModifier` — Add appends a Stored entry at EOF; Remove walks the entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the HA archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the HA archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `HaModifier`. | - -#### `HaModifier` - -Random-access in-place modifier for HA (Harri Hirvola) archives. The HA format is a 2-byte "HA" magic followed by chained per-entry blocks; there is no central directory and no explicit end-of-archive marker — the reader simply walks until EOF. Add appends a new Stored entry at the end of the file; Remove walks the chain, locates the target by name, and shifts trailing bytes forward to compact. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream ha, string name, byte[] data)` | Appends a Stored entry to the archive. Walks the existing entry chain to find the EOF position, writes a new entry at that offset, and truncates. I/O cost is one full sequential header walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream ha, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact (HA has no central directory, so compaction is required). The "HA" magic at offset 0 is preserved. | - -#### `HaReader` - -Reads entries from an Ha archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HaReader` | `HaReader(Stream stream, bool leaveOpen = false)` | Initializes a new `HaReader` and parses the archive directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries present in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(HaEntry entry)` | Extracts and decompresses the data for the given entry. | - -#### `HaWriter` - -Creates an Ha archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HaWriter` | `HaWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `HaWriter`. | -| `AddDirectory` | `void AddDirectory(string name, DateTime? lastModified = null)` | Adds a directory entry to the archive (method 14, zero size). | -| `AddFile` | `void AddFile(string fileName, byte[] data, DateTime? lastModified = null)` | Adds a file entry to the archive using Store compression (method 0). | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.Hdf4` - -[`Hdf4FormatDescriptor`](#hdf4formatdescriptor) · [`Hdf4Reader`](#hdf4reader) · [`Hdf4Reader.DataDescriptor`](#hdf4readerdatadescriptor) · [`Hdf4Reader.Hdf4File`](#hdf4readerhdf4file) - -#### `Hdf4FormatDescriptor` - -Read-only descriptor for the classic HDF4 container (NCSA HDF v4). Walks the Data Descriptor (DD) linked list from the file prefix and emits one entry per non-empty tag/ref pair, plus a `metadata.ini` with the detected magic, total DD count and per-tag histogram. References: `https://www.hdfgroup.org/solutions/hdf4/` — The HDF Group's HDF4 page (maintained but deprecated in favour of HDF5)"HDF4 Specification and Developer's Guide" (NCSA / The HDF Group) — the defining document for the DD list and tag/ref model`https://en.wikipedia.org/wiki/Hierarchical_Data_Format` — format overview - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hdf4FormatDescriptor` | `Hdf4FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `Hdf4Reader` - -Reader for the NCSA HDF4 container (predecessor of HDF5). Walks the Data Descriptor (DD) linked list starting at the file prefix and collects each object as a `DataDescriptor` — tag + reference + file offset + length. Byte order is big-endian throughout. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hdf4Reader` | `Hdf4Reader()` | | -| `MaxBlocks` | `const int MaxBlocks` | Maximum number of DDH blocks the walker will traverse before giving up. | -| `LegacyMagic` | `static ReadOnlySpan LegacyMagic { get; }` | Older HDF 8-byte ASCII-like signature ("HDF\0\0\0\x0E\x02"). | -| `Magic` | `static ReadOnlySpan Magic { get; }` | Standard 4-byte HDF4 file signature. | -| `Read` | `static Hdf4File Read(ReadOnlySpan data)` | Parses an HDF4 file from an in-memory span. | -| `TagName` | `static string TagName(ushort tag)` | Short human-readable name for well-known HDF4 tags. | - -#### `Hdf4Reader.DataDescriptor` - -One entry of a Data Descriptor block. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DataDescriptor` | `DataDescriptor(ushort Tag, ushort Reference, uint Offset, uint Length)` | One entry of a Data Descriptor block. | -| `Length` | `uint Length { get; init; }` | | -| `Offset` | `uint Offset { get; init; }` | | -| `Reference` | `ushort Reference { get; init; }` | | -| `Tag` | `ushort Tag { get; init; }` | | - -#### `Hdf4Reader.Hdf4File` - -Parsed HDF4 file — all DD entries walked from the DD linked list. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hdf4File` | `Hdf4File(string MagicKind, IReadOnlyList DataDescriptors, IReadOnlyDictionary TagHistogram)` | Parsed HDF4 file — all DD entries walked from the DD linked list. | -| `DataDescriptors` | `IReadOnlyList DataDescriptors { get; init; }` | | -| `MagicKind` | `string MagicKind { get; init; }` | | -| `TagHistogram` | `IReadOnlyDictionary TagHistogram { get; init; }` | | - -### Namespace `FileFormat.Hdf5` - -[`Hdf5FormatDescriptor`](#hdf5formatdescriptor) · [`Hdf5SuperblockInfo`](#hdf5superblockinfo) - -#### `Hdf5FormatDescriptor` - -Read-only, metadata-surfacing descriptor for HDF5. Does not walk the full B-tree / local-heap / object-header graph; only reads the superblock and does a best-effort scan for object-header signatures (`OHDR`) in a bounded prefix of the payload. References: `https://github.com/HDFGroup/hdf5` — canonical implementation (libhdf5); the on-disk format specification is maintained in its documentation`https://www.hdfgroup.org/solutions/hdf5/` — HDF Group HDF5 portal`https://en.wikipedia.org/wiki/Hierarchical_Data_Format` — Wikipedia - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hdf5FormatDescriptor` | `Hdf5FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `Hdf5SuperblockInfo` - -Partial HDF5 parser — finds the superblock, reads the offset/length sizes and root object-header offset, and scans the file for object-header signatures. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hdf5SuperblockInfo` | `Hdf5SuperblockInfo()` | | -| `Found` | `bool Found { get; set; }` | | -| `LengthSize` | `int LengthSize { get; set; }` | | -| `OffsetSize` | `int OffsetSize { get; set; }` | | -| `RootOffset` | `long RootOffset { get; set; }` | | -| `SuperblockOffset` | `long SuperblockOffset { get; set; }` | | -| `Version` | `int Version { get; set; }` | | - -### Namespace `FileFormat.Hog` - -[`HogEntry`](#hogentry) · [`HogFormatDescriptor`](#hogformatdescriptor) · [`HogModifier`](#hogmodifier) · [`HogReader`](#hogreader) · [`HogWriter`](#hogwriter) - -#### `HogEntry` - -Represents a single file entry in a HOG archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HogEntry` | `HogEntry()` | | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the offset of the file data from the start of the HOG file. | -| `Name` | `string Name { get; init; }` | Gets the file name (up to 13 characters). | -| `Size` | `int Size { get; init; }` | Gets the size of the file data in bytes. | - -#### `HogFormatDescriptor` - -Descent / Descent II HOG game-data archive ('DHF' signature + 13-byte-name records). References: `https://github.com/dxx-rebirth/dxx-rebirth` — DXX-Rebirth — maintained open-source Descent engine and de-facto format referenceNo official specification — documented by the community from the released Descent source code - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HogFormatDescriptor` | `HogFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends (or replaces by name) files inside an existing HOG archive. HOG's record chain is naturally append-friendly: each entry is a 13-byte name + 4-byte LE size + raw data, so AddFile is a pure append at EOF — bytes `[0, oldLength)` are byte-identical afterwards. Replacement semantics drop the prior entry with the same name first (single-pass shift over the tail), then append the replacement at the new EOF. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing HOG archive. Each removal walks the record chain to locate the entry, then shifts every trailing record toward offset 0 and truncates the stream. O(image size) on the shift, O(touched bytes) on every other axis. | - -#### `HogModifier` - -In-place HOG archive modifier. The Descent I/II HOG container has the trivial structure {3-byte "DHF" magic, then sequence of [13-byte name + 4-byte LE size + size bytes of data]} — no directory, no offsets, just a chain. That makes Add an O(touched bytes) pure append at EOF, and Remove a contiguous-shift operation over the tail. Byte-identity contract: AddFile preserves `[0, oldLength)` byte-identical — it only writes new bytes at `oldLength` and beyond. RemoveFile shifts everything after the removed entry forward, then truncates. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream archive, string name, byte[] data)` | Appends a file to a HOG archive in place. Writes a 13-byte name + 4-byte LE size + data at EOF; bytes `[0, oldLength)` are byte-identical afterwards (pure append). | -| `InitializeEmpty` | `static void InitializeEmpty(Stream archive)` | Creates a fresh empty HOG archive — emits the 3-byte "DHF" magic with no entries. Used when modifying an empty stream. | -| `RemoveFile` | `static bool RemoveFile(Stream archive, string name)` | Removes the first entry matching `name` from the HOG archive. Walks the record chain, then shifts everything after the matched record's data block toward offset 0 and truncates. Returns false if no such entry is present. | - -#### `HogReader` - -Reads entries from a Descent I/II HOG archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HogReader` | `HogReader(Stream stream, bool leaveOpen = false)` | Initializes a new `HogReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file entries in the HOG archive. | -| `Magic` | `static ReadOnlySpan Magic { get; }` | The HOG magic bytes at offset 0. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(HogEntry entry)` | Extracts the data for a given entry. | - -#### `HogWriter` - -Creates a Descent I/II HOG archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HogWriter` | `HogWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `HogWriter`. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the HOG archive to the stream and finishes writing. | - -### Namespace `FileFormat.Hpi` - -[`HpiConstants`](#hpiconstants) · [`HpiEntry`](#hpientry) · [`HpiFormatDescriptor`](#hpiformatdescriptor) · [`HpiReader`](#hpireader) · [`HpiWriter`](#hpiwriter) - -#### `HpiConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `ChunkHeaderSize` | `const int ChunkHeaderSize` | | -| `ChunkMagic` | `const uint ChunkMagic` | | -| `ChunkMarkerDefault` | `const byte ChunkMarkerDefault` | | -| `CompressionLz77` | `const byte CompressionLz77` | | -| `CompressionStored` | `const byte CompressionStored` | | -| `CompressionZlib` | `const byte CompressionZlib` | | -| `DirectoryHeaderSize` | `const int DirectoryHeaderSize` | | -| `EncryptPlain` | `const byte EncryptPlain` | | -| `EntryRecordSize` | `const int EntryRecordSize` | | -| `HeaderSize` | `const int HeaderSize` | | -| `Magic` | `const uint Magic` | | -| `MaxChunkSize` | `const int MaxChunkSize` | | -| `VersionTaClassic` | `const uint VersionTaClassic` | | - -#### `HpiEntry` - -Represents a single entry (file or directory) in a Total Annihilation HPI archive. Paths use forward-slash separators and never start with a slash. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HpiEntry` | `HpiEntry()` | | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the absolute byte offset in the archive of this entry's data block (files) or sub-directory header (directories). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets a value indicating whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the full forward-slash path of the entry (e.g. `"units/armcom.fbi"`). | -| `Size` | `long Size { get; init; }` | Gets the original (uncompressed) size of the file in bytes; 0 for directories. | - -#### `HpiFormatDescriptor` - -Total Annihilation HPI (HAPI) game resource archive with chunked, zlib-subset-compressed entries. References: Total Annihilation modding-community HPI format documentation (HPIUtil and successors) — no official Cavedog specification exists`https://en.wikipedia.org/wiki/Total_Annihilation` — Wikipedia on the game - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HpiFormatDescriptor` | `HpiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `HpiReader` - -Reads the unencrypted, zlib-only subset of Total Annihilation HPI/UFO/CCX/GP3 archives. Encrypted archives (HeaderKey != 0) and TA's bespoke LZ77 chunk variant are rejected. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HpiReader` | `HpiReader(Stream stream, bool leaveOpen = false)` | Initializes a new `HpiReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries discovered in the archive (files and directories), with full forward-slash paths. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(HpiEntry entry)` | Extracts the raw, decompressed bytes of a file entry. Returns `[]` for directories. | - -#### `HpiWriter` - -Writes the unencrypted, zlib-only subset of Total Annihilation HPI archives. All file payloads are split into 64 KB SQSH chunks and compressed with zlib; chunks that fail to shrink fall back to stored to avoid bloat. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HpiWriter` | `HpiWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `HpiWriter`. | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file to the archive at the given forward-slash path. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Flushes everything to the stream and finalizes the archive. | - -### Namespace `FileFormat.IcePacker` - -[`IcePackerFormatDescriptor`](#icepackerformatdescriptor) · [`IcePackerStream`](#icepackerstream) - -#### `IcePackerFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IcePackerFormatDescriptor` | `IcePackerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `IcePackerStream` - -Compressor and decompressor for the Atari ST ICE Packer format (Axe of Delight, 1989). ICE is a stream format popular in the Atari demo scene that uses backward LZ77 with variable-length match encoding. Bits are read from end to start during decompression, and the output buffer is filled from end to start. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses raw data into ICE Packer format. | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses raw data from `input` in ICE Packer format and writes the result to `output`. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses ICE-packed data from a byte span. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses ICE-packed data from `input` and writes the original data to `output`. | - -### Namespace `FileFormat.IffCdaf` - -[`IffCdafEntry`](#iffcdafentry) · [`IffCdafFormatDescriptor`](#iffcdafformatdescriptor) · [`IffCdafModifier`](#iffcdafmodifier) · [`IffCdafReader`](#iffcdafreader) · [`IffCdafWriter`](#iffcdafwriter) - -#### `IffCdafEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `IffCdafEntry` | `IffCdafEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `IffCdafFormatDescriptor` - -Amiga IFF CDAF (Compact Disk Archive Format) — an EA-IFF-85 FORM container carrying FNAM/FDAT chunk pairs per archived file. References: "EA IFF 85: Standard for Interchange Format Files" (Jerry Morrison, Electronic Arts, 1985) — the underlying container standard`https://en.wikipedia.org/wiki/Interchange_File_Format` — Wikipedia on IFF`https://aminet.net` — Aminet — distribution home of the Amiga CDAF tooling - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IffCdafFormatDescriptor` | `IffCdafFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an IFF-CDAF archive. Uses `IffCdafModifier` — appends FNAM+FDAT chunk pairs and updates the FORM header size. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `IffCdafModifier`. | - -#### `IffCdafModifier` - -Random-access in-place modifier for IFF-CDAF archives. Each "entry" is a pair of FNAM (filename) and FDAT (file data) chunks under the FORM/CDAF container. Add appends a new FNAM+FDAT pair just before the FORM body ends and updates the FORM size. Remove locates the chunk pair, shifts trailing bytes forward, and updates the FORM size. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream cdaf, string name, byte[] data)` | Appends a (FNAM, FDAT) chunk pair to the archive and updates the FORM size header. | -| `RemoveFile` | `static bool RemoveFile(Stream cdaf, string name, bool wipeData = true)` | Removes a named entry. Returns true if found. Removes both the FNAM chunk and its following FDAT chunk, shifts trailing bytes, and updates the FORM size. | - -#### `IffCdafReader` - -Reads IFF CDAF (Compact Disk Archive Format) archives. IFF-based container with FORM/CDAF header, FNAM (filename) and FDAT (data) chunks. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IffCdafReader` | `IffCdafReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(IffCdafEntry entry)` | | - -#### `IffCdafWriter` - -Creates IFF CDAF archives with FNAM+FDAT chunk pairs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IffCdafWriter` | `IffCdafWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.InnoSetup` - -[`InnoSetupEntry`](#innosetupentry) · [`InnoSetupFormatDescriptor`](#innosetupformatdescriptor) · [`InnoSetupReader`](#innosetupreader) · [`InnoSetupWriter`](#innosetupwriter) - -#### `InnoSetupEntry` - -Represents a file or directory entry listed in an Inno Setup installer. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `InnoSetupEntry` | `InnoSetupEntry(string FileName, string DestDir, long Size, long CompressedSize, bool IsDirectory)` | Represents a file or directory entry listed in an Inno Setup installer. | -| `CompressedSize` | `long CompressedSize { get; init; }` | The compressed size in bytes, or -1 when unknown. | -| `DestDir` | `string DestDir { get; init; }` | The destination directory string from the installer header, or empty. | -| `FileName` | `string FileName { get; init; }` | The source filename or a generated name when parsing fails. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether this entry represents a directory rather than a file. | -| `Size` | `long Size { get; init; }` | The uncompressed file size in bytes, or -1 when unknown. | - -#### `InnoSetupFormatDescriptor` - -Inno Setup installer package (PE stub + Setup.0 data blob). References: `https://jrsoftware.org/isinfo.php` — official Inno Setup site (Jordan Russell)`https://github.com/dscharrer/innoextract` — innoextract — de-facto reference for the undocumented installer data layout`https://en.wikipedia.org/wiki/Inno_Setup` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `InnoSetupFormatDescriptor` | `InnoSetupFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | - -#### `InnoSetupReader` - -Reads Inno Setup installer metadata from a Windows PE executable. - -| Member | Signature | Summary | -| --- | --- | --- | -| `InnoSetupReader` | `InnoSetupReader(Stream stream)` | Opens an Inno Setup installer from a seekable stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries parsed from the Setup.0 header. | -| `Version` | `string Version { get; }` | Gets the Inno Setup version string detected in the overlay, e.g. "5.5.3". | -| `Extract` | `byte[] Extract(InnoSetupEntry entry)` | Attempts to extract the data for `entry` from the Setup.1 block. | - -#### `InnoSetupWriter` - -Writes a minimal Inno Setup header. No PE stub is emitted; the reader scans from offset 0 for the Inno signature when it can't parse a PE. Setup.0 is emitted as an empty compressed block — the reader's LZMA + zlib decompression both fail gracefully on empty input, leaving the entry list empty. This is detection-only WORM; producing a functional installer requires bundling a signed PE stub which is out of scope. - -| Member | Signature | Summary | -| --- | --- | --- | -| `InnoSetupWriter` | `InnoSetupWriter()` | | -| `WriteTo` | `void WriteTo(Stream output, byte[] embeddedData = null)` | | - -### Namespace `FileFormat.Ipa` - -[`IpaFormatDescriptor`](#ipaformatdescriptor) - -#### `IpaFormatDescriptor` - -Apple iOS application package (.ipa) — a ZIP archive laid out as Payload/AppName.app plus metadata. References: `https://en.wikipedia.org/wiki/.ipa` — Wikipedia on the .ipa bundle layout`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE ZIP APPNOTE — the underlying container format - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IpaFormatDescriptor` | `IpaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing IPA archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (IPA is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (IPA is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Jar` - -[`JarFormatDescriptor`](#jarformatdescriptor) - -#### `JarFormatDescriptor` - -Java Archive (JAR) — a ZIP container with a META-INF/MANIFEST.MF manifest. References: `https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html` — Oracle JAR File Specification`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE ZIP APPNOTE — the underlying container format`https://en.wikipedia.org/wiki/JAR_(file_format)` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `JarFormatDescriptor` | `JarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing JAR archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (JAR is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (JAR is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Kmz` - -[`KmzFormatDescriptor`](#kmzformatdescriptor) - -#### `KmzFormatDescriptor` - -Google Earth KMZ — a ZIP archive bundling a root KML document plus referenced resources. References: `https://developers.google.com/kml/documentation` — Google KML documentation (KMZ packaging rules)OGC KML 2.3 (OGC 12-007r2) — the standardized KML specification`https://en.wikipedia.org/wiki/Keyhole_Markup_Language` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `KmzFormatDescriptor` | `KmzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing KMZ archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (KMZ is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (KMZ is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Kwaj` - -[`KwajConstants`](#kwajconstants) · [`KwajFormatDescriptor`](#kwajformatdescriptor) · [`KwajStream`](#kwajstream) - -#### `KwajConstants` - -Constants for the Microsoft KWAJ compressed file format, produced by COMPRESS.EXE and used in some Windows setup packages. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DataOffsetOffset` | `const int DataOffsetOffset` | Offset of the compressed data start offset field (uint16 LE). | -| `FixedHeaderSize` | `const int FixedHeaderSize` | Total size of the fixed (non-optional) header portion. | -| `FlagHasDecompressedLength` | `const ushort FlagHasDecompressedLength` | Header flag bit 0: the four-byte decompressed data length field is present. | -| `FlagHasFilename` | `const ushort FlagHasFilename` | Header flag bit 3: a null-terminated original filename string is present. | -| `FlagUnknown1` | `const ushort FlagUnknown1` | Header flag bit 1: two unknown bytes are present. | -| `FlagUnknown2` | `const ushort FlagUnknown2` | Header flag bit 2: two unknown bytes are present. | -| `FlagsOffset` | `const int FlagsOffset` | Offset of the header flags field (uint16 LE). | -| `MagicLength` | `const int MagicLength` | Length of the magic signature in bytes. | -| `MethodLzHuffman` | `const ushort MethodLzHuffman` | Method 3 — LZ + Huffman compression, similar to LZH (not supported by this library). | -| `MethodLzss` | `const ushort MethodLzss` | Method 2 — SZDD-style LZSS compression (not supported by this library). | -| `MethodMsZip` | `const ushort MethodMsZip` | Method 4 — MSZIP (Deflate with 32 KB block reset), identical to the algorithm used inside Microsoft Cabinet files. | -| `MethodOffset` | `const int MethodOffset` | Offset of the compression method field (uint16 LE). | -| `MethodStore` | `const ushort MethodStore` | Method 0 — no compression; data is stored verbatim. | -| `MethodXor` | `const ushort MethodXor` | Method 1 — each byte is XOR-ed with 0xFF. | -| `Magic` | `static ReadOnlySpan Magic { get; }` | The 8-byte file magic: ASCII "KWAJ" followed by 0x88, 0xF0, 0x27, 0xD1. | - -#### `KwajFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `KwajFormatDescriptor` | `KwajFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `KwajStream` - -Provides static methods for reading and writing files in the Microsoft KWAJ compressed format, produced by COMPRESS.EXE and found in some Windows setup packages. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output, int method = 4, string filename = null)` | Compresses `input` using the specified KWAJ method and writes the result — including header — to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a KWAJ-format stream, writing the result to `output`. | -| `GetOriginalFilename` | `static string GetOriginalFilename(Stream input)` | Reads the KWAJ header from `input` and returns the embedded original filename, or `null` when the `FlagHasFilename` flag is not set. | - -### Namespace `FileFormat.Lbr` - -[`LbrEntry`](#lbrentry) · [`LbrFormatDescriptor`](#lbrformatdescriptor) · [`LbrModifier`](#lbrmodifier) · [`LbrReader`](#lbrreader) · [`LbrWriter`](#lbrwriter) - -#### `LbrEntry` - -Represents a single entry in a CP/M LBR archive directory. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LbrEntry` | `LbrEntry()` | | -| `Crc16` | `ushort Crc16 { get; init; }` | CRC-16 of the file data (may be 0 if not computed). | -| `CreatedDate` | `DateTime? CreatedDate { get; init; }` | Optional creation date. | -| `DataLength` | `long DataLength { get; }` | Total byte length of the file data (including any trailing padding). | -| `DataOffset` | `long DataOffset { get; }` | Byte offset of the file data from the start of the LBR file. | -| `FileName` | `string FileName { get; init; }` | Filename in "NAME.EXT" format (CP/M 8.3, uppercase). | -| `IsActive` | `bool IsActive { get; }` | Whether this entry is active (not deleted). | -| `ModifiedDate` | `DateTime? ModifiedDate { get; init; }` | Optional last-modified date. | -| `PadCount` | `byte PadCount { get; init; }` | Number of padding bytes in the last sector (0 means full sector used). | -| `SectorCount` | `ushort SectorCount { get; init; }` | Number of sectors occupied by this entry's data. | -| `SectorOffset` | `ushort SectorOffset { get; init; }` | Offset in sectors from the start of the LBR file. | -| `Status` | `byte Status { get; init; }` | Status byte: 0x00 = active, 0xFE = deleted/unused. | - -#### `LbrFormatDescriptor` - -CP/M LBR library archive (LU by Gary P. Novosielski) — a directory of stored, uncompressed member files. References: LU library utility documentation (Gary P. Novosielski) — the defining format description`https://en.wikipedia.org/wiki/LBR_(file_format)` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LbrFormatDescriptor` | `LbrFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an LBR archive. Uses `LbrModifier` — reuses deleted directory slots and appends data after the existing data region. Throws if the pre-allocated directory pool is full. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `LbrModifier`. | - -#### `LbrModifier` - -Random-access in-place modifier for CP/M LBR archives. The first directory entry is self-referencing and reserves a fixed pool of 32-byte directory slots; data sectors follow the directory. Add reuses a deleted slot and appends data at the next free sector. Remove marks the slot deleted (status 0xFE) and optionally wipes the underlying data sectors. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream lbr, string name, byte[] data, DateTime? lastModified = null)` | Appends a file to the archive. Reuses a deleted directory slot; data is placed at the next free sector run. | -| `RemoveFile` | `static bool RemoveFile(Stream lbr, string name, bool wipeData = true)` | Removes a named entry. Returns true if found. Marks the directory slot deleted (status 0xFE) and optionally wipes the data sectors. | - -#### `LbrReader` - -Reads CP/M LBR (Library) archive files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LbrReader` | `LbrReader(Stream stream, bool leaveOpen = false)` | Creates a new LBR reader over the given stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Active file entries in the archive (excludes the directory entry and deleted entries). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(LbrEntry entry)` | Extracts the raw data for the given entry. | - -#### `LbrWriter` - -Creates CP/M LBR (Library) archive files. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LbrWriter` | `LbrWriter(Stream stream, bool leaveOpen = false)` | Creates a new LBR writer that writes to the given stream. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive to the underlying stream. Called automatically on `Dispose`. | - -### Namespace `FileFormat.Lfd` - -[`LfdEntry`](#lfdentry) · [`LfdFormatDescriptor`](#lfdformatdescriptor) · [`LfdReader`](#lfdreader) · [`LfdWriter`](#lfdwriter) - -#### `LfdEntry` - -Represents a single resource entry inside a LucasArts LFD bundle. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LfdEntry` | `LfdEntry()` | | -| `DisplayName` | `string DisplayName { get; init; }` | Gets the display name (Type + "." + Name) used by tools to surface entries. | -| `Name` | `string Name { get; init; }` | Gets the entry's 8-character name. | -| `Offset` | `long Offset { get; init; }` | Gets the byte offset of the payload from the start of the LFD stream. | -| `Size` | `long Size { get; init; }` | Gets the payload size in bytes. | -| `Type` | `string Type { get; init; }` | Gets the 4-character resource type (e.g. "BMAP", "DELT", "VOIC", "RMAP"). | - -#### `LfdFormatDescriptor` - -LucasArts LFD resource bundle used by X-Wing and TIE Fighter. References: `https://github.com/MikeG621/LfdReader` — Idmr.LfdReader — community reference implementation with detailed format documentationNo official specification — community-reverse-engineered LucasArts container - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LfdFormatDescriptor` | `LfdFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `LfdReader` - -Reads resources from a LucasArts X-Wing / TIE Fighter LFD bundle. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LfdReader` | `LfdReader(Stream stream, bool leaveOpen = false)` | Initializes a new `LfdReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all resource entries discovered in the bundle (including the RMAP, if present). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(LfdEntry entry)` | Extracts the raw payload bytes for a given entry. | - -#### `LfdWriter` - -Creates a LucasArts X-Wing / TIE Fighter LFD bundle. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LfdWriter` | `LfdWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `LfdWriter`. | -| `AddEntry` | `void AddEntry(string type, string name, byte[] data)` | Adds a resource to the bundle. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Flushes the RMAP index and all resource records to the underlying stream. | - -### Namespace `FileFormat.LhF` - -[`LhFEntry`](#lhfentry) · [`LhFFormatDescriptor`](#lhfformatdescriptor) · [`LhFModifier`](#lhfmodifier) · [`LhFReader`](#lhfreader) · [`LhFWriter`](#lhfwriter) - -#### `LhFEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhFEntry` | `LhFEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `LhFFormatDescriptor` - -Amiga LhFloppy (LhF) disk archive storing whole floppy tracks with LZ77+Huffman compression. References: `https://aminet.net` — Aminet — distribution home of the Amiga disk-archiver toolingNo published specification — format reverse-engineered from the archiver - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhFFormatDescriptor` | `LhFFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) tracks inside an existing LhF archive. Uses `LhFModifier` — Add appends after the EOF position and bumps the trackCount field; Remove walks the track list and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named tracks; uses `LhFModifier`. | - -#### `LhFModifier` - -Random-access in-place modifier for LhF (LhFloppy) Amiga disk archives. LhF differs from LZH/LHA — there is no header chain. The file layout is: Add appends a new track block before EOF and bumps the trackCount field; Remove walks the track list, locates the target by name (the conventional `track_NNN.raw` produced by `LhFReader`), and shifts trailing bytes forward to compact, then decrements trackCount. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TrackSize` | `const int TrackSize` | | -| `AddFile` | `static void AddFile(Stream lhf, string name, byte[] data)` | Appends a new track to an existing LhF archive. The track number is parsed from `name` (e.g., `track_007.raw`); if the name does not encode a track number, one past the highest existing track is used. I/O cost is one full sequential walk to find EOF + the new track's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream lhf, string name, bool wipeData = true)` | Removes the named track. Returns true if found. Walks the track list, shifts trailing bytes forward to compact, then truncates and decrements the trackCount field. | - -#### `LhFReader` - -Reads LhF (LhFloppy) Amiga disk archives. Each track is independently compressed with LZ77+Huffman (similar to LhA's -lh5- method). Magic: "LhF\0" at offset 0, followed by track count and track headers. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhFReader` | `LhFReader(Stream stream, bool leaveOpen = false)` | | -| `LhFMagic` | `static readonly byte[] LhFMagic` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(LhFEntry entry)` | | - -#### `LhFWriter` - -Writes LhF (LhFloppy) Amiga disk archives. Each input becomes one 5632-byte track; smaller inputs are zero-padded, larger inputs are truncated. Tracks are LZH-compressed (lh5 layout, 8 KB window). Stored uncompressed when compression doesn't help -- mirrors the reader's "compSize == TrackSize" shortcut. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhFWriter` | `LhFWriter()` | | -| `TrackSize` | `const int TrackSize` | | -| `AddTrack` | `void AddTrack(int trackNumber, ReadOnlySpan data)` | Adds a track. `trackNumber` is written verbatim into the per-track header; the order of `AddTrack` calls determines the physical order in the output file. | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Lizard` - -[`LizardFormatDescriptor`](#lizardformatdescriptor) · [`LizardStream`](#lizardstream) - -#### `LizardFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LizardFormatDescriptor` | `LizardFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LizardStream` - -Lizard (formerly LZ5) compression stream. Frame format: magic (06 22 4D 18) + FLG + BD + ContentSize + HC + blocks + end mark. Block internals use LZ4-compatible token format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses input into the Lizard frame format. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a Lizard frame stream. | - -### Namespace `FileFormat.Lrzip` - -[`LrzipFormatDescriptor`](#lrzipformatdescriptor) · [`LrzipReader`](#lrzipreader) · [`LrzipWriter`](#lrzipwriter) - -#### `LrzipFormatDescriptor` - -Long Range ZIP (lrzip) container, LZMA-compressed subtype — an rzip-style long-range redundancy front end plus a back-end compressor. References: `https://github.com/ckolivas/lrzip` — canonical implementation (Con Kolivas); the file layout is defined by these sources`https://en.wikipedia.org/wiki/Rzip` — Wikipedia on rzip, the long-range scheme lrzip derives from - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LrzipFormatDescriptor` | `LrzipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: decompresses the single payload then re-compresses it. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: decompresses the single payload then re-compresses it. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `LrzipReader` - -Reads a Long Range Zip (lrzip) container. Only the LZMA subtype is decompressed; other method codes are surfaced via `NotSupportedException` so callers can still read header metadata (version, expanded size, hash) without erroring out. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LrzipReader` | `LrzipReader(Stream stream, bool leaveOpen = false)` | Initializes a new `LrzipReader` from a stream and parses the 38-byte header. | -| `ExpandedSize` | `ulong ExpandedSize { get; }` | Original uncompressed payload size, as recorded in the header. | -| `Flags` | `byte Flags { get; }` | Flag byte (bit 0 = encrypted; we do not support encryption). | -| `HashType` | `byte HashType { get; }` | Hash type identifier (typically 0 = MD5 of uncompressed data). | -| `Hash` | `byte[] Hash { get; }` | Stored hash (typically MD5 of uncompressed data) — preserved verbatim, not validated. | -| `MajorVersion` | `byte MajorVersion { get; }` | Container major version from the header. | -| `Method` | `byte Method { get; }` | Compression method byte (1 = LZMA, see `LrzipConstants`). | -| `MinorVersion` | `byte MinorVersion { get; }` | Container minor version from the header (0x06 = lrzip 0.6). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract()` | Decompresses the body and returns the full uncompressed payload. | - -#### `LrzipWriter` - -Writes a Long Range Zip (lrzip) container with the LZMA subtype. Other methods are not supported on the write path; the format itself documents them only for interop reading. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LrzipWriter` | `LrzipWriter()` | | -| `LzmaDictionarySize` | `int LzmaDictionarySize { get; set; }` | LZMA dictionary size in bytes. Defaults to 1 MiB. | -| `LzmaPropertiesByte` | `byte LzmaPropertiesByte { get; set; }` | LZMA properties byte. Defaults to 0x5D (lc=3 lp=0 pb=2). | -| `MajorVersion` | `byte MajorVersion { get; set; }` | Major version to write into the header. Defaults to 0. | -| `MinorVersion` | `byte MinorVersion { get; set; }` | Minor version to write into the header. Defaults to 6 (lrzip 0.6). | -| `Write` | `void Write(ReadOnlySpan input, Stream output)` | Compresses `input` with LZMA and writes a complete lrzip container (header + body) to `output`. | - -### Namespace `FileFormat.Lz4` - -[`Lz4FormatDescriptor`](#lz4formatdescriptor) · [`Lz4FrameReader`](#lz4framereader) · [`Lz4FrameWriter`](#lz4framewriter) - -#### `Lz4FormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz4FormatDescriptor` | `Lz4FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The tunable LZ4 frame knobs: encoder strength, max block size, and the two optional xxHash32 checksums (content + per-block). Every combination yields a fully conformant, self-describing LZ4 frame. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `Lz4FrameReader` - -Reads data from the LZ4 frame format (specification v1.6.1+). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz4FrameReader` | `Lz4FrameReader(Stream input)` | Initializes a new `Lz4FrameReader`. | -| `Read` | `byte[] Read()` | Reads and decompresses the entire LZ4 frame. | -| `TryReadFrameTo` | `bool TryReadFrameTo(Stream destination)` | Decodes the next LZ4 frame into `destination`, returning false at end of input. A .lz4 file may hold a sequence of frames -- that is how a large payload is written without buffering all of it -- so callers should loop. | - -#### `Lz4FrameWriter` - -Writes data in the LZ4 frame format (specification v1.6.1+). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Lz4FrameWriter` | `Lz4FrameWriter(Stream output, int blockMaxSize = 4194304, bool contentChecksum = true, bool blockChecksum = false, Lz4CompressionLevel level = 0)` | Initializes a new `Lz4FrameWriter`. | -| `Write` | `void Write(ReadOnlySpan data)` | Writes data as an LZ4 frame. | - -### Namespace `FileFormat.Lzfse` - -[`LzfseFormatDescriptor`](#lzfseformatdescriptor) · [`LzfseStream`](#lzfsestream) - -#### `LzfseFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzfseFormatDescriptor` | `LzfseFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzfseStream` - -Provides static methods for compressing and decompressing data using Apple's LZFSE block format with LZVN as the sub-algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses data from `input` and writes an LZFSE-format stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an LZFSE-format stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Lzg` - -[`LzgFormatDescriptor`](#lzgformatdescriptor) · [`LzgStream`](#lzgstream) - -#### `LzgFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzgFormatDescriptor` | `LzgFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzgStream` - -Provides LZG compression and decompression (simplified liblzg-compatible format). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses `input` to `output` using LZG encoding. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses `input` to `output` using LZG decoding. | - -### Namespace `FileFormat.Lzh` - -[`LhaConstants`](#lhaconstants) · [`LhaEntry`](#lhaentry) · [`LhaModifier`](#lhamodifier) · [`LhaReader`](#lhareader) · [`LhaWriter`](#lhawriter) · [`LzhFormatDescriptor`](#lzhformatdescriptor) · [`LzhLayoutMap`](#lzhlayoutmap) - -#### `LhaConstants` - -Constants for the LHA/LZH archive format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HeaderLevel0` | `const byte HeaderLevel0` | Header level 0 marker. | -| `HeaderLevel1` | `const byte HeaderLevel1` | Header level 1 marker. | -| `HeaderLevel2` | `const byte HeaderLevel2` | Header level 2 marker. | -| `MethodLh0` | `const string MethodLh0` | Method: no compression (store). | -| `MethodLh1` | `const string MethodLh1` | Method: 4KB window, dynamic Huffman (LHarc 1.x). | -| `MethodLh2` | `const string MethodLh2` | Method: dynamic Huffman with 8KB window (LHA 2.x). | -| `MethodLh3` | `const string MethodLh3` | Method: static Huffman with 8KB window (transitional). | -| `MethodLh4` | `const string MethodLh4` | Method: LZH compression with 4KB window (same tree format as lh5+). | -| `MethodLh5` | `const string MethodLh5` | Method: LZH compression with 8KB window. | -| `MethodLh6` | `const string MethodLh6` | Method: LZH compression with 32KB window. | -| `MethodLh7` | `const string MethodLh7` | Method: LZH compression with 64KB window. | -| `MethodLhd` | `const string MethodLhd` | Method: directory marker. | -| `MethodLz4` | `const string MethodLz4` | Method: store (same as lh0, legacy). | -| `MethodLz5` | `const string MethodLz5` | Method: LZSS with 4KB window (LArc variant). | -| `MethodLzs` | `const string MethodLzs` | Method: LZSS with 4KB window (no Huffman). | -| `MethodPm0` | `const string MethodPm0` | Method: PMA store (no compression). | -| `MethodPm1` | `const string MethodPm1` | Method: PMA PPMd order-2 compression. | -| `MethodPm2` | `const string MethodPm2` | Method: PMA PPMd order-3 compression. | -| `OsIdentifierUnix` | `const byte OsIdentifierUnix` | The system a level-1 header says it was written on: 'U' for Unix. | - -#### `LhaEntry` - -Represents an entry in an LHA/LZH archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhaEntry` | `LhaEntry()` | | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `Crc16` | `ushort Crc16 { get; set; }` | Gets or sets the CRC-16 of the original data. | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name. | -| `HeaderLevel` | `byte HeaderLevel { get; set; }` | Gets or sets the header level (0, 1, or 2). | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last modification time. | -| `Method` | `string Method { get; set; }` | Gets or sets the compression method (e.g. "-lh5-"). | -| `OriginalSize` | `long OriginalSize { get; set; }` | Gets or sets the original (uncompressed) size in bytes. | -| `OsId` | `byte OsId { get; set; }` | Gets or sets the OS identifier. | - -#### `LhaModifier` - -Random-access in-place modifier for LHA/LZH archives. Add appends a new entry just before the implicit EOF (the LHA writer doesn't emit an explicit terminator; readers stop at a header_size byte of 0 or end-of-stream). Remove walks the entry chain, locates the target, and shifts trailing bytes forward to compact. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream lha, string name, byte[] data, string method = "-lh5-")` | Appends a file to an LHA archive. Walks the existing header chain to find the EOF position, then writes a new -lh5- entry at that offset and truncates. I/O cost is one full sequential header walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream lha, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact (LHA has no central directory, so compaction is required). | - -#### `LhaReader` - -Reads entries from an LHA/LZH archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhaReader` | `LhaReader(Stream stream, bool leaveOpen = false)` | Initializes a new `LhaReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the archive. | -| `Dispose` | `void Dispose()` | | -| `ExtractEntry` | `byte[] ExtractEntry(LhaEntry entry)` | Extracts the data for an entry. | - -#### `LhaWriter` - -Creates LHA/LZH archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LhaWriter` | `LhaWriter(string method = "-lh5-")` | Initializes a new `LhaWriter`. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, string method = "-lh5-")` | Creates an LHA archive split into multiple volumes. | -| `ToArray` | `byte[] ToArray()` | Creates an LHA archive as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the archive to a stream. | - -#### `LzhFormatDescriptor` - -LHA/LZH archive — the LZSS+Huffman archiver family historically dominant in Japan and on the Amiga. References: `https://github.com/jca02266/lha` — LHa for UNIX — maintained canonical implementation; header layouts documented in the source tree`https://en.wikipedia.org/wiki/LHA_(file_format)` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhFormatDescriptor` | `LzhFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing LHA/LZH archive. Uses `LhaModifier` — Add appends after the EOF position, Remove walks the chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the LHA archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the LHA archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single LHA/LZH entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's original size so callers see the universal isolation contract. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `LhaModifier`. | - -#### `LzhLayoutMap` - -Walks an LHA/LZH archive and emits the byte-level layout: each entry's variable-length header as MetadataReserved and compressed data as Used. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -### Namespace `FileFormat.Lzham` - -[`LzhamFormatDescriptor`](#lzhamformatdescriptor) · [`LzhamStream`](#lzhamstream) - -#### `LzhamFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzhamFormatDescriptor` | `LzhamFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzhamStream` - -LZHAM stream format: 4-byte magic "LZHM" followed by the raw LZHAM building block output (4-byte LE original size + compressed data). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Lzip` - -[`LzipConstants`](#lzipconstants) · [`LzipFormatDescriptor`](#lzipformatdescriptor) · [`LzipStream`](#lzipstream) - -#### `LzipConstants` - -Constants for the Lzip (.lz) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HeaderSize` | `const int HeaderSize` | Size of the Lzip member header in bytes. | -| `LzmaPropertiesByte` | `const byte LzmaPropertiesByte` | LZMA property byte used by Lzip: lc=3, lp=0, pb=2. Computed as: lc + 9 * (lp + 5 * pb) = 3 + 9 * (0 + 10) = 93 = 0x5D. | -| `Magic0` | `const byte Magic0` | Magic byte 0: 'L'. | -| `Magic1` | `const byte Magic1` | Magic byte 1: 'Z'. | -| `Magic2` | `const byte Magic2` | Magic byte 2: 'I'. | -| `Magic3` | `const byte Magic3` | Magic byte 3: 'P'. | -| `MaxDictionarySize` | `const int MaxDictionarySize` | Maximum allowed dictionary size (512 MiB). | -| `MinDictionarySize` | `const int MinDictionarySize` | Minimum allowed dictionary size (4 KiB). | -| `TrailerSize` | `const int TrailerSize` | Size of the Lzip member trailer in bytes. | -| `Version` | `const byte Version` | The only supported format version. | - -#### `LzipFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzipFormatDescriptor` | `LzipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The tunable Lzip knobs: LZMA effort level and dictionary size. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzipStream` - -Provides static methods for reading and writing Lzip (.lz) format members. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output, int dictionarySize = 8388608, LzmaCompressionLevel level = 1)` | Compresses all data from `input` and writes a single Lzip member to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a single Lzip member from `input` and writes the uncompressed data to `output`. | - -### Namespace `FileFormat.Lzma` - -[`LzmaConstants`](#lzmaconstants) · [`LzmaFormatDescriptor`](#lzmaformatdescriptor) · [`LzmaStream`](#lzmastream) - -#### `LzmaConstants` - -Constants for the LZMA alone (.lzma) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultDictionarySize` | `const int DefaultDictionarySize` | Default dictionary size: 8 MiB. | -| `HeaderSize` | `const int HeaderSize` | Total size of the LZMA alone header in bytes (1 properties + 4 dict size + 8 uncompressed size). | -| `UnknownSize` | `const long UnknownSize` | Sentinel value stored in the uncompressed-size field when the size is unknown. The decoder uses end-of-stream marker detection in this case. | - -#### `LzmaFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzmaFormatDescriptor` | `LzmaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The tunable LZMA knobs: compression level, dictionary size and the lc/lp/pb literal/position modelling bits. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzmaStream` - -Provides static methods for reading and writing the LZMA alone (.lzma) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output, int dictionarySize = 8388608, int lc = 3, int lp = 0, int pb = 2, LzmaCompressionLevel level = 1)` | Compresses data from `input` and writes the LZMA alone stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an LZMA alone stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Lzop` - -[`LzopConstants`](#lzopconstants) · [`LzopFormatDescriptor`](#lzopformatdescriptor) · [`LzopReader`](#lzopreader) · [`LzopWriter`](#lzopwriter) - -#### `LzopConstants` - -Constants for the LZOP file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockSize` | `const int BlockSize` | The block size used when splitting large inputs: 256 KB. | -| `DefaultLevel` | `const byte DefaultLevel` | Default compression level. | -| `FlagAdler32C` | `const uint FlagAdler32C` | Flag bit: include Adler-32 checksum for compressed data. | -| `FlagAdler32D` | `const uint FlagAdler32D` | Flag bit: include Adler-32 checksum for uncompressed data. | -| `LibVersion` | `const ushort LibVersion` | The LZO library version reported in the header. | -| `MethodLzo1X115` | `const byte MethodLzo1X115` | What lzop -1 writes: LZO1X-1 with a fifteen-bit hash. | -| `MethodLzo1X1` | `const byte MethodLzo1X1` | LZO1X-1 compression method identifier. | -| `MethodLzo1X999` | `const byte MethodLzo1X999` | What lzop -7 and above write: LZO1X-999. | -| `VersionNeeded` | `const ushort VersionNeeded` | The minimum LZOP version required to decompress files written by this implementation. | -| `Version` | `const ushort Version` | The LZOP file format version written by this implementation (1.0.3.0). | -| `Magic` | `static ReadOnlySpan Magic { get; }` | The LZOP magic number: 9 bytes that begin every LZOP file. | - -#### `LzopFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzopFormatDescriptor` | `LzopFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzopReader` - -Reads and decompresses LZOP format files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzopReader` | `LzopReader(Stream stream)` | Initializes a new `LzopReader` that reads from the given stream. | -| `OriginalFileName` | `string OriginalFileName { get; }` | Gets the original filename stored in the LZOP header, or `null` if none was stored. | -| `Decompress` | `byte[] Decompress()` | Reads and decompresses all blocks from the LZOP stream. | - -#### `LzopWriter` - -Writes data to the LZOP file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, string fileName = null, LzoCompressionLevel level = 0)` | Compresses the given data and returns it wrapped in an LZOP container. | - -### Namespace `FileFormat.Lzs` - -[`LzsFormatDescriptor`](#lzsformatdescriptor) · [`LzsStream`](#lzsstream) - -#### `LzsFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzsFormatDescriptor` | `LzsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `LzsStream` - -LZS stream format: 4-byte magic header followed by LZS building block output (4-byte LE uncompressed size + compressed bitstream). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Lzx` - -[`LzxAmigaEntry`](#lzxamigaentry) · [`LzxAmigaFormatDescriptor`](#lzxamigaformatdescriptor) · [`LzxAmigaReader`](#lzxamigareader) · [`LzxAmigaWriter`](#lzxamigawriter) - -#### `LzxAmigaEntry` - -Represents a single entry in an Amiga LZX archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxAmigaEntry` | `LzxAmigaEntry()` | | -| `Attributes` | `uint Attributes { get; init; }` | Gets the Amiga file attributes (RWED bits etc.). | -| `Comment` | `string Comment { get; init; }` | Gets the entry comment, or an empty string if none. | -| `CompressedSize` | `uint CompressedSize { get; init; }` | Gets the compressed size in bytes. May be 0 for merged (solid) entries whose data is part of the group's final entry. | -| `Crc` | `uint Crc { get; init; }` | Gets the CRC-32 of the uncompressed data. | -| `FileName` | `string FileName { get; init; }` | Gets the filename of the entry. | -| `IsMerged` | `bool IsMerged { get; init; }` | Gets whether this entry is merged with the following entry (solid group). When `true`, this entry's compressed data is combined with subsequent entries until a non-merged entry is reached. | -| `LastModified` | `DateTime LastModified { get; init; }` | Gets the last-modified timestamp. | -| `MachineType` | `byte MachineType { get; init; }` | Gets the machine type (0 = Amiga, 1 = Unix, 2 = PC). | -| `Method` | `byte Method { get; init; }` | Gets the compression method (0 = Stored, 2 = LZX). | -| `OriginalSize` | `uint OriginalSize { get; init; }` | Gets the uncompressed size in bytes. | - -#### `LzxAmigaFormatDescriptor` - -Amiga LZX archive (Jonathan Forbes and Tomi Salo) — LZ77+Huffman with merged-file compression groups. References: `https://en.wikipedia.org/wiki/LZX` — Wikipedia — covers the Amiga LZX archiver lineage`https://aminet.net` — Aminet — home of the original archiver and the unlzx extractor whose source is the de-facto format reference - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxAmigaFormatDescriptor` | `LzxAmigaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the LZX archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the LZX archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `LzxAmigaReader` - -Reads entries from an Amiga LZX archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxAmigaReader` | `LzxAmigaReader(Stream stream, bool leaveOpen = false)` | Initializes a new `LzxAmigaReader` and reads the archive directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries present in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(LzxAmigaEntry entry)` | Extracts the uncompressed data for the specified entry. | - -#### `LzxAmigaWriter` - -Creates an Amiga LZX archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LzxAmigaWriter` | `LzxAmigaWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `LzxAmigaWriter`. | -| `AddFileLzx` | `void AddFileLzx(string name, byte[] data, DateTime? lastModified = null)` | Adds a file to the archive using LZX compression. | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? lastModified = null)` | Adds a file to the archive using Store method (no compression). | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.M3u8` - -[`M3u8FormatDescriptor`](#m3u8formatdescriptor) · [`M3u8Reader`](#m3u8reader) · [`M3u8Reader.Playlist`](#m3u8readerplaylist) · [`M3u8Reader.Segment`](#m3u8readersegment) · [`M3u8Reader.VariantStream`](#m3u8readervariantstream) - -#### `M3u8FormatDescriptor` - -Pseudo-archive descriptor for HTTP Live Streaming M3U8 playlists (RFC 8216). Surfaces the parsed manifest as `metadata.ini`, `playlist.txt` (verbatim source), and `segments.txt` (one entry per variant or segment). References: `https://www.rfc-editor.org/rfc/rfc8216` — RFC 8216 — HTTP Live Streaming (defines the extended M3U playlist)`https://developer.apple.com/streaming/` — Apple HLS portal`https://en.wikipedia.org/wiki/M3U` — Wikipedia - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `M3u8FormatDescriptor` | `M3u8FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `M3u8Reader` - -Reader for HLS M3U8 playlists per RFC 8216. - -| Member | Signature | Summary | -| --- | --- | --- | -| `M3u8Reader` | `M3u8Reader()` | | -| `Read` | `static Playlist Read(string text)` | Parses a UTF-8 M3U8 text body. Throws if the leading `#EXTM3U` tag is missing. | - -#### `M3u8Reader.Playlist` - -Parsed playlist contents. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Playlist` | `Playlist(bool IsMaster, int? Version, int? TargetDurationSeconds, int? MediaSequence, string PlaylistType, bool EndList, IReadOnlyList Variants, IReadOnlyList Segments, string RawText)` | Parsed playlist contents. | -| `EndList` | `bool EndList { get; init; }` | | -| `IsMaster` | `bool IsMaster { get; init; }` | | -| `MediaSequence` | `int? MediaSequence { get; init; }` | | -| `PlaylistType` | `string PlaylistType { get; init; }` | | -| `RawText` | `string RawText { get; init; }` | | -| `Segments` | `IReadOnlyList Segments { get; init; }` | | -| `TargetDurationSeconds` | `int? TargetDurationSeconds { get; init; }` | | -| `Variants` | `IReadOnlyList Variants { get; init; }` | | -| `Version` | `int? Version { get; init; }` | | - -#### `M3u8Reader.Segment` - -One segment entry from a media playlist (`#EXTINF` + URI). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Segment` | `Segment(double DurationSeconds, string Title, string Uri)` | One segment entry from a media playlist (`#EXTINF` + URI). | -| `DurationSeconds` | `double DurationSeconds { get; init; }` | | -| `Title` | `string Title { get; init; }` | | -| `Uri` | `string Uri { get; init; }` | | - -#### `M3u8Reader.VariantStream` - -One variant entry from a master playlist (the `#EXT-X-STREAM-INF` attribute pairs paired with the URI on the next non-tag line). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VariantStream` | `VariantStream(IReadOnlyDictionary Attributes, string Uri)` | One variant entry from a master playlist (the `#EXT-X-STREAM-INF` attribute pairs paired with the URI on the next non-tag line). | -| `Attributes` | `IReadOnlyDictionary Attributes { get; init; }` | | -| `Uri` | `string Uri { get; init; }` | | - -### Namespace `FileFormat.MacBinary` - -[`MacBinaryFormatDescriptor`](#macbinaryformatdescriptor) · [`MacBinaryHeader`](#macbinaryheader) · [`MacBinaryReader`](#macbinaryreader) · [`MacBinaryWriter`](#macbinarywriter) - -#### `MacBinaryFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MacBinaryFormatDescriptor` | `MacBinaryFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `MacBinaryHeader` - -Represents the 128-byte header of a MacBinary encoded file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MacBinaryHeader` | `MacBinaryHeader()` | | -| `CreatedDate` | `DateTime CreatedDate { get; init; }` | File creation date. | -| `DataForkLength` | `uint DataForkLength { get; init; }` | Length of the data fork in bytes. | -| `FileCreator` | `byte[] FileCreator { get; init; }` | 4-byte Mac creator code (e.g., "ttxt"). | -| `FileName` | `string FileName { get; init; }` | Mac filename (1-63 characters). | -| `FileType` | `byte[] FileType { get; init; }` | 4-byte Mac file type (e.g., "TEXT"). | -| `FinderFlags` | `byte FinderFlags { get; init; }` | Finder flags high byte. | -| `HeaderCrc` | `ushort HeaderCrc { get; init; }` | CRC-16 of header bytes 0-123 (MacBinary II and III). | -| `ModifiedDate` | `DateTime ModifiedDate { get; init; }` | File modification date. | -| `ResourceForkLength` | `uint ResourceForkLength { get; init; }` | Length of the resource fork in bytes. | -| `Version` | `byte Version { get; init; }` | MacBinary version (0 = I, 129 = II, 130 = III). | - -#### `MacBinaryReader` - -Reads MacBinary I/II/III encoded files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MacBinaryReader` | `MacBinaryReader()` | | -| `IsMacBinary` | `static bool IsMacBinary(Stream input)` | Checks whether the stream contains a valid MacBinary header. | -| `ReadDataFork` | `static byte[] ReadDataFork(Stream input)` | Reads the data fork from the stream. The stream must be positioned at the start of the MacBinary file. | -| `ReadHeader` | `static MacBinaryHeader ReadHeader(Stream input)` | Reads and parses the 128-byte MacBinary header from the current stream position. | -| `ReadResourceFork` | `static byte[] ReadResourceFork(Stream input)` | Reads the resource fork from the stream. The stream must be positioned at the start of the MacBinary file. | - -#### `MacBinaryWriter` - -Writes MacBinary I/II/III encoded files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MacBinaryWriter` | `MacBinaryWriter()` | | -| `Write` | `static void Write(Stream output, string fileName, byte[] dataFork, byte[] resourceFork = null, string fileType = null, string fileCreator = null, DateTime? modified = null, int version = 130)` | Writes a MacBinary encoded file to the output stream. | - -### Namespace `FileFormat.Maff` - -[`MaffFormatDescriptor`](#maffformatdescriptor) - -#### `MaffFormatDescriptor` - -Mozilla Archive Format (MAFF) — a ZIP container of saved web pages plus RDF metadata. References: `https://en.wikipedia.org/wiki/Mozilla_Archive_Format` — WikipediaMAFF specification by the Mozilla Archive Format add-on project (formerly maf.mozdev.org; mozdev has shut down) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MaffFormatDescriptor` | `MaffFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing MAFF archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (MAFF is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (MAFF is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Matroska` - -[`EbmlReader`](#ebmlreader) · [`EbmlReader.Element`](#ebmlreaderelement) · [`MkvCuesFrontOptimizer`](#mkvcuesfrontoptimizer) · [`MkvDemuxer`](#mkvdemuxer) · [`MkvDemuxer.Attachment`](#mkvdemuxerattachment) · [`MkvDemuxer.DemuxResult`](#mkvdemuxerdemuxresult) · [`MkvDemuxer.FrameEntry`](#mkvdemuxerframeentry) · [`MkvDemuxer.Track`](#mkvdemuxertrack) · [`MkvFormatDescriptor`](#mkvformatdescriptor) · [`MkvLayoutMap`](#mkvlayoutmap) - -#### `EbmlReader` - -Raw EBML (Extensible Binary Meta Language) element reader. IDs and size fields are variable-width unsigned integers with a leading-bit marker; the body is opaque bytes or a nested sequence of EBML elements depending on the schema. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EbmlReader` | `EbmlReader(byte[] data)` | | -| `Body` | `ReadOnlySpan Body(Element el)` | | -| `Children` | `IEnumerable Children(Element master)` | Iterates direct child elements of a master element body. | -| `ReadBinary` | `byte[] ReadBinary(Element el)` | | -| `ReadSigned` | `long ReadSigned(Element el)` | | -| `ReadString` | `string ReadString(Element el)` | | -| `ReadUnsigned` | `ulong ReadUnsigned(Element el)` | | -| `Read` | `Element? Read(ref long pos)` | Reads one element at `pos`, advancing it past the element. | - -#### `EbmlReader.Element` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Element` | `Element(ulong Id, long BodyOffset, long BodyLength)` | | -| `BodyLength` | `long BodyLength { get; init; }` | | -| `BodyOffset` | `long BodyOffset { get; init; }` | | -| `Id` | `ulong Id { get; init; }` | | - -#### `MkvCuesFrontOptimizer` - -MKV/WebM optimizer that moves the Cues element (seek index) to the front of the Segment, before the first Cluster. This enables fast seeking without downloading the entire file, analogous to MP4 fast-start (moov before mdat). - -Implements `IFileInternalChunkMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MkvCuesFrontOptimizer` | `MkvCuesFrontOptimizer()` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `MkvDemuxer` - -Walks a Matroska/WebM file and produces per-track raw elementary-stream blobs, plus attachments and chapters as addressable entries. Video tracks known to be H.264/HEVC get Annex-B start-codes prepended, with SPS/PPS extracted from `CodecPrivate`; other codecs pass through as concatenated frame bytes. Compression (header-stripping, zlib, bzlib) per track's ContentEncoding is intentionally not decoded — in practice the frame-compression codepath is extremely rare in real-world MKVs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MkvDemuxer` | `MkvDemuxer()` | | -| `Demux` | `DemuxResult Demux(byte[] file)` | | - -#### `MkvDemuxer.Attachment` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Attachment` | `Attachment(string FileName, string MimeType, byte[] Data)` | | -| `Data` | `byte[] Data { get; init; }` | | -| `FileName` | `string FileName { get; init; }` | | -| `MimeType` | `string MimeType { get; init; }` | | - -#### `MkvDemuxer.DemuxResult` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DemuxResult` | `DemuxResult(IReadOnlyList Tracks, IReadOnlyList Attachments, byte[] ChaptersXml)` | | -| `Attachments` | `IReadOnlyList Attachments { get; init; }` | | -| `ChaptersXml` | `byte[] ChaptersXml { get; init; }` | | -| `Tracks` | `IReadOnlyList Tracks { get; init; }` | | - -#### `MkvDemuxer.FrameEntry` - -A single block (frame) from a track. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FrameEntry` | `FrameEntry(byte[] Data)` | A single block (frame) from a track. | -| `Data` | `byte[] Data { get; init; }` | | - -#### `MkvDemuxer.Track` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Track` | `Track(int Number, string TrackType, string CodecId, string Language, byte[] CodecPrivate, byte[] FrameBytes, IReadOnlyList Frames, int AudioChannels = 0, int AudioSampleRate = 0, int AudioBitDepth = 0)` | | -| `AudioBitDepth` | `int AudioBitDepth { get; init; }` | | -| `AudioChannels` | `int AudioChannels { get; init; }` | | -| `AudioSampleRate` | `int AudioSampleRate { get; init; }` | | -| `CodecId` | `string CodecId { get; init; }` | | -| `CodecPrivate` | `byte[] CodecPrivate { get; init; }` | | -| `FrameBytes` | `byte[] FrameBytes { get; init; }` | | -| `Frames` | `IReadOnlyList Frames { get; init; }` | | -| `Language` | `string Language { get; init; }` | | -| `Number` | `int Number { get; init; }` | | -| `TrackType` | `string TrackType { get; init; }` | | - -#### `MkvFormatDescriptor` - -Surfaces a Matroska/WebM file as an archive: one entry per demuxed track, plus attachments, plus chapters XML when present. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFileInternalChunkMover`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MkvFormatDescriptor` | `MkvFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `MkvLayoutMap` - -Walks the top-level and first-level EBML elements of a Matroska/WebM file and emits `DefragBlockInfo` tiles. SeekHead/Info/Tracks/Cues are classified as MetadataReserved; each Cluster is classified as Used. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream file)` | | - -### Namespace `FileFormat.Mcm` - -[`McmFormatDescriptor`](#mcmformatdescriptor) · [`McmStream`](#mcmstream) - -#### `McmFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `McmFormatDescriptor` | `McmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `McmStream` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Mhk` - -[`MhkEntry`](#mhkentry) · [`MhkFormatDescriptor`](#mhkformatdescriptor) · [`MhkReader`](#mhkreader) · [`MhkWriter`](#mhkwriter) - -#### `MhkEntry` - -Represents a single resource entry in a Cyan Mohawk (MHK) archive. Resources are uniquely identified by the (Type, Id) pair; names are optional metadata. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MhkEntry` | `MhkEntry()` | | -| `DisplayName` | `string DisplayName { get; init; }` | Gets the synthetic display name used by tools: `TYPE_id` or `TYPE_id_name` if a name is present. | -| `Id` | `ushort Id { get; init; }` | Gets the game-specific 16-bit resource identifier. | -| `Name` | `string Name { get; init; }` | Gets the optional resource name from the per-type name table (may be null). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the file's data inside the MHK stream. | -| `Size` | `long Size { get; init; }` | Gets the file size in bytes (encoded as 24+8 bits in the file table). | -| `Type` | `string Type { get; init; }` | Gets the 4-character ASCII FourCC resource type tag (e.g. "tBMP", "tWAV", "NAME"). | - -#### `MhkFormatDescriptor` - -Cyan / Broderbund Mohawk (MHWK) resource archive used by Myst, Riven and Living Books titles. References: `https://github.com/scummvm/scummvm` — ScummVM — the Mohawk engine is the de-facto reference implementation`https://wiki.scummvm.org` — ScummVM wiki — Mohawk engine and archive documentation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MhkFormatDescriptor` | `MhkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single Mohawk entry as a bounded read-only stream. Entry names follow the flat `DisplayName + ".bin"` convention used by Extract. The decoded bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length. | - -#### `MhkReader` - -Reads resources from a Cyan Mohawk (MHK) archive used by Myst, Riven, Cosmic Osmo and the Living Books titles. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MhkReader` | `MhkReader(Stream stream, bool leaveOpen = false)` | Initializes a new `MhkReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all resource entries discovered in the archive (one per file-table slot, per (Type, Id) pair). | -| `Version` | `ushort Version { get; }` | Gets the Mohawk version word from the RSRC header (typically 0x0100). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(MhkEntry entry)` | Extracts the raw payload bytes for a given resource entry. | - -#### `MhkWriter` - -Creates a Cyan Mohawk (MHK) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MhkWriter` | `MhkWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `MhkWriter`. | -| `AddEntry` | `void AddEntry(string type, ushort id, string name, byte[] data)` | Adds a resource to the archive. Type/id pairs identify resources; names are optional metadata. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Flushes the outer/inner headers, all payloads, and the resource directory to the underlying stream. | - -### Namespace `FileFormat.Mix` - -[`MixEntry`](#mixentry) · [`MixFormatDescriptor`](#mixformatdescriptor) · [`MixReader`](#mixreader) · [`MixWriter`](#mixwriter) · [`WestwoodCrc`](#westwoodcrc) - -#### `MixEntry` - -Represents a single entry in a Westwood TD/RA1 MIX archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MixEntry` | `MixEntry()` | | -| `Id` | `uint Id { get; init; }` | Gets the Westwood 32-bit ID hash of the original filename. | -| `Name` | `string Name { get; init; }` | Gets the entry name. May be the original filename (writer side) or a synthetic `<0xXXXXXXXX>` placeholder (reader side). | -| `Offset` | `long Offset { get; init; }` | Gets the offset of the entry data relative to the start of the body section. | -| `Size` | `long Size { get; init; }` | Gets the entry size in bytes. | - -#### `MixFormatDescriptor` - -Westwood Studios MIX archive (Command and Conquer: Tiberian Dawn / Red Alert variant) — header plus CRC-keyed file table. References: `https://github.com/OpenRA/OpenRA` — OpenRA — maintained open reimplementation with a MIX readerXCC Utilities (Olaf van der Spek) — long-standing de-facto MIX reference implementationNo official specification — community-reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MixFormatDescriptor` | `MixFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `MixReader` - -Reads entries from a Westwood TD/RA1 MIX archive (no encryption, no checksum). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MixReader` | `MixReader(Stream stream, bool leaveOpen = false)` | Initializes a new `MixReader` from a stream. | -| `BodySize` | `long BodySize { get; }` | Gets the total body size declared in the header (sum of all file payload sizes). | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the MIX archive, in directory order (sorted ascending by Westwood ID). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(MixEntry entry)` | Extracts the raw bytes for a given entry. | - -#### `MixWriter` - -Creates a Westwood TD/RA1 MIX archive (no encryption, no checksum). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MixWriter` | `MixWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `MixWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the MIX archive to the stream and finishes writing. | - -#### `WestwoodCrc` - -Computes the 32-bit Westwood "classic" file ID used by Tiberian Dawn / Red Alert 1 MIX archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hash` | `static uint Hash(string filename)` | Computes the Westwood TD/RA1 32-bit file ID for the given filename. | - -### Namespace `FileFormat.Mp4` - -[`BoxParser`](#boxparser) · [`BoxParser.Box`](#boxparserbox) · [`Mp4Demuxer`](#mp4demuxer) · [`Mp4Demuxer.SampleEntry`](#mp4demuxersampleentry) · [`Mp4Demuxer.Track`](#mp4demuxertrack) · [`Mp4FastStart`](#mp4faststart) · [`Mp4FastStart.AtomInfo`](#mp4faststartatominfo) · [`Mp4FormatDescriptor`](#mp4formatdescriptor) · [`Mp4LayoutMap`](#mp4layoutmap) - -#### `BoxParser` - -ISO Base Media File Format (ISO/IEC 14496-12) box walker. An MP4/MOV/3GP file is a tree of boxes, each with a 32-bit size, 4-char type, optional 64-bit largesize, and a body. Compound boxes (moov, trak, mdia, minf, …) contain child boxes; leaf boxes (mdat, tkhd, hdlr, …) carry payload bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BoxParser` | `BoxParser()` | | -| `FindAll` | `static IEnumerable FindAll(IEnumerable boxes, string type)` | | -| `Find` | `static Box Find(IEnumerable boxes, string type)` | | -| `Parse` | `List Parse(ReadOnlySpan data)` | | - -#### `BoxParser.Box` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Box` | `Box(string Type, long Offset, long Size, long BodyOffset, long BodyLength, List Children)` | | -| `BodyLength` | `long BodyLength { get; init; }` | | -| `BodyOffset` | `long BodyOffset { get; init; }` | | -| `Children` | `List Children { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Size` | `long Size { get; init; }` | | -| `Type` | `string Type { get; init; }` | | - -#### `Mp4Demuxer` - -Demuxes an MP4/MOV file to raw per-track elementary streams. This is not a full decoder: video tracks become Annex-B NALU streams (for H.264/HEVC, SPS/PPS extracted from `avcC`/`hvcC` and prepended); audio tracks get the raw sample data in track order; all other track types are written as the flat concatenation of their samples, which is useful for triage even when the codec is obscure. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp4Demuxer` | `Mp4Demuxer()` | | -| `Demux` | `IReadOnlyList Demux(byte[] file)` | | - -#### `Mp4Demuxer.SampleEntry` - -A single sample (video frame or audio packet). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SampleEntry` | `SampleEntry(byte[] Data)` | A single sample (video frame or audio packet). | -| `Data` | `byte[] Data { get; init; }` | | - -#### `Mp4Demuxer.Track` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Track` | `Track(int Id, string HandlerType, string CodecFourCc, byte[] Data, long DurationTicks, int Timescale, IReadOnlyList Samples)` | | -| `CodecFourCc` | `string CodecFourCc { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `DurationTicks` | `long DurationTicks { get; init; }` | | -| `HandlerType` | `string HandlerType { get; init; }` | | -| `Id` | `int Id { get; init; }` | | -| `Samples` | `IReadOnlyList Samples { get; init; }` | | -| `Timescale` | `int Timescale { get; init; }` | | - -#### `Mp4FastStart` - -MP4 fast-start optimizer. Moves the `moov` atom before `mdat` so browsers and players can begin playback immediately without downloading the entire file. Patches `stco` and `co64` chunk-offset tables inside `moov` to account for the position shift. - -Implements `IFileInternalChunkMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp4FastStart` | `Mp4FastStart()` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | -| `PatchChunkOffsets` | `static void PatchChunkOffsets(byte[] data, int start, int end, long delta)` | Recursively patches stco and co64 atoms inside moov. Walks the atom tree looking for compound containers and leaf offset tables. | -| `WalkTopLevelAtoms` | `static List WalkTopLevelAtoms(Stream file)` | Walks top-level atoms in the stream and returns their positions. | - -#### `Mp4FastStart.AtomInfo` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AtomInfo` | `AtomInfo(string Type, long Offset, long Size, int HeaderSize)` | | -| `HeaderSize` | `int HeaderSize { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Size` | `long Size { get; init; }` | | -| `Type` | `string Type { get; init; }` | | - -#### `Mp4FormatDescriptor` - -Exposes an MP4/MOV file as an archive of demuxed tracks. Video tracks produce raw H.264 Annex-B (or raw sample data for non-H.264 codecs); audio tracks produce the concatenated sample payload in track order. Not a re-muxer — the output is elementary streams, not playable MP4 fragments. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFileInternalChunkMover`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp4FormatDescriptor` | `Mp4FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `Mp4LayoutMap` - -Walks the top-level atoms of an MP4/MOV file and exposes each as a `DefragBlockInfo` for block-chart visualization. - -Implements `IFileInternalLayoutMap`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp4LayoutMap` | `Mp4LayoutMap()` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | - -### Namespace `FileFormat.MpegTs` - -[`MpegTsFormatDescriptor`](#mpegtsformatdescriptor) · [`MpegTsReader`](#mpegtsreader) · [`MpegTsReader.ElementaryStream`](#mpegtsreaderelementarystream) · [`MpegTsReader.Program`](#mpegtsreaderprogram) · [`MpegTsReader.TransportStream`](#mpegtsreadertransportstream) - -#### `MpegTsFormatDescriptor` - -Pseudo-archive descriptor for MPEG-2 Transport Streams. Each detected elementary stream is exposed as `stream__.bin` containing the concatenated PES payload bytes for that PID. References: `https://www.itu.int/rec/T-REC-H.222.0` — ITU-T H.222.0 / ISO/IEC 13818-1 — MPEG-2 Systems (transport stream) standard`https://en.wikipedia.org/wiki/MPEG_transport_stream` — Wikipedia - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpegTsFormatDescriptor` | `MpegTsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `MpegTsReader` - -Reader for MPEG-2 Transport Stream files (`.ts`, `.m2ts`, `.mts`) per ISO/IEC 13818-1. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpegTsReader` | `MpegTsReader()` | | -| `M2tsPacketSize` | `const int M2tsPacketSize` | | -| `NullPid` | `const int NullPid` | | -| `PacketSize` | `const int PacketSize` | | -| `PatPid` | `const int PatPid` | | -| `SyncByte` | `const byte SyncByte` | | -| `Read` | `static TransportStream Read(ReadOnlySpan data)` | Parses a complete TS file. Auto-detects 188 vs 192 byte packet stride from the position of the second sync byte. | -| `StreamTypeName` | `static string StreamTypeName(byte type)` | Maps the 8-bit stream_type value from a PMT entry to a short identifier used in emitted entry filenames (e.g. `"h264"`). | - -#### `MpegTsReader.ElementaryStream` - -One detected elementary stream within the TS file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ElementaryStream` | `ElementaryStream(int Pid, byte StreamType, int ProgramNumber, byte[] Payload)` | One detected elementary stream within the TS file. | -| `Payload` | `byte[] Payload { get; init; }` | | -| `Pid` | `int Pid { get; init; }` | | -| `ProgramNumber` | `int ProgramNumber { get; init; }` | | -| `StreamType` | `byte StreamType { get; init; }` | | - -#### `MpegTsReader.Program` - -One program from the Program Association Table. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Program` | `Program(int ProgramNumber, int PmtPid)` | One program from the Program Association Table. | -| `PmtPid` | `int PmtPid { get; init; }` | | -| `ProgramNumber` | `int ProgramNumber { get; init; }` | | - -#### `MpegTsReader.TransportStream` - -Result of parsing a TS file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TransportStream` | `TransportStream(int PacketCount, int PacketSizeUsed, IReadOnlyList Programs, IReadOnlyList Streams)` | Result of parsing a TS file. | -| `PacketCount` | `int PacketCount { get; init; }` | | -| `PacketSizeUsed` | `int PacketSizeUsed { get; init; }` | | -| `Programs` | `IReadOnlyList Programs { get; init; }` | | -| `Streams` | `IReadOnlyList Streams { get; init; }` | | - -### Namespace `FileFormat.Mpq` - -[`MpqEntry`](#mpqentry) · [`MpqFormatDescriptor`](#mpqformatdescriptor) · [`MpqReader`](#mpqreader) · [`MpqWriter`](#mpqwriter) - -#### `MpqEntry` - -Entry in an MPQ archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpqEntry` | `MpqEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `Exists` | `bool Exists { get; }` | File exists in archive. | -| `FileName` | `string FileName { get; init; }` | | -| `FileOffset` | `long FileOffset { get; init; }` | | -| `Flags` | `uint Flags { get; init; }` | | -| `IsCompressed` | `bool IsCompressed { get; }` | File is compressed. | -| `IsEncrypted` | `bool IsEncrypted { get; }` | File is encrypted. | -| `IsSingleUnit` | `bool IsSingleUnit { get; }` | File is a single unit (not sector-based). | -| `OriginalSize` | `long OriginalSize { get; init; }` | | - -#### `MpqFormatDescriptor` - -Blizzard MPQ (Mo'PaQ) game archive used by Diablo, StarCraft, WarCraft III and World of Warcraft. References: `http://www.zezula.net/en/mpq/main.html` — Ladislav Zezula's MPQ format documentation — the de-facto specification`https://github.com/ladislav-zezula/StormLib` — StormLib — maintained reference implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpqFormatDescriptor` | `MpqFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing MPQ archive via the verified extract -> edit -> re-create rebuild. The auto-generated `(listfile)` is dropped from the extracted tree before re-creation (the writer regenerates it and refuses it as an explicit input), so entry names still round-trip without duplicating the listing. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the MPQ archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the MPQ archive per the requested mode. The auto-generated `(listfile)` is excluded from the extracted set — the writer regenerates it and refuses it as an explicit input. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single MPQ entry as a bounded read-only stream. The reader decodes per-entry compression/encryption; the decoded bytes are wrapped in a `BoundedEntryStream` sized to the entry's original (uncompressed) length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries via the verified extract -> edit -> re-create rebuild, dropping the auto-generated `(listfile)` the same way `Add` does. | - -#### `MpqReader` - -Reads Blizzard MPQ (Mike O'Brien Pack) archives. Supports v1 format. Read-only — MPQ creation is extremely complex. Used by Diablo, StarCraft, Warcraft III, World of Warcraft. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpqReader` | `MpqReader(Stream stream)` | | -| `HeaderMagic` | `const uint HeaderMagic` | MPQ header magic. | -| `UserDataMagic` | `const uint UserDataMagic` | User data magic. | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `HeaderOffset` | `long HeaderOffset { get; }` | Gets the byte offset of the MPQ header within the stream. | -| `Extract` | `byte[] Extract(MpqEntry entry)` | Extracts a file by entry. | - -#### `MpqWriter` - -Writes Blizzard MPQ v1 archives. WORM creation only; existing archives are not modified in place. Files are stored uncompressed (no method negotiation, no sector splitting). A "(listfile)" stream is auto-generated so file names roundtrip through `MpqReader`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MpqWriter` | `MpqWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Msi` - -[`CfbLayoutMap`](#cfblayoutmap) · [`CfbWriter`](#cfbwriter) · [`MsiEntry`](#msientry) · [`MsiFormatDescriptor`](#msiformatdescriptor) · [`MsiReader`](#msireader) - -#### `CfbLayoutMap` - -Walks the OLE Compound File Binary (CFB) structure and emits the byte-level layout: header, FAT sectors, DIFAT sectors, directory sectors, mini-FAT sectors, mini-stream container sectors, and each stream's sector chain as `DefragBlockInfo` tiles. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `CfbWriter` - -Writes a flat OLE Compound File Binary (MS-CFB) container holding a list of named streams under a single root storage. Used to give "WORM" creation to formats that wrap CFB (DOC/XLS/PPT/MSG/Thumbs.db) -- the produced files roundtrip through `CfbReader` and `MsiReader`. Simplifications taken to keep this small (~200 LoC vs the ~2000-LoC full MS-CFB writer): Always v3 (512-byte sectors). Up to ~6.8 MB total file size (109 FAT sectors, no DIFAT chain).Mini-stream cutoff is set to 0 -- every stream uses regular sectors regardless of size, so no mini FAT or mini stream bookkeeping is needed.Single root storage, no nested sub-storages. All streams are direct children.Directory tree is a degenerate right-leaning chain. Permissive readers (ours, libgsf, Apache POI) accept it; strict readers (Word/Excel) won't open the file as a document but its CFB envelope is structurally valid. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CfbWriter` | `CfbWriter()` | | -| `AddStream` | `void AddStream(string name, byte[] data)` | Adds a stream entry to the root storage. | -| `WriteTo` | `void WriteTo(Stream output)` | Serialises the CFB container to `output`. | - -#### `MsiEntry` - -Represents an entry (stream or storage) in an MSI/OLE Compound File. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsiEntry` | `MsiEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `MsiFormatDescriptor` - -Microsoft OLE2 Compound File Binary container (MSI installer databases, legacy Office documents). References: `https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/` — [MS-CFB] Compound File Binary File Format — Microsoft Open Specifications`https://learn.microsoft.com/en-us/windows/win32/msi/windows-installer-portal` — Windows Installer documentation portal`https://en.wikipedia.org/wiki/Compound_File_Binary_Format` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsiFormatDescriptor` | `MsiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single MSI / OLE2 stream as a bounded read-only `Stream`. The CFB reader's per-entry extract returns the stream's raw bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's size. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `MsiReader` - -Reads MSI (Windows Installer) and OLE Compound File Binary Format files. Exposes all streams and storages as entries. Streams can be extracted directly. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsiReader` | `MsiReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(MsiEntry entry)` | | - -### Namespace `FileFormat.Msix` - -[`MsixFormatDescriptor`](#msixformatdescriptor) - -#### `MsixFormatDescriptor` - -Descriptor for MSIX and MSIXBUNDLE packages. On disk these are ZIP archives whose root contains an `AppxManifest.xml` (MSIX) or `AppxBundleManifest.xml` (MSIX bundle). The on-disk structure is identical to APPX; only the manifest semantics and file extensions differ. The descriptor surfaces a synthetic `metadata.ini` summarising identity and capability declarations parsed from the manifest, followed by every ZIP entry verbatim. References: `https://learn.microsoft.com/en-us/windows/msix/` — Microsoft MSIX documentation portal`https://github.com/microsoft/msix-packaging` — Microsoft MSIX SDK — canonical packaging implementation`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE ZIP APPNOTE — the underlying container format - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MsixFormatDescriptor` | `MsixFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Capabilities supported by this descriptor. R/W: a mutable ZIP-based package — Add/Replace/Remove are genuine in-place ZIP edits (`ZipModifier`), matching the sibling APPX/APK descriptors. See FormatCapabilities.cs (WORM vs R/W). | -| `Category` | `FormatCategory Category { get; }` | This format describes an archive container. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | Compound extensions are not used by this format. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Preferred extension when producing a new package. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Human-readable name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Extensions recognised as MSIX packages. | -| `Family` | `AlgorithmFamily Family { get; }` | Algorithmic family. | -| `Id` | `string Id { get; }` | Unique format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | No magic bytes are advertised: MSIX is a ZIP archive and detection relies on extension plus the presence of `AppxManifest.xml` or `AppxBundleManifest.xml`. Declaring the ZIP magic here would cause first-match conflicts with the bare ZIP descriptor. | -| `Methods` | `IReadOnlyList Methods { get; }` | Compression methods exposed for creation. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a TAR-compound format. | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing MSIX package. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written; pre-existing entries stay byte-identical. The synthetic `metadata.ini` listing entry is a derived view and is skipped. Note that editing a signed package invalidates its `AppxSignature.p7x`; re-signing is out of scope. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates a new MSIX package as a plain ZIP archive. The caller is responsible for supplying a valid `AppxManifest.xml` among the inputs. | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (MSIX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (MSIX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | Extracts ZIP entries to `outputDir` and also emits `metadata.ini` when no explicit file filter is provided or when the filter explicitly names it. | -| `List` | `List List(Stream stream, string password)` | Lists the synthetic `metadata.ini` entry followed by every ZIP entry in the package. | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The synthetic `metadata.ini` entry is materialised on the fly from the `AppxManifest.xml` identity; all other entries delegate to the inner `ZipReader` and are wrapped in a `BoundedEntryStream` sized to the entry's uncompressed length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries via `ZipModifier`. The synthetic `metadata.ini` listing entry is a derived view and is skipped. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the package: gaps between entries not covered by a live extent in the ZIP layout map. Local headers, entry data, the central directory and EOCD are live and preserved. Cluster-tip wiping is N/A (ZIP packs entries back to back with no per-file slack). | - -### Namespace `FileFormat.Narc` - -[`NarcConstants`](#narcconstants) · [`NarcEntry`](#narcentry) · [`NarcFormatDescriptor`](#narcformatdescriptor) · [`NarcReader`](#narcreader) · [`NarcWriter`](#narcwriter) - -#### `NarcConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `BomLittleEndian` | `const ushort BomLittleEndian` | | -| `BtafEntrySize` | `const int BtafEntrySize` | | -| `DefaultVersion` | `const ushort DefaultVersion` | | -| `MagicBtaf` | `static readonly byte[] MagicBtaf` | | -| `MagicBtnf` | `static readonly byte[] MagicBtnf` | | -| `MagicGmif` | `static readonly byte[] MagicGmif` | | -| `MagicNarc` | `static readonly byte[] MagicNarc` | | -| `MaxNameLength` | `const int MaxNameLength` | | -| `NitroHeaderSize` | `const int NitroHeaderSize` | | -| `SectionCount` | `const ushort SectionCount` | | -| `SectionHeaderSize` | `const int SectionHeaderSize` | | - -#### `NarcEntry` - -Represents a single file inside a NARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NarcEntry` | `NarcEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the entry name (from BTNF, or a synthesized `file_NNNN.bin` if BTNF is non-flat). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute offset into the source stream where this entry's data begins. | -| `Size` | `long Size { get; init; }` | Gets the length in bytes of this entry's data. | - -#### `NarcFormatDescriptor` - -Nintendo DS NARC (Nitro Archive) — BTAF/BTNF/GMIF chunks reusing the NitroROM FNT/FAT layout. References: `https://problemkaputt.de/gbatek.htm` — GBATEK (Martin Korth) — canonical DS technical reference including the NitroROM FNT/FAT structures`https://github.com/pleonex/tinke` — Tinke — community DS resource tool reading NARC - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NarcFormatDescriptor` | `NarcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `NarcReader` - -Reads files from a Nintendo NARC (Archive Resource Compound) container. Supports the flat BTNF variant directly; for nested directory trees the names are synthesized so payload extraction still works. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NarcReader` | `NarcReader(Stream stream, bool leaveOpen = false)` | Opens a NARC archive from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in this archive in the order BTAF lists them (== file ID order). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(NarcEntry entry)` | Reads the raw bytes for a given entry from the stream. | - -#### `NarcWriter` - -Writes a Nintendo NARC archive using the flat-tree BTNF variant (one root directory containing all files at the top level). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NarcWriter` | `NarcWriter(Stream stream, bool leaveOpen = false)` | Creates a new NARC writer. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds a file to the archive. Names must be 1..127 ASCII bytes (BTNF length byte is 7-bit). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Flushes all sections to the stream. Idempotent. | - -### Namespace `FileFormat.Nds` - -[`NdsEntry`](#ndsentry) · [`NdsFormatDescriptor`](#ndsformatdescriptor) · [`NdsReader`](#ndsreader) · [`NdsWriter`](#ndswriter) - -#### `NdsEntry` - -Represents a single file or directory entry within a Nintendo DS ROM NitroFS file system. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NdsEntry` | `NdsEntry()` | | -| `FileId` | `int FileId { get; init; }` | Gets the file ID within the FAT (only meaningful for file entries). | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path within the NitroFS (e.g., "data/sprites/enemy.bin"). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the entry name (file or directory name without path). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute offset of the file data within the ROM image. | -| `Size` | `long Size { get; init; }` | Gets the size of the file data in bytes. | - -#### `NdsFormatDescriptor` - -Nintendo DS ROM image — cartridge header, FNT/FAT filesystem and ARM9/ARM7 binaries. References: `https://problemkaputt.de/gbatek.htm` — GBATEK (Martin Korth) — canonical DS cartridge-header and filesystem reference`https://github.com/devkitPro/ndstool` — ndstool (devkitPro) — maintained ROM build/extract tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NdsFormatDescriptor` | `NdsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `NdsReader` - -Reads the header and NitroFS file system from a Nintendo DS ROM image (.nds). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NdsReader` | `NdsReader(Stream stream, bool leaveOpen = false)` | Initializes a new `NdsReader` from a stream containing an NDS ROM image. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries discovered in the NitroFS. | -| `GameCode` | `string GameCode { get; }` | Gets the 4-character game code. | -| `GameTitle` | `string GameTitle { get; }` | Gets the game title (up to 12 bytes, null-padded ASCII). | -| `MakerCode` | `string MakerCode { get; }` | Gets the 2-character maker code. | -| `RomSize` | `uint RomSize { get; }` | Gets the total ROM size in bytes as declared in the header. | -| `UnitCode` | `byte UnitCode { get; }` | Gets the unit code byte. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(NdsEntry entry)` | Extracts the raw data for a file entry. | - -#### `NdsWriter` - -Writes a minimal Nintendo DS ROM image with NitroFS containing the input files. No ARM9/ARM7 code is emitted — the ROM is structurally valid for file extraction but won't boot on hardware/emulators. Roundtrips through `NdsReader`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NdsWriter` | `NdsWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Nifti` - -[`NiftiFormatDescriptor`](#niftiformatdescriptor) · [`NiftiReader`](#niftireader) · [`NiftiReader.NiftiImage`](#niftireaderniftiimage) · [`NiftiReader.NiftiVersion`](#niftireaderniftiversion) - -#### `NiftiFormatDescriptor` - -Pseudo-archive descriptor for NIfTI-1 and NIfTI-2 medical imaging files (single-file `.nii` variant, optionally gzip-framed as `.nii.gz`). Emits a `metadata.ini` with dimensionality + datatype + pixel spacing, the raw header bytes, and the voxel payload following `vox_offset`. References: `https://nifti.nimh.nih.gov/` — official NIfTI DFWG site — nifti1.h / nifti2.h header definitions`https://en.wikipedia.org/wiki/Neuroimaging_Informatics_Technology_Initiative` — Wikipedia - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NiftiFormatDescriptor` | `NiftiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `NiftiReader` - -Reader for NIfTI-1 and NIfTI-2 medical imaging files (single-file `.nii` variant). Parses the 352-byte (NIfTI-1) or 540-byte (NIfTI-2) header and separates the voxel payload following `vox_offset`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NiftiReader` | `NiftiReader()` | | -| `DatatypeName` | `static string DatatypeName(int code)` | Short human-readable name for the NIfTI datatype code. See `nifti1.h` DT_* constants. | -| `Read` | `static NiftiImage Read(ReadOnlySpan data)` | Parses an in-memory `.nii` (single-file variant). | - -#### `NiftiReader.NiftiImage` - -Parsed NIfTI file — header, raw header bytes, voxels, and key metadata. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NiftiImage` | `NiftiImage(NiftiVersion Version, bool LittleEndian, string Magic, int SizeOfHeader, int Datatype, int Bitpix, long[] Dim, double[] Pixdim, long VoxOffset, double SclSlope, double SclInter, string Description, string IntentName, byte[] HeaderBytes, byte[] VoxelBytes)` | Parsed NIfTI file — header, raw header bytes, voxels, and key metadata. | -| `Bitpix` | `int Bitpix { get; init; }` | | -| `Datatype` | `int Datatype { get; init; }` | | -| `Description` | `string Description { get; init; }` | | -| `Dim` | `long[] Dim { get; init; }` | | -| `HeaderBytes` | `byte[] HeaderBytes { get; init; }` | | -| `IntentName` | `string IntentName { get; init; }` | | -| `LittleEndian` | `bool LittleEndian { get; init; }` | | -| `Magic` | `string Magic { get; init; }` | | -| `Pixdim` | `double[] Pixdim { get; init; }` | | -| `SclInter` | `double SclInter { get; init; }` | | -| `SclSlope` | `double SclSlope { get; init; }` | | -| `SizeOfHeader` | `int SizeOfHeader { get; init; }` | | -| `Version` | `NiftiVersion Version { get; init; }` | | -| `VoxOffset` | `long VoxOffset { get; init; }` | | -| `VoxelBytes` | `byte[] VoxelBytes { get; init; }` | | - -#### `NiftiReader.NiftiVersion` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Nifti1` | `1` | | -| `Nifti2` | `2` | | - -### Namespace `FileFormat.Nsa` - -[`NsaCompressionType`](#nsacompressiontype) · [`NsaEntry`](#nsaentry) · [`NsaFormatDescriptor`](#nsaformatdescriptor) · [`NsaReader`](#nsareader) · [`NsaWriter`](#nsawriter) - -#### `NsaCompressionType` - -Compression type codes used in NSA archive entries. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No compression — data is stored as-is. | -| `Spb` | `1` | SPB — special image compression (not decompressable as generic binary). | -| `Lzss` | `2` | LZSS — LZ77-based compression with 4 KB window and flag-byte framing. | -| `Nbz` | `3` | NBZ — bzip2 compressed data without the leading "BZ" magic header. | - -#### `NsaEntry` - -Represents a single file entry in an NSA archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsaEntry` | `NsaEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | Gets the compressed size of the data in bytes. | -| `CompressionType` | `NsaCompressionType CompressionType { get; init; }` | Gets the compression type for this entry. | -| `Name` | `string Name { get; init; }` | Gets the filename stored in the archive (null-terminated Shift-JIS/ASCII). | -| `Offset` | `uint Offset { get; init; }` | Gets the absolute offset of the compressed data from the start of the archive file. | -| `OriginalSize` | `uint OriginalSize { get; init; }` | Gets the original (uncompressed) size of the data in bytes. | - -#### `NsaFormatDescriptor` - -NScripter NSA game-data archive (entry table + data-offset header). References: ONScripter (Ogapee) — the open NScripter engine whose NsaReader is the de-facto format referenceNo official specification — NScripter is proprietary; the container is documented by the visual-novel tooling community - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsaFormatDescriptor` | `NsaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `NsaReader` - -Reads entries from an NScripter NSA archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsaReader` | `NsaReader(Stream stream, bool leaveOpen = false)` | Initializes a new `NsaReader` from a stream containing an NSA archive. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in this archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(NsaEntry entry)` | Extracts the raw or decompressed data for the given entry. | - -#### `NsaWriter` - -Writes NScripter NSA archives. Always uses compression type `None` -- this is WORM creation, the existing LZSS/NBZ decoders aren't paired with corresponding encoders. NScripter engines accept stored entries in NSA archives. Layout matches `NsaReader`: Header: uint16 BE file count, uint32 BE data offset.Per entry: null-terminated ASCII filename, uint8 compression type, uint32 BE offset (relative to data start), uint32 BE compressed size, uint32 BE original size.Data area: file data concatenated, in the same order as the index. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsaWriter` | `NsaWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Nsis` - -[`NsisCompression`](#nsiscompression) · [`NsisEntry`](#nsisentry) · [`NsisFormatDescriptor`](#nsisformatdescriptor) · [`NsisReader`](#nsisreader) · [`NsisWriter`](#nsiswriter) - -#### `NsisCompression` - -Identifies the compression algorithm used in an NSIS installer. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No compression — data is stored verbatim. | -| `Zlib` | `1` | Zlib/Deflate compression (2-byte zlib header + raw Deflate stream). | -| `BZip2` | `2` | BZip2 block-sorted compression. | -| `Lzma` | `3` | LZMA compression (5-byte properties header + raw LZMA stream). | - -#### `NsisEntry` - -Represents a data block embedded in an NSIS installer. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsisEntry` | `NsisEntry(string FileName, long Size, long CompressedSize, bool IsDirectory)` | Represents a data block embedded in an NSIS installer. | -| `CompressedSize` | `long CompressedSize { get; init; }` | The compressed size in bytes, or -1 when unknown (solid stream). | -| `FileName` | `string FileName { get; init; }` | The entry name. Will be a generated name such as "block_0" unless the installer header was successfully parsed to recover actual file names. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether the entry represents a directory. | -| `Size` | `long Size { get; init; }` | The uncompressed size in bytes, or -1 when unknown (solid stream). | - -#### `NsisFormatDescriptor` - -NSIS (Nullsoft Scriptable Install System) installer archive — PE stub plus compressed installer data. References: `https://nsis.sourceforge.io` — official NSIS project site and sources — the installer data layout is defined there`https://en.wikipedia.org/wiki/Nullsoft_Scriptable_Install_System` — Wikipedia`https://www.7-zip.org` — 7-Zip — widely used independent parser of NSIS installer payloads - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsisFormatDescriptor` | `NsisFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the NSIS data block in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the NSIS data block per the requested mode. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | - -#### `NsisReader` - -Reads data blocks from an NSIS (Nullsoft Scriptable Install System) installer executable. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsisReader` | `NsisReader(Stream stream, bool leaveOpen = false)` | Opens an NSIS installer from a stream. The stream must be seekable. | -| `Compression` | `NsisCompression Compression { get; }` | Gets the compression method used by this installer. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the data blocks found in the installer. | -| `IsSolid` | `bool IsSolid { get; }` | Gets whether the installer uses solid (single-stream) compression. | -| `Dispose` | `void Dispose()` | | -| `ExtractSolidStream` | `byte[] ExtractSolidStream()` | Decompresses the entire solid data stream and returns it as a single byte array. Only meaningful when `IsSolid` is `true`. | -| `Extract` | `byte[] Extract(NsisEntry entry)` | Extracts the raw (decompressed) data for the given entry. | - -#### `NsisWriter` - -Writes a minimal NSIS-formatted file. No PE stub is emitted — the reader's `ScanForSignature` fallback finds the NSIS overlay via linear scan when PE parsing fails. Files are stored uncompressed as individual data blocks (non-solid). Roundtrips through `NsisReader`. Note: the produced file has no executable code and cannot be "run" to install — the NSIS format is primarily an installer stub + overlay data, and emitting a functional installer would require shipping a signed PE stub which is out of scope for a compression toolkit. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NsisWriter` | `NsisWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.NuPkg` - -[`NuPkgFormatDescriptor`](#nupkgformatdescriptor) - -#### `NuPkgFormatDescriptor` - -NuGet package (.nupkg) — a ZIP/OPC container with a .nuspec manifest. References: `https://learn.microsoft.com/en-us/nuget/` — Microsoft NuGet documentation portal (package structure, .nuspec)`https://github.com/NuGet/NuGet.Client` — canonical client implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NuPkgFormatDescriptor` | `NuPkgFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing NuPkg archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (NuPkg is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (NuPkg is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Numpy` - -[`NpyFormatDescriptor`](#npyformatdescriptor) · [`NpyReader`](#npyreader) · [`NpyReader.NpyArray`](#npyreadernpyarray) · [`NpyWriter`](#npywriter) · [`NpzFormatDescriptor`](#npzformatdescriptor) - -#### `NpyFormatDescriptor` - -Pseudo-archive descriptor for NumPy's NPY array serialization format. Splits an `.npy` file into `metadata.ini` (dtype, shape, header-length, version, fortran order) and `array.bin` (the raw payload bytes after the header). References: `https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html` — the NPY format specification (numpy.lib.format)`https://github.com/numpy/numpy` — canonical implementation - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NpyFormatDescriptor` | `NpyFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM create — concatenates every input's bytes into a single uint8 NPY array. When exactly one input is supplied and it is itself a valid NPY file, it is written through verbatim so callers can round-trip an existing array. The dtype/shape can be overridden via `FormatCreateOptions` keys `npy_dtype`, `npy_shape` and `npy_fortran_order`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `NpyReader` - -Reader for the NumPy NPY on-disk format (v1, v2, v3). Splits an `.npy` into its magic prefix, version, Python-dict header string, and raw array payload. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NpyReader` | `NpyReader()` | | -| `Magic` | `static ReadOnlySpan Magic { get; }` | The 6-byte magic that begins every NPY file. | -| `Read` | `static NpyArray Read(ReadOnlySpan data)` | Parses an NPY file from an in-memory span. | - -#### `NpyReader.NpyArray` - -Parsed NPY file — the four on-disk regions plus scanned metadata. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NpyArray` | `NpyArray(byte MajorVersion, byte MinorVersion, int HeaderLength, string HeaderText, string Dtype, string Shape, bool FortranOrder, byte[] HeaderBytes, byte[] ArrayBytes)` | Parsed NPY file — the four on-disk regions plus scanned metadata. | -| `ArrayBytes` | `byte[] ArrayBytes { get; init; }` | | -| `Dtype` | `string Dtype { get; init; }` | | -| `FortranOrder` | `bool FortranOrder { get; init; }` | | -| `HeaderBytes` | `byte[] HeaderBytes { get; init; }` | | -| `HeaderLength` | `int HeaderLength { get; init; }` | | -| `HeaderText` | `string HeaderText { get; init; }` | | -| `MajorVersion` | `byte MajorVersion { get; init; }` | | -| `MinorVersion` | `byte MinorVersion { get; init; }` | | -| `Shape` | `string Shape { get; init; }` | | - -#### `NpyWriter` - -WORM writer for the NumPy NPY array serialization format (NEP 1). Emits a v1 file: 6-byte magic + 2-byte version (1.0) + u16 little-endian header length + ASCII Python-dict header (padded with spaces + trailing newline so the preamble + header is a multiple of 64 bytes) + raw array payload. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultDtype` | `const string DefaultDtype` | Default dtype string used when no explicit type is supplied. | -| `Write` | `static void Write(Stream output, ReadOnlySpan payload, string dtype = "\|u1", string shape = null, bool fortranOrder = false)` | Writes an NPY file from `payload` with the supplied dtype/shape header. When `shape` is null, a 1-D shape matching the payload's element count is inferred from the dtype's item-size. | -| `Write` | `static void Write(Stream output, byte[] payload, string dtype = "\|u1", string shape = null, bool fortranOrder = false)` | Convenience: writes an NPY file from a byte array. See span overload for parameter docs. | - -#### `NpzFormatDescriptor` - -Descriptor for NumPy's NPZ format — a ZIP archive whose entries are all `.npy` array serializations. Detection is extension-based (NPZ has no dedicated magic; its raw magic is the plain ZIP signature) and the contents are surfaced as-is: one entry per enclosed `.npy`, plus a `metadata.ini` summary of array names and byte sizes. References: `https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html` — numpy.lib.format — defines NPZ as a ZIP of .npy members`https://github.com/numpy/numpy` — canonical implementation (numpy.savez / numpy.load)`https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE ZIP APPNOTE — the underlying container format - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NpzFormatDescriptor` | `NpzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM create — emits an NPZ (ZIP archive) where every non-directory input becomes one entry. Inputs whose name ends in `.npy` and whose bytes already carry the NPY magic are stored as-is; other inputs are wrapped in a minimal uint8 NPY frame on the fly and their archive name gets a `.npy` suffix appended when not already present. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Obj` - -[`ObjFormatDescriptor`](#objformatdescriptor) - -#### `ObjFormatDescriptor` - -Wavefront OBJ (`.obj`) — text 3D format where `o ` starts a new object and `g ` starts a new group. Archive view: `FULL.obj` plus one sub-OBJ per object (or group when no `o` lines exist). Each sub-OBJ retains any pre-object preamble (vertex/uv/normal tables + mtllib references) so the emitted slices are geometrically valid on their own. This mirrors how slicing a multi-frame GIF rebuilds a standalone single-frame GIF. References: `https://paulbourke.net/dataformats/obj/` — Paul Bourke's mirror of the Wavefront OBJ specificationWavefront Advanced Visualizer manual, Appendix B1 — the original OBJ definition`https://en.wikipedia.org/wiki/Wavefront_.obj_file` — Wikipedia - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ObjFormatDescriptor` | `ObjFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Odp` - -[`OdpFormatDescriptor`](#odpformatdescriptor) - -#### `OdpFormatDescriptor` - -OpenDocument presentation (.odp) — an OASIS ODF ZIP package. References: OASIS OpenDocument Format v1.3 (also ISO/IEC 26300) — the ODF package and XML specification`https://en.wikipedia.org/wiki/OpenDocument` — Wikipedia`https://www.libreoffice.org` — LibreOffice — principal implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OdpFormatDescriptor` | `OdpFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ODP archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (ODP is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (ODP is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Ods` - -[`OdsFormatDescriptor`](#odsformatdescriptor) - -#### `OdsFormatDescriptor` - -OpenDocument spreadsheet (.ods) — an OASIS ODF ZIP package. References: OASIS OpenDocument Format v1.3 (also ISO/IEC 26300) — the ODF package and XML specification`https://en.wikipedia.org/wiki/OpenDocument` — Wikipedia`https://www.libreoffice.org` — LibreOffice — principal implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OdsFormatDescriptor` | `OdsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ODS archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (ODS is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (ODS is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Odt` - -[`OdtFormatDescriptor`](#odtformatdescriptor) - -#### `OdtFormatDescriptor` - -OpenDocument text document (.odt) — an OASIS ODF ZIP package. References: OASIS OpenDocument Format v1.3 (also ISO/IEC 26300) — the ODF package and XML specification`https://en.wikipedia.org/wiki/OpenDocument` — Wikipedia`https://www.libreoffice.org` — LibreOffice — principal implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OdtFormatDescriptor` | `OdtFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ODT archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (ODT is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (ODT is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Onnx` - -[`OnnxFormatDescriptor`](#onnxformatdescriptor) · [`OnnxReader`](#onnxreader) · [`OnnxReader.Model`](#onnxreadermodel) · [`OnnxReader.Operator`](#onnxreaderoperator) · [`OnnxReader.OpsetImport`](#onnxreaderopsetimport) · [`OnnxReader.Tensor`](#onnxreadertensor) · [`OnnxReader.ValueInfo`](#onnxreadervalueinfo) · [`ProtobufReader`](#protobufreader) - -#### `OnnxFormatDescriptor` - -Read-only descriptor for ONNX neural-network model files. Parses the protobuf-serialized `ModelProto` via the in-tree minimal reader and surfaces: `metadata.ini` (IR version, producer, opsets, input/output shapes, op counts), `ops.txt` (one line per graph operation), and one `initializers/{name}.bin` per weight tensor. References: `https://github.com/onnx/onnx/blob/main/onnx/onnx.proto` — the ModelProto schema, the defining document for the on-disk bytes`https://github.com/onnx/onnx` — canonical implementation and IR specification`https://onnx.ai` — project home (Open Neural Network Exchange) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OnnxFormatDescriptor` | `OnnxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `OnnxReader` - -Minimal read-only parser for ONNX `ModelProto` files. Extracts the fields needed for metadata surfacing + tensor extraction without pulling in a full protobuf library: IR version, producer info, opset imports, graph-level inputs/outputs, operator list, and each `initializer` tensor's raw bytes (either the inline `raw_data` field or a reconstructed little-endian serialization of one of the typed arrays). - -| Member | Signature | Summary | -| --- | --- | --- | -| `OnnxReader` | `OnnxReader()` | | -| `DataTypeName` | `static string DataTypeName(int code)` | ONNX data-type names as defined in `TensorProto.DataType`. | -| `Read` | `static Model Read(ReadOnlySpan data)` | Parses an in-memory ONNX `ModelProto`. | - -#### `OnnxReader.Model` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Model` | `Model(long IrVersion, string ProducerName, string ProducerVersion, string Domain, long ModelVersion, string DocString, string GraphName, IReadOnlyList OpsetImports, IReadOnlyList Operators, IReadOnlyList Initializers, IReadOnlyList Inputs, IReadOnlyList Outputs)` | | -| `DocString` | `string DocString { get; init; }` | | -| `Domain` | `string Domain { get; init; }` | | -| `GraphName` | `string GraphName { get; init; }` | | -| `Initializers` | `IReadOnlyList Initializers { get; init; }` | | -| `Inputs` | `IReadOnlyList Inputs { get; init; }` | | -| `IrVersion` | `long IrVersion { get; init; }` | | -| `ModelVersion` | `long ModelVersion { get; init; }` | | -| `Operators` | `IReadOnlyList Operators { get; init; }` | | -| `OpsetImports` | `IReadOnlyList OpsetImports { get; init; }` | | -| `Outputs` | `IReadOnlyList Outputs { get; init; }` | | -| `ProducerName` | `string ProducerName { get; init; }` | | -| `ProducerVersion` | `string ProducerVersion { get; init; }` | | - -#### `OnnxReader.Operator` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Operator` | `Operator(string OpType, string Domain, string Name, IReadOnlyList Inputs, IReadOnlyList Outputs)` | | -| `Domain` | `string Domain { get; init; }` | | -| `Inputs` | `IReadOnlyList Inputs { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `OpType` | `string OpType { get; init; }` | | -| `Outputs` | `IReadOnlyList Outputs { get; init; }` | | - -#### `OnnxReader.OpsetImport` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpsetImport` | `OpsetImport(string Domain, long Version)` | | -| `Domain` | `string Domain { get; init; }` | | -| `Version` | `long Version { get; init; }` | | - -#### `OnnxReader.Tensor` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Tensor` | `Tensor(string Name, int DataType, long[] Dims, byte[] RawData)` | | -| `DataType` | `int DataType { get; init; }` | | -| `Dims` | `long[] Dims { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `RawData` | `byte[] RawData { get; init; }` | | - -#### `OnnxReader.ValueInfo` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ValueInfo` | `ValueInfo(string Name, int ElementType, long[] Dims)` | | -| `Dims` | `long[] Dims { get; init; }` | | -| `ElementType` | `int ElementType { get; init; }` | | -| `Name` | `string Name { get; init; }` | | - -#### `ProtobufReader` - -Minimal read-only Protocol Buffers (proto3) decoder. Handles the four wire types relevant to ONNX: `Varint`, `Fixed64`, `LengthDelimited`, and `Fixed32`. Group wire types (3 and 4) are deprecated in proto3 and not emitted by the ONNX serializer, but we tolerate them during a scan. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ProtobufReader` | `ProtobufReader(ReadOnlySpan data)` | | -| `WireEndGroup` | `const int WireEndGroup` | | -| `WireFixed32` | `const int WireFixed32` | | -| `WireFixed64` | `const int WireFixed64` | | -| `WireLengthDelimited` | `const int WireLengthDelimited` | | -| `WireStartGroup` | `const int WireStartGroup` | | -| `WireVarint` | `const int WireVarint` | | -| `AtEnd` | `bool AtEnd { get; }` | | -| `Position` | `int Position { get; }` | | -| `Remaining` | `int Remaining { get; }` | | -| `LooksLikeProtobuf` | `static bool LooksLikeProtobuf(ReadOnlySpan data, int maxFieldsToScan = 4)` | Quick plausibility check: true if the buffer parses as at least one valid wire-format (tag, value) pair without overrun. Used for soft format detection. | -| `ReadBytes` | `ReadOnlySpan ReadBytes()` | Reads a length-delimited chunk; returns a span pointing into the underlying buffer. | -| `ReadFixed32` | `uint ReadFixed32()` | | -| `ReadFixed64` | `ulong ReadFixed64()` | | -| `ReadInt32` | `int ReadInt32()` | | -| `ReadInt64` | `long ReadInt64()` | | -| `ReadString` | `string ReadString()` | | -| `ReadTag` | `bool ReadTag(out int fieldNumber, out int wireType)` | Reads a tag (field number + wire type); returns false at EOF. | -| `ReadVarint` | `ulong ReadVarint()` | Reads an unsigned LEB128 varint (up to 10 bytes). | -| `SkipField` | `void SkipField(int wireType)` | Skips one wire-format value (tag already consumed). | - -### Namespace `FileFormat.PackBits` - -[`PackBitsFormatDescriptor`](#packbitsformatdescriptor) · [`PackBitsStream`](#packbitsstream) - -#### `PackBitsFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackBitsFormatDescriptor` | `PackBitsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `PackBitsStream` - -Provides PackBits compression and decompression (Apple MacPaint standard) with a framed container header. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses `input` to `output` using PackBits encoding. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses `input` to `output` using PackBits decoding. | - -### Namespace `FileFormat.PackDisk` - -[`DcsFormatDescriptor`](#dcsformatdescriptor) · [`PackDiskEntry`](#packdiskentry) · [`PackDiskFormatDescriptor`](#packdiskformatdescriptor) · [`PackDiskReader`](#packdiskreader) · [`PackDiskWriter`](#packdiskwriter) · [`XDiskFormatDescriptor`](#xdiskformatdescriptor) · [`XMashFormatDescriptor`](#xmashformatdescriptor) - -#### `DcsFormatDescriptor` - -Amiga DCS disk archive — whole-floppy track data compressed with the XPK library. References: `https://aminet.net` — Aminet — distribution home of the archiver and the XPK compression libraryXPK master library developer documentation (Amiga) — defines the XPKF container the track data is stored inNo published specification — reverse-engineered from the tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DcsFormatDescriptor` | `DcsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PackDiskEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackDiskEntry` | `PackDiskEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `PackDiskFormatDescriptor` - -Amiga PackDisk disk archive — whole-floppy track data compressed with the XPK library. References: `https://aminet.net` — Aminet — distribution home of the archiver and the XPK compression libraryXPK master library developer documentation (Amiga) — defines the XPKF container the track data is stored inNo published specification — reverse-engineered from the tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackDiskFormatDescriptor` | `PackDiskFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PackDiskReader` - -Reads PackDisk/xMash/xDisk/GDC/DCS/MDC Amiga disk archives. These all use XPK-based compression for individual tracks. Common structure: 4-byte magic, track table, XPK-compressed track data. We support listing and extracting stored/raw data. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackDiskReader` | `PackDiskReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Format` | `string Format { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(PackDiskEntry entry)` | | - -#### `PackDiskWriter` - -Writes PackDisk-family Amiga disk archives (PackDisk/xMash/xDisk/GDC/DCS/MDC). All share the same shape: a 4-byte format magic, 4 bytes of flags, then a sequence of tracks. WORM creation always emits *stored* tracks (raw 5632-byte sectors) -- the reader treats these as uncompressed because no "XPKF" chunk header precedes them. No XPK encoder is needed. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackDiskWriter` | `PackDiskWriter(string magic)` | Format magic. Use one of the 4-byte ASCII codes the reader recognises. | -| `TrackSize` | `const int TrackSize` | | -| `AddTrack` | `void AddTrack(ReadOnlySpan data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -#### `XDiskFormatDescriptor` - -Amiga xDisk/GDC disk archive — whole-floppy track data compressed with the XPK library. References: `https://aminet.net` — Aminet — distribution home of the archiver and the XPK compression libraryXPK master library developer documentation (Amiga) — defines the XPKF container the track data is stored inNo published specification — reverse-engineered from the tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XDiskFormatDescriptor` | `XDiskFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `XMashFormatDescriptor` - -Amiga xMash disk archive — whole-floppy track data compressed with the XPK library. References: `https://aminet.net` — Aminet — distribution home of the archiver and the XPK compression libraryXPK master library developer documentation (Amiga) — defines the XPKF container the track data is stored inNo published specification — reverse-engineered from the tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XMashFormatDescriptor` | `XMashFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.PackIt` - -[`PackItEntry`](#packitentry) · [`PackItFormatDescriptor`](#packitformatdescriptor) · [`PackItModifier`](#packitmodifier) · [`PackItReader`](#packitreader) · [`PackItWriter`](#packitwriter) - -#### `PackItEntry` - -Represents a file entry in a PackIt (.pit) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackItEntry` | `PackItEntry()` | | -| `Creator` | `string Creator { get; init; }` | Gets the Mac four-character creator code (e.g. "CWIE"). | -| `DataForkSize` | `long DataForkSize { get; init; }` | Gets the uncompressed data fork size in bytes. | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the absolute byte offset where the data fork begins in the source stream. | -| `FileType` | `string FileType { get; init; }` | Gets the Mac four-character file type code (e.g. "TEXT"). | -| `IsCompressed` | `bool IsCompressed { get; init; }` | Gets whether this entry uses Huffman compression ("PMa4"). | -| `Name` | `string Name { get; init; }` | Gets the filename (up to 63 characters, Mac Roman / Latin-1 encoded). | -| `ResourceForkSize` | `long ResourceForkSize { get; init; }` | Gets the uncompressed resource fork size in bytes. | - -#### `PackItFormatDescriptor` - -PackIt classic Macintosh archive (.pit; Harry Chesley, 1984) — sequential PMag/PMa4 records bundling data and resource forks. References: `https://github.com/MacPaw/XADMaster` — XADMaster (The Unarchiver) — maintained implementation including PackItNo formal specification — format known from PackIt itself and later community documentation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackItFormatDescriptor` | `PackItFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing PackIt archive. Uses `PackItModifier` — Add appends Stored at EOF; Remove walks the entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the PackIt archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the PackIt archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single PackIt entry as a bounded read-only stream. The reader already produces the decoded data-fork bytes for each entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to the data fork's logical length so the resource fork tail and adjacent entries cannot leak. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `PackItModifier`. | - -#### `PackItModifier` - -Random-access in-place modifier for PackIt (.pit) classic Macintosh archives. PackIt has no explicit end-of-archive marker — readers stop when the next 4 bytes are not "PMag" or "PMa4". Add appends a new stored entry at EOF; Remove walks the entry chain, locates the target, and shifts trailing bytes forward to compact (no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream pit, string name, byte[] data, string fileType = "TEXT", string creator = "CWIE")` | Appends a stored ("PMag") entry at the end of the archive. Walks the existing entry chain to find the EOF (first non-magic 4 bytes), then writes the new entry there and truncates. I/O cost is one full sequential entry walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream pit, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact. | - -#### `PackItReader` - -Reads entries from a PackIt (.pit) classic Macintosh archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackItReader` | `PackItReader(Stream stream, bool leaveOpen = false)` | Opens a PackIt archive from the given stream and reads all entries. | -| `EntryHeaderSize` | `const int EntryHeaderSize` | Size of the fixed per-entry header in bytes (magic + filename field + metadata). | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries found in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(PackItEntry entry)` | Extracts the data fork of the specified entry. | - -#### `PackItWriter` - -Creates a PackIt (.pit) classic Macintosh archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackItWriter` | `PackItWriter(Stream stream, bool leaveOpen = false)` | Initialises a new `PackItWriter`. | -| `AddFile` | `void AddFile(string name, byte[] data, string fileType = "TEXT", string creator = "CWIE")` | Appends a stored file entry to the archive. | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.Pak` - -[`PakFormatDescriptor`](#pakformatdescriptor) · [`PakInPlaceModifier`](#pakinplacemodifier) · [`PakReader`](#pakreader) · [`PakWriter`](#pakwriter) - -#### `PakFormatDescriptor` - -id Software Quake PAK resource archive ('PACK' header + 64-byte-entry directory). References: `https://github.com/id-Software/Quake` — released Quake source — the pakfile code is the canonical definitionUnofficial Quake Specs (Olivier Montanuy et al.) — long-standing community format documentation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PakFormatDescriptor` | `PakFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing PAK archive. PAK shares the ARC binary layout so this delegates to `PakInPlaceModifier`, which itself wraps `ArcModifier`. Add overwrites only the trailing end-of-archive marker; Remove walks the entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the PAK archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the PAK archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single PAK entry as a bounded read-only stream. PAK shares the ARC binary layout: a forward-iterating reader produces per-entry bytes (decompressed if the entry was stored compressed). The bytes are wrapped in a `BoundedEntryStream` sized to the entry's original length — adjacent entries and trailing padding are physically unreachable. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries via `PakInPlaceModifier`. | - -#### `PakInPlaceModifier` - -Random-access in-place modifier for Quake PAK archives. PAK shares the ARC binary layout (chain of entry blocks terminated by a 2-byte 0x1A 0x00 end-of-archive marker), so this wrapper delegates straight to `ArcModifier`. Add overwrites the old EOA marker with a new Stored entry plus a fresh EOA — bytes before the old EOA are untouched. Remove walks the entry chain, locates the target, and shifts trailing bytes forward to compact (no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream pak, string name, byte[] data)` | Appends a Stored entry to a PAK archive. Bytes before the old end-of-archive marker are not modified. | -| `RemoveFile` | `static bool RemoveFile(Stream pak, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. | - -#### `PakReader` - -Reads PAK archives. PAK is an ARC-compatible format (same binary layout). Delegates to `ArcReader` for all operations. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PakReader` | `PakReader(Stream stream)` | Reads a PAK archive from a stream. | -| `Dispose` | `void Dispose()` | | -| `GetNextEntry` | `ArcEntry GetNextEntry()` | Gets the next entry, or null if no more entries. | -| `ReadEntryData` | `byte[] ReadEntryData()` | Reads the data of the current entry. | - -#### `PakWriter` - -Creates PAK archives. PAK is ARC-compatible (same binary layout). Delegates to `ArcWriter` for all operations. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PakWriter` | `PakWriter(Stream stream)` | Creates a new PAK archive writer. | -| `AddEntry` | `void AddEntry(string fileName, byte[] data)` | Adds a file entry. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive end marker. | - -### Namespace `FileFormat.Paq8` - -[`Paq8FormatDescriptor`](#paq8formatdescriptor) · [`Paq8Stream`](#paq8stream) - -#### `Paq8FormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Paq8FormatDescriptor` | `Paq8FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `Paq8Stream` - -PAQ8 stream compressor. Writes a simplified single-file paq8l container with an arithmetic-coded payload driven by a per-byte bit-tree context model. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses `input` into the PAQ8 container on `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a PAQ8 container from `input` into `output`. | - -### Namespace `FileFormat.Pbp` - -[`PbpEntry`](#pbpentry) · [`PbpFormatDescriptor`](#pbpformatdescriptor) · [`PbpReader`](#pbpreader) · [`PbpWriter`](#pbpwriter) - -#### `PbpEntry` - -Represents a single section in a PSP PBP archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PbpEntry` | `PbpEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the fixed section name (one of the eight PBP section names). | -| `Offset` | `long Offset { get; init; }` | Gets the offset of this section's payload from the start of the PBP file. | -| `Size` | `long Size { get; init; }` | Gets the size in bytes of this section's payload. | - -#### `PbpFormatDescriptor` - -Sony PSP PBP package (EBOOT.PBP) — 'PBP' magic plus eight offsets to PARAM.SFO, icon/PIC/PMF media and DATA.PSP / DATA.PSAR sections. References: `https://github.com/pspdev/pspsdk` — PSP homebrew SDK — de-facto reference for the PBP headerNo official Sony specification — structure documented by the PSP homebrew community - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PbpFormatDescriptor` | `PbpFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | - -#### `PbpReader` - -Reads sections from a PSP PBP archive (EBOOT.PBP and similar multi-section files). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PbpReader` | `PbpReader(Stream stream, bool leaveOpen = false)` | Initializes a new `PbpReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the non-empty entries discovered in the archive, in section order. | -| `Version` | `uint Version { get; }` | Gets the PBP version field from the header. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(PbpEntry entry)` | Extracts the raw bytes for a given entry. | - -#### `PbpWriter` - -Writes a PSP PBP archive containing up to eight fixed-name sections. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PbpWriter` | `PbpWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `PbpWriter`. | -| `Version` | `uint Version { get; set; }` | Gets or sets the version word written into the PBP header. Defaults to 0x00010000. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds a section payload by its fixed name. Each section may only be added once. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the PBP archive to the stream and finishes writing. | - -### Namespace `FileFormat.PeResources` - -[`PeResourcesFormatDescriptor`](#peresourcesformatdescriptor) - -#### `PeResourcesFormatDescriptor` - -Read-only archive view of any PE file. Every resource inside the target `.dll`/`.exe`/`.ocx`/`.cpl`/`.sys` surfaces as an entry. `RT_GROUP_ICON`/`RT_GROUP_CURSOR` entries are reassembled against their child `RT_ICON`/`RT_CURSOR` members so extracted `.ico` / `.cur` files are standalone on-disk-format files. `RT_BITMAP` payloads are wrapped with a synthesised `BITMAPFILEHEADER` so extracted `.bmp` files open in any image viewer. Other types come out as raw bytes with a type-appropriate extension. References: `https://learn.microsoft.com/en-us/windows/win32/debug/pe-format` — Microsoft PE/COFF specification — .rsrc resource directory layout"An In-Depth Look into the Win32 Portable Executable File Format" — Matt Pietrek, MSDN Magazine, 2002`https://en.wikipedia.org/wiki/Portable_Executable` — Wikipedia - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PeResourcesFormatDescriptor` | `PeResourcesFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Ply` - -[`PlyFormatDescriptor`](#plyformatdescriptor) - -#### `PlyFormatDescriptor` - -Stanford PLY polygon file. Starts with `ply\n` (or `ply\r\n`), declares `format ascii 1.0` / `format binary_little_endian 1.0` / `format binary_big_endian 1.0`, then a series of `element ` blocks each with one or more `property ` lines. Header terminates with `end_header\n`; the body that follows is either ASCII records or the declared binary layout. References: `http://paulbourke.net/dataformats/ply/` — Paul Bourke's classic PLY format description`https://en.wikipedia.org/wiki/PLY_(file_format)` — Wikipedia overviewGreg Turk, "The PLY Polygon File Format" (Stanford Graphics Lab) — original definition - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PlyFormatDescriptor` | `PlyFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Read-only archive capabilities. | -| `Category` | `FormatCategory Category { get; }` | Archive category. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | No compound extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default extension. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Display name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Known extensions. | -| `Family` | `AlgorithmFamily Family { get; }` | Archive family. | -| `Id` | `string Id { get; }` | Format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | Magic: `ply\n` at offset 0 (high confidence, unique). | -| `Methods` | `IReadOnlyList Methods { get; }` | Stored only. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a tar compound format. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.PowerPacker` - -[`PowerPackerFormatDescriptor`](#powerpackerformatdescriptor) · [`PowerPackerStream`](#powerpackerstream) - -#### `PowerPackerFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PowerPackerFormatDescriptor` | `PowerPackerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `PowerPackerStream` - -Compressor and decompressor for the Amiga PowerPacker (PP20) crunched file format. PP20 is a backward-decoding LZ77 variant: both the bit stream and the output buffer are consumed from end to start. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses raw data into the PP20 format and returns the result as a new byte array. | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses raw data into the PP20 format and writes the result to `output`. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses a PP20-crunched byte array and returns the original data. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a PP20-crunched stream and writes the original data to `output`. | - -### Namespace `FileFormat.Ppmd` - -[`PpmdFormatDescriptor`](#ppmdformatdescriptor) · [`PpmdStream`](#ppmdstream) - -#### `PpmdFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PpmdFormatDescriptor` | `PpmdFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `PpmdStream` - -PPMd stream container format. Layout: 4-byte magic (0x8F 0xAF 0xAC 0x84), then the raw output of `PpmBuildingBlock` (which includes its own 1-byte order + 4-byte LE size header). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Pptx` - -[`PptxFormatDescriptor`](#pptxformatdescriptor) - -#### `PptxFormatDescriptor` - -Office Open XML presentation (.pptx) — an OPC ZIP package. References: `https://ecma-international.org/publications-and-standards/standards/ecma-376/` — ECMA-376 Office Open XML File Formats (also ISO/IEC 29500)`https://en.wikipedia.org/wiki/Office_Open_XML` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PptxFormatDescriptor` | `PptxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing PPTX archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (PPTX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (PPTX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Psarc` - -[`PsarcEntry`](#psarcentry) · [`PsarcFormatDescriptor`](#psarcformatdescriptor) · [`PsarcReader`](#psarcreader) · [`PsarcWriter`](#psarcwriter) - -#### `PsarcEntry` - -Represents a single entry inside a PSARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsarcEntry` | `PsarcEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Gets the total compressed size on disk in bytes (sum of all blocks belonging to this entry). | -| `Name` | `string Name { get; init; }` | Gets the relative, forward-slash, lowercase path of this entry (manifest-derived; empty for the manifest itself). | -| `OriginalSize` | `long OriginalSize { get; init; }` | Gets the original (uncompressed) size in bytes. | -| `StartBlockIndex` | `int StartBlockIndex { get; init; }` | Gets the index into the block-sizes table where this entry's first block lives. | -| `StartOffset` | `long StartOffset { get; init; }` | Gets the absolute byte offset into the archive where this entry's first compressed block begins. | - -#### `PsarcFormatDescriptor` - -Sony PlayStation archive (PSARC) used on PS3/PS4/Vita — manifest-named entries behind a compressed table of contents. References: psdevwiki "PlayStation archive (PSARC)" (www.psdevwiki.com) — community on-disk layout notesPSARC.EXE from Sony's PlayStation SDKs — the defining (non-public) tool - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsarcFormatDescriptor` | `PsarcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the PSARC archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the PSARC archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | - -#### `PsarcReader` - -Reads entries from a Sony PlayStation archive (PSARC) v1.3/1.4. Supports zlib block compression. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsarcReader` | `PsarcReader(Stream stream, bool leaveOpen = false)` | Initializes a new `PsarcReader` from a stream. | -| `BlockSize` | `int BlockSize { get; }` | Gets the block size used by the archive. | -| `Compression` | `string Compression { get; }` | Gets the compression algorithm name ("zlib" or "lzma") declared in the header. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive (entry 0 is the path manifest itself, omitted from this list). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(PsarcEntry entry)` | Extracts and decompresses the contents of the given entry. | - -#### `PsarcWriter` - -Creates a Sony PlayStation archive (PSARC) v1.4 with zlib block compression. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsarcWriter` | `PsarcWriter(Stream stream, bool leaveOpen = false, int blockSize = 65536, string compression = "zlib")` | Initializes a new `PsarcWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. The data is buffered in memory until `Finish` (or `Dispose`) is called. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalizes the archive: emits header, TOC, block-sizes table, and compressed data. | - -### Namespace `FileFormat.QuickLz` - -[`QuickLzFormatDescriptor`](#quicklzformatdescriptor) · [`QuickLzStream`](#quicklzstream) - -#### `QuickLzFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `QuickLzFormatDescriptor` | `QuickLzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `QuickLzStream` - -QuickLZ level-1 stream format by Lasse Mikkel Reinhold. Header layout (9-byte long form, always used here): byte 0 flags: 0x47 = compressed, 0x46 = stored (level 1, long header, bit6=1) uint32 LE compressed size (includes the 9-byte header) uint32 LE decompressed size Payload encoding (after header): Control words are 32-bit LE values written before each group of up to 31 tokens. Bit 31 is a sentinel (always 1). The remaining bits describe tokens from LSB upward: 0 = literal → 1 raw byte follows 1 = match → 2-byte LE offset + 1-byte (length - 3) follow; min match = 3 If compressed output >= original, the block is stored uncompressed (flag 0x46). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses `input` into QuickLZ format and writes to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a QuickLZ stream from `input` and writes to `output`. | - -### Namespace `FileFormat.Rar` - -[`Rar4Writer`](#rar4writer) · [`RarEntry`](#rarentry) · [`RarFormatDescriptor`](#rarformatdescriptor) · [`RarInPlaceAdder`](#rarinplaceadder) · [`RarInPlaceRemover`](#rarinplaceremover) · [`RarLayoutMap`](#rarlayoutmap) · [`RarReader`](#rarreader) · [`RarWriter`](#rarwriter) - -#### `Rar4Writer` - -Creates RAR4 archives. Supports Store and compressed (LZ+Huffman) methods, with optional AES-128-CBC encryption. RAR4 uses the v2.9 (UnPack29) compression algorithm. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Rar4Writer` | `Rar4Writer(Stream stream, bool leaveOpen = false, byte method = 51, int windowBits = 20, bool solid = false, string password = null)` | Initializes a new `Rar4Writer`. | -| `AddFile` | `void AddFile(string fileName, ReadOnlySpan data, DateTimeOffset? modifiedTime = null)` | Adds a file entry to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, byte method = 51, string password = null)` | Creates a RAR4 archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the end-of-archive header and flushes. | - -#### `RarEntry` - -Represents an entry in a RAR archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RarEntry` | `RarEntry()` | | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `CompressionMethod` | `int CompressionMethod { get; set; }` | Gets or sets the compression method used (0 = Store, 1-5 = compressed). | -| `Crc` | `uint? Crc { get; set; }` | Gets or sets the CRC-32 of the uncompressed data, or `null` if not stored. | -| `IsDirectory` | `bool IsDirectory { get; set; }` | Gets or sets a value indicating whether this entry is a directory. | -| `IsEncrypted` | `bool IsEncrypted { get; set; }` | Gets or sets a value indicating whether this entry is encrypted. | -| `IsSolid` | `bool IsSolid { get; set; }` | Gets or sets a value indicating whether this entry uses solid compression (dictionary carries over from previous file). | -| `ModifiedTime` | `DateTimeOffset? ModifiedTime { get; set; }` | Gets or sets the last modification time, or `null` if not stored. | -| `Name` | `string Name { get; set; }` | Gets or sets the entry name (including path within the archive). | -| `Size` | `long Size { get; set; }` | Gets or sets the uncompressed size in bytes. | - -#### `RarFormatDescriptor` - -RAR archive (RAR4 and RAR5 container framing). References: `https://www.rarlab.com/technote.htm` — RAR 5.0 archive format technote (RARLAB, official)unrar source distribution (rarlab.com) — de-facto reference for RAR4 decoding`https://en.wikipedia.org/wiki/RAR_(file_format)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RarFormatDescriptor` | `RarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends (or same-name updates) `inputs` in `archive`. A pure add of new file names to a non-solid/recovery-free, unencrypted RAR5 archive takes the genuine in-place append (`RarInPlaceAdder`): new non-solid FILE blocks are written before a rewritten ENDARC, leaving every pre-existing block byte-identical at its original offset. A same-name update is attempted as an in-place remove of the old block (`RarInPlaceRemover`, only when the old block is not part of a solid run) followed by an in-place add of the new content. Any case that cannot be served byte-additively — encryption headers, a recovery-record (RR) or quick-open (QO) service block, a RAR4 archive, a directory input, or an update whose old block is part of a solid run — falls back to the verified extract -> re-create rebuild. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Builds a RAR archive from `inputs`. Selects RAR4 or RAR5 based on `options.MethodName` and resolves dictionary / level from `options.DictSize` / `options.Level`. | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction — routed through the bounded `OpenEntry` so the per-entry isolation contract holds uniformly. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single RAR entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's uncompressed size so the universal per-entry isolation contract holds even though RAR's decoder produces a byte[]. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from the RAR5 archive. Removing a non-solid FILE block from a recovery-free, unencrypted RAR5 archive is a genuine O(bytes-shifted) in-place remove: the block's `[header + data]` range is excised and the following blocks (and ENDARC) shift down to close the gap, so every surviving block stays byte-identical — the ones before the hole at their exact offset, the ones after shifted down (`RarInPlaceRemover`). Any case that cannot be served byte-additively — a target that is part of a solid run (itself solid, or immediately followed by a solid block that reuses its dictionary), an encryption header, a recovery-record (RR) or quick-open (QO) service block, or a RAR4 archive — falls back to the verified extract -> re-create rebuild. | - -#### `RarInPlaceAdder` - -Genuine O(bytes-added) in-place append for RAR5 archives. New files are compressed into fresh, non-solid RAR5 FILE blocks written at the byte offset the old end-of-archive block occupied; a new ENDARC block is written after them. The signature and every pre-existing block (offset 8 .. old-ENDARC-offset) are never re-read or re-packed, so the existing compressed file data stays byte-identical at its original offsets. RAR5 readers scan blocks sequentially and the MAIN header stores no file count or offset table, so an append needs no back-patching of earlier headers. A newly appended file is written non-solid (solid bit clear), which resets the dictionary and lets it decode independently — so it can be appended even after a solid run without touching the existing blocks. The append bails out with `NotSupportedException` (so the caller can fall back to the verified rebuild) when the archive is not byte-additive: an ENCRYPTION block / encrypted headers — append cannot extend an encrypted header chain byte-additively;a recovery-record SERVICE block ("RR") or a quick-open SERVICE block ("QO") — both checksum/index the whole archive, so appending invalidates them;no ENDARC block (truncated / streamed archive) — there is no defined insertion point;a new file name that collides with an existing entry (a replace would rewrite an existing block). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Add` | `static void Add(Stream archive, IReadOnlyList> newFiles, int method = 0, int dictionarySizeLog = 17)` | Attempts a genuine in-place append of `newFiles` to the RAR5 archive in `archive`. On success the stream contains the merged archive and its length is trimmed to the new end. Throws `NotSupportedException` for any case that cannot be served as a pure byte-additive append (the caller should then rebuild). | - -#### `RarInPlaceRemover` - -Genuine O(bytes-shifted) in-place removal for RAR5 archives. RAR5 blocks are laid out sequentially, so removing a non-solid FILE block = excising its `[header + data]` byte range and shifting every following block down to close the gap. Only the bytes after the removed block move; the signature and MAIN header are unchanged, and the base RAR5 layout carries no whole-archive checksum, so nothing earlier needs back-patching. The trailing ENDARC keeps the same fixed encoding, just at its new (lower) offset. The removal bails out with `NotSupportedException` (so the caller can fall back to the verified rebuild) when it cannot be byte-additive: an ENCRYPTION block / encrypted file headers — the header chain is not plain-byte editable;a recovery-record (RR) or quick-open (QO) SERVICE block — both checksum/index the whole archive, so a removal invalidates them;no ENDARC block (truncated / streamed archive);the target is part of a solid run — it is itself solid, or the FILE block immediately after it is solid (and would reuse the removed file's dictionary). Removing such a file breaks the solid chain, so the survivors must be recompressed.a RAR4 archive (only RAR5 is edited in place). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Remove` | `static void Remove(Stream archive, IReadOnlyCollection entryNames)` | Attempts a genuine in-place removal of `entryNames` from the RAR5 archive in `archive`. On success the stream contains the compacted archive and its length is trimmed to the new end. Throws `NotSupportedException` for any case that cannot be served as a pure byte-shifting removal (the caller should then rebuild). | - -#### `RarLayoutMap` - -Walks RAR5 or RAR4 block headers and emits the byte-level layout of the archive as `DefragBlockInfo` tiles: signature, main header, file headers (MetadataReserved), compressed data payloads (Used), service headers, and end-of-archive marker. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `RarReader` - -Reads entries from a RAR v4 or v5 archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RarReader` | `RarReader(Stream stream, bool leaveOpen = false)` | Initializes a new `RarReader` from a seekable stream containing a RAR archive. | -| `RarReader` | `RarReader(Stream stream, string password, bool leaveOpen = false)` | Initializes a new `RarReader` with a password for encrypted archives. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the RAR archive. | -| `HasRecoveryRecord` | `bool HasRecoveryRecord { get; }` | Gets whether this archive has a recovery record. | -| `IsRar4` | `bool IsRar4 { get; }` | Gets a value indicating whether this is a RAR4 (or earlier) format archive. | -| `IsRar5` | `bool IsRar5 { get; }` | Gets a value indicating whether this is a RAR5 format archive. | -| `Version` | `int Version { get; }` | Gets the RAR version (1-5) for the overall archive format. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(int entryIndex)` | Extracts the data for the entry at the specified index. | -| `Extract` | `void Extract(int entryIndex, Stream output)` | Extracts the data for the entry at the specified index into the given output stream. | -| `VerifyRecoveryRecord` | `bool VerifyRecoveryRecord()` | Verifies the recovery record by checking Reed-Solomon parity data against archive contents. Returns `true` if the parity is valid. | - -#### `RarWriter` - -Creates RAR5 archives. Supports Store and compressed (LZ+Huffman) methods, optional solid mode, and optional AES-256 encryption. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RarWriter` | `RarWriter(Stream stream, bool leaveOpen = false, int method = 3, int dictionarySizeLog = 17, bool solid = false, string password = null, int recoveryPercent = 0, bool encryptHeaders = false)` | Initializes a new `RarWriter`. | -| `AddFile` | `void AddFile(string fileName, ReadOnlySpan data, DateTimeOffset? modifiedTime = null)` | Adds a file entry to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, int method = 3, string password = null)` | Creates a RAR5 archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the end-of-archive header and flushes. | - -### Namespace `FileFormat.RefPack` - -[`RefPackFormatDescriptor`](#refpackformatdescriptor) · [`RefPackStream`](#refpackstream) - -#### `RefPackFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RefPackFormatDescriptor` | `RefPackFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `RefPackStream` - -Compressor and decompressor for the RefPack (EA/DBPF) compression format. RefPack is a multi-width opcode LZ77 variant used by Electronic Arts in various game file formats (SimCity 4, The Sims 2, etc.). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data)` | Compresses raw data into the RefPack format and returns the result as a new byte array. | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses raw data into the RefPack format and writes the result to `output`. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses a RefPack-compressed byte array and returns the original data. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a RefPack-compressed stream and writes the original data to `output`. | - -### Namespace `FileFormat.ResourceDll` - -[`ResourceDllFormatDescriptor`](#resourcedllformatdescriptor) · [`ResourceDllReader`](#resourcedllreader) · [`ResourceDllReader.Entry`](#resourcedllreaderentry) · [`ResourceDllReader.RawResource`](#resourcedllreaderrawresource) · [`ResourceDllWriter`](#resourcedllwriter) - -#### `ResourceDllFormatDescriptor` - -Format descriptor for resource-DLL archives — PE32+ DLLs whose only payload is a populated `.rsrc` section holding files as `RT_RCDATA` resources. Detection by magic alone matches every PE; `List`/`Extract` validate the structure (a PE without an `RT_RCDATA` tree yields zero entries rather than throwing). The `.resource.dll` compound extension routes file-by-name dispatch here without claiming all `.dll` files. References: `https://learn.microsoft.com/en-us/windows/win32/debug/pe-format` — PE/COFF specification — defines the .rsrc resource section`https://en.wikipedia.org/wiki/Portable_Executable` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ResourceDllFormatDescriptor` | `ResourceDllFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `ResourceDllReader` - -Reads files embedded as Win32 resources in a PE32/PE32+ DLL/EXE. `Read` returns only `RT_RCDATA` string-named entries (the shape `ResourceDllWriter` produces); `ReadAll` returns every resource, regardless of type, suitable for general PE-resource browsing. Multi-language resources expose only the first language entry. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ResourceDllReader` | `ResourceDllReader()` | | -| `ReadAll` | `List ReadAll(Stream stream)` | | -| `Read` | `List Read(Stream stream)` | | - -#### `ResourceDllReader.Entry` - -One `RT_RCDATA`-style entry as surfaced by `Read`. `Data.Length` is authoritative; there is no separate size field. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entry` | `Entry(string Name, byte[] Data)` | One `RT_RCDATA`-style entry as surfaced by `Read`. `Data.Length` is authoritative; there is no separate size field. | -| `Data` | `byte[] Data { get; init; }` | | -| `Name` | `string Name { get; init; }` | | - -#### `ResourceDllReader.RawResource` - -One generic PE resource as surfaced by `ReadAll`. `TypeId` is the RT_* numeric type (or a string type, in which case `TypeName` is non-null). `NameId` is the numeric id (0 when the resource has a string name, in which case `NameString` is non-null). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RawResource` | `RawResource(ushort TypeId, string TypeName, ushort NameId, string NameString, ushort LanguageId, byte[] Data)` | One generic PE resource as surfaced by `ReadAll`. `TypeId` is the RT_* numeric type (or a string type, in which case `TypeName` is non-null). `NameId` is the numeric id (0 when the resource has a string name, in which case `NameString` is non-null). | -| `Data` | `byte[] Data { get; init; }` | | -| `LanguageId` | `ushort LanguageId { get; init; }` | | -| `NameId` | `ushort NameId { get; init; }` | | -| `NameString` | `string NameString { get; init; }` | | -| `TypeId` | `ushort TypeId { get; init; }` | | -| `TypeName` | `string TypeName { get; init; }` | | - -#### `ResourceDllWriter` - -Writes a minimal PE32+ DLL whose only purpose is to host opaque files as Win32 resources. Each input becomes one `RT_RCDATA` resource keyed by its archive name (string ID). Readable from native code via `LoadLibraryEx + FindResource + LoadResource + LockResource`, from .NET via the same API through P/Invoke, or cross-platform via any PE resource parser (LIEF, pefile, llvm-readobj). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ResourceDllWriter` | `ResourceDllWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds `data` as an embedded resource keyed by `name`. Names become UTF-16 string IDs in the resource directory. | -| `WriteTo` | `void WriteTo(Stream output)` | Serializes the resource DLL to `output`. | - -### Namespace `FileFormat.Rgss` - -[`RgssEntry`](#rgssentry) · [`RgssFormatDescriptor`](#rgssformatdescriptor) · [`RgssReader`](#rgssreader) - -#### `RgssEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `RgssEntry` | `RgssEntry()` | | -| `FileKey` | `uint FileKey { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `RgssFormatDescriptor` - -RPG Maker XP/VX/VX Ace RGSSAD encrypted resource archive. References: `https://github.com/morkt/GARbro` — GARbro — game resource browser implementing RGSSAD decryptionformat defined by Enterbrain's RPG Maker runtime (RGSS); no official spec, key schedule reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RgssFormatDescriptor` | `RgssFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing RGSS archive via the verified extract -> edit -> re-create rebuild. The synthetic `metadata.ini` listing entry (a derived view of the header) is dropped from the extracted tree before re-creation so it is not duplicated as a real entry. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the RGSS archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the RGSS archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries via the verified extract -> edit -> re-create rebuild, dropping the synthetic `metadata.ini` the same way `Add` does. | - -#### `RgssReader` - -Reads RPG Maker RGSSAD / RGSS2A / RGSS3A encrypted archives. v1 ("RGSSAD\0\1"): per-byte XOR with low byte of a running 32-bit key (init 0xDEADCAFE, advance `key = key * 7 + 3`). Entries: name_length (u32 xor), name (per-byte xor), size (u32 xor), then inline data (xor'd with running key restarted at 0xDEADCAFE advanced per byte). v2 ("RGSSAD\0\2"): u32-at-a-time XOR with running key (init 0xDEADCAFE, advance per word). Entries: data_offset, size, name_length, name — name xor'd per 32-bit word. v3 ("RGSSAD\0\3"): master key stored at offset 8 (u32 LE), transformed via `masterKey * 9 + 3`. Entries: offset, size, per-file-key, name_length, name — all XOR'd with the transformed master key. Data is XOR'd with the per-file key, byte-by-byte cycling through key bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RgssReader` | `RgssReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `MasterKeyV3` | `uint MasterKeyV3 { get; }` | | -| `Version` | `int Version { get; }` | | -| `Extract` | `byte[] Extract(RgssEntry entry)` | | - -### Namespace `FileFormat.Rnc` - -[`RncFormatDescriptor`](#rncformatdescriptor) · [`RncStream`](#rncstream) - -#### `RncFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RncFormatDescriptor` | `RncFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `RncStream` - -Compressor and decompressor for the Rob Northen Compression (RNC) format. RNC is a Huffman + LZSS scheme used in many classic Amiga and DOS games. This implementation supports Method 1 (Huffman + LZSS). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses raw data into the RNC Method 1 format and writes the result to `output`. | -| `Crc16` | `static ushort Crc16(ReadOnlySpan data)` | Computes the RNC CRC-16 checksum using the custom polynomial 0xCC01. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an RNC-compressed stream and writes the original data to `output`. | - -### Namespace `FileFormat.Rpa` - -[`RpaEntry`](#rpaentry) · [`RpaFormatDescriptor`](#rpaformatdescriptor) · [`RpaReader`](#rpareader) · [`RpaWriter`](#rpawriter) - -#### `RpaEntry` - -A single entry parsed from an RPA index. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpaEntry` | `RpaEntry()` | | -| `Length` | `long Length { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Path` | `string Path { get; init; }` | | -| `Prefix` | `byte[] Prefix { get; init; }` | | - -#### `RpaFormatDescriptor` - -Ren'Py visual-novel resource archive (RPA) — pickle-encoded index, zlib-compressed header. References: `https://github.com/renpy/renpy` — Ren'Py engine — its loader defines the RPA format`https://github.com/Shizmob/rpatool` — rpatool — standalone RPA reader/writer`https://www.renpy.org/` — Ren'Py project home - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpaFormatDescriptor` | `RpaFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates an RPA-3.0 archive at `output` containing `inputs`. Synthetic entries from the listing layer (`FULL.rpa`, `metadata.ini`) are skipped automatically so round-trips through Extract→Create don't accidentally embed the passthrough copy. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Handles three synthetic shapes: `FULL.rpa` (a passthrough view of the entire archive), `metadata.ini` (built on the fly), and the regular pickle-indexed entries whose bytes are decoded by the reader. All returns are wrapped in `BoundedEntryStream` sized to their logical length so adjacent regions can't leak. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `RpaReader` - -Reads Ren'Py RPA archives (RPA-2.0, RPA-3.0, RPA-3.2). The first line is an ASCII header giving the offset of a zlib-compressed Python pickle index. The pickle maps filename to a list of (offset, length, prefix) tuples; for v3 the offset/length are XOR-scrambled with a 32-bit key embedded in the header. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpaReader` | `RpaReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `IndexOffset` | `long IndexOffset { get; }` | | -| `PickleParsed` | `bool PickleParsed { get; }` | | -| `Version` | `string Version { get; }` | | -| `XorKey` | `uint XorKey { get; }` | | -| `Extract` | `byte[] Extract(RpaEntry entry)` | Extracts the raw bytes for the given entry (prefix + data slice). | - -#### `RpaWriter` - -Writer for Ren'Py archive files (RPA-3.0). The output layout is: 34-byte ASCII header `"RPA-3.0 <16-hex-offset> <8-hex-key>\n"`.Raw file payloads, back-to-back, starting immediately after the header.zlib-compressed Python pickle index (offset/length XORed with the key) at the offset declared in the header. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpaWriter` | `RpaWriter(Stream stream, bool leaveOpen = false, uint xorKey = 3735928559)` | Initializes a new `RpaWriter` targeting `stream`. | -| `AddEntry` | `void AddEntry(string path, byte[] data, byte[] prefix = null)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Emits the header placeholder, copies each entry's payload to the stream, builds the zlib-compressed pickle index and back-patches the header with the real index offset and XOR key. | - -### Namespace `FileFormat.Rpm` - -[`RpmFormatDescriptor`](#rpmformatdescriptor) · [`RpmHeader`](#rpmheader) · [`RpmHeaderEntry`](#rpmheaderentry) · [`RpmReader`](#rpmreader) · [`RpmWriter`](#rpmwriter) - -#### `RpmFormatDescriptor` - -RPM package — lead + signature header + main header + compressed cpio payload. References: `https://github.com/rpm-software-management/rpm` — canonical rpm sources (docs/manual describes the package format)Edward C. Bailey, "Maximum RPM" — classic format documentation`https://en.wikipedia.org/wiki/RPM_Package_Manager` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpmFormatDescriptor` | `RpmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the RPM archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the RPM archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single RPM entry as a bounded read-only stream. RPM wraps an inner CPIO payload; entry names route to the matching CPIO member's decoded bytes, wrapped in a `BoundedEntryStream` sized to its logical length. | - -#### `RpmHeader` - -Represents a parsed RPM header structure (either the Signature or the main Header section). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of index entries in this header. | -| `Store` | `byte[] Store { get; }` | Gets the raw store data referenced by the index entries. | -| `GetInt32` | `int? GetInt32(int tag)` | Reads an `Int32` value for the given tag from the store. Returns `null` if the tag is not present. | -| `GetString` | `string GetString(int tag)` | Reads a string value for the given tag from the store. Returns `null` if the tag is not present. | - -#### `RpmHeaderEntry` - -A single index entry in an RPM header structure. Each entry describes one tag: its type, byte offset into the store, and element count. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpmHeaderEntry` | `RpmHeaderEntry(int Tag, int Type, int Offset, int Count)` | A single index entry in an RPM header structure. Each entry describes one tag: its type, byte offset into the store, and element count. | -| `Count` | `int Count { get; init; }` | Number of elements (strings, integers, etc.) stored for this tag. | -| `Offset` | `int Offset { get; init; }` | Byte offset of the tag's data within the header store section. | -| `Tag` | `int Tag { get; init; }` | The tag number identifying the field. | -| `Type` | `int Type { get; init; }` | The data type code (see `RpmConstants` TypeXxx constants). | - -#### `RpmReader` - -Reads metadata and payload from an RPM package file. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpmReader` | `RpmReader(Stream stream)` | Opens an RPM package from the given stream and parses its Lead, Signature, and Header. | -| `Architecture` | `string Architecture { get; }` | Gets the package architecture from the main header. | -| `Header` | `RpmHeader Header { get; }` | Gets the parsed main Header structure. | -| `Name` | `string Name { get; }` | Gets the package name from the main header. | -| `PayloadCompressor` | `string PayloadCompressor { get; }` | Gets the name of the payload compressor, e.g. `"gzip"`, `"bzip2"`, `"xz"`, `"lzma"`, or `"zstd"`. Defaults to `"gzip"` when the PAYLOADCOMPRESSOR tag is absent. | -| `PayloadOffset` | `long PayloadOffset { get; }` | Gets the byte offset where the compressed payload begins. | -| `Release` | `string Release { get; }` | Gets the package release from the main header. | -| `SignatureHeader` | `RpmHeader SignatureHeader { get; }` | Gets the parsed Signature header structure. | -| `Version` | `string Version { get; }` | Gets the package version from the main header. | -| `Dispose` | `void Dispose()` | | -| `ExtractFiles` | `IReadOnlyList> ExtractFiles()` | Decompresses the payload, parses the inner cpio archive, and returns all regular file entries. | -| `GetDecompressedPayloadStream` | `Stream GetDecompressedPayloadStream()` | Returns the payload already decompressed, ready to be handed to a `CpioReader`. | -| `GetPayloadStream` | `Stream GetPayloadStream()` | Returns a stream positioned at the beginning of the raw compressed payload. | - -#### `RpmWriter` - -Creates basic unsigned RPM packages. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RpmWriter` | `RpmWriter()` | | -| `Architecture` | `string Architecture { get; set; }` | Gets or sets the package architecture. | -| `Name` | `string Name { get; set; }` | Gets or sets the package name. | -| `PayloadCompressor` | `string PayloadCompressor { get; set; }` | Gets or sets the payload compressor name. Supported: "gzip", "xz", "bzip2", "zstd". Defaults to "gzip". | -| `Release` | `string Release { get; set; }` | Gets or sets the package release. | -| `Version` | `string Version { get; set; }` | Gets or sets the package version. | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file to the package payload. | -| `ToArray` | `byte[] ToArray()` | Creates the RPM package as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the RPM package to the specified stream. | - -### Namespace `FileFormat.Rzip` - -[`RzipBuildingBlock`](#rzipbuildingblock) · [`RzipFormatDescriptor`](#rzipformatdescriptor) · [`RzipStream`](#rzipstream) - -#### `RzipBuildingBlock` - -Exposes rzip as a benchmarkable building block. Produces a complete rzip stream — "RZIP" signature, version, the big-endian original size and the token stream — so the payload carries its own length and no extra uncompressed-size header is prepended. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RzipBuildingBlock` | `RzipBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `RzipFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RzipFormatDescriptor` | `RzipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `RzipStream` - -Provides static methods for compressing and decompressing data in the RZIP format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses data into RZIP format. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an RZIP stream. | - -### Namespace `FileFormat.Sar` - -[`SarEntry`](#sarentry) · [`SarFormatDescriptor`](#sarformatdescriptor) · [`SarReader`](#sarreader) · [`SarWriter`](#sarwriter) - -#### `SarEntry` - -Represents a single file entry in a SAR archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarEntry` | `SarEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the filename stored in the archive (null-terminated Shift-JIS/ASCII). | -| `Offset` | `uint Offset { get; init; }` | Gets the offset of the file data relative to the start of the data area. | -| `Size` | `uint Size { get; init; }` | Gets the size of the file data in bytes. | - -#### `SarFormatDescriptor` - -NScripter SAR resource archive (uncompressed entries behind a big-endian index). References: `https://github.com/morkt/GARbro` — GARbro — implements NScripter SAR extractionNScripter engine (Naoki Takahashi) defines the format; ONScripter is the open reimplementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarFormatDescriptor` | `SarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the SAR archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the SAR archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `SarReader` - -Reads entries from an NScripter SAR archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarReader` | `SarReader(Stream stream, bool leaveOpen = false)` | Initializes a new `SarReader` from a stream containing a SAR archive. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in this archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(SarEntry entry)` | Extracts the data for the given entry. | - -#### `SarWriter` - -Writes NScripter SAR archives (uncompressed). Layout matches `SarReader`: Header: uint16 BE file count, uint32 BE data offset.Per entry: null-terminated ASCII filename, uint32 BE offset (relative to data start), uint32 BE size.Data area: file data concatenated, in the same order as the index. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarWriter` | `SarWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Sarc` - -[`SarcEntry`](#sarcentry) · [`SarcFormatDescriptor`](#sarcformatdescriptor) · [`SarcHash`](#sarchash) · [`SarcReader`](#sarcreader) · [`SarcWriter`](#sarcwriter) - -#### `SarcEntry` - -Represents a single file entry in a Nintendo SARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarcEntry` | `SarcEntry()` | | -| `NameHash` | `uint NameHash { get; init; }` | Gets the precomputed name hash stored in the SFAT entry. | -| `Name` | `string Name { get; init; }` | Gets the entry name resolved from the SFNT string table (UTF-8 path). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute offset of this entry's data within the SARC stream. | -| `Size` | `long Size { get; init; }` | Gets the size in bytes of this entry's payload. | - -#### `SarcFormatDescriptor` - -Nintendo SARC (Sorted ARChive) used across Wii U / 3DS / Switch first-party titles. References: `https://zeldamods.org/wiki/SARC` — ZeldaMods wiki — community SARC/SFAT/SFNT layout documentationNintendo's internal archive format; no official spec, structure community-documented - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarcFormatDescriptor` | `SarcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the SARC archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the SARC archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `SarcHash` - -SARC filename hash. The SARC SFAT stores entries sorted by this hash so that the Switch SDK can perform a binary search by name without parsing strings. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hash` | `static uint Hash(string name, uint hashKey)` | Computes the SARC name hash. Each character is treated as a SIGNED byte before being added — high-bit characters (e.g. UTF-8 continuation bytes in non-ASCII paths) sign-extend to 0xFFFFFFxx, which is how the official hash differs from a plain unsigned-byte rolling hash. | - -#### `SarcReader` - -Reads a Nintendo SARC archive (Wii U / 3DS / Switch). Endianness is detected via the BOM at offset 6: 0xFEFF = little-endian (Switch), 0xFFFE = big-endian (Wii U / 3DS). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarcReader` | `SarcReader(Stream stream, bool leaveOpen = false)` | Initializes a new `SarcReader` from a stream. | -| `DataOffset` | `long DataOffset { get; }` | Gets the data-region start offset declared in the SARC header. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries discovered in the archive, in SFAT order (sorted by NameHash). | -| `HashKey` | `uint HashKey { get; }` | Gets the hash multiplier (HashKey) declared in the SFAT header. | -| `IsLittleEndian` | `bool IsLittleEndian { get; }` | Gets whether the archive was stored little-endian. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(SarcEntry entry)` | Extracts the raw payload bytes for the given entry. | - -#### `SarcWriter` - -Creates a Nintendo SARC archive in little-endian format (Switch convention). Entries are sorted by name hash on Finish() — the "sorted" in SARC — so that the Switch SDK can binary-search by name without scanning the string table. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SarcWriter` | `SarcWriter(Stream stream, bool leaveOpen = false, uint hashKey = 101)` | Initializes a new `SarcWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds a file entry to the archive. Path separators should be forward slashes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalizes the archive layout and writes it to the underlying stream. | - -### Namespace `FileFormat.SevenZip` - -[`SevenZipCodec`](#sevenzipcodec) · [`SevenZipEntry`](#sevenzipentry) · [`SevenZipFilter`](#sevenzipfilter) · [`SevenZipFormatDescriptor`](#sevenzipformatdescriptor) · [`SevenZipInPlaceAdder`](#sevenzipinplaceadder) · [`SevenZipInPlaceRemover`](#sevenzipinplaceremover) · [`SevenZipLayoutMap`](#sevenziplayoutmap) · [`SevenZipReader`](#sevenzipreader) · [`SevenZipWriter`](#sevenzipwriter) · [`SevenZipWriter.BlockDescriptor`](#sevenzipwriterblockdescriptor) · [`SolidBlockOptimizer`](#solidblockoptimizer) · [`SolidBlockOptimizer.OptimizeResult`](#solidblockoptimizeroptimizeresult) · [`SolidBlockOptimizer.ProgressCallback`](#solidblockoptimizerprogresscallback) · [`SolidBlockOptimizer.TrialResult`](#solidblockoptimizertrialresult) · [`SolidBlockPlanner`](#solidblockplanner) · [`SolidBlockPlanner.SolidBlock`](#solidblockplannersolidblock) - -#### `SevenZipCodec` - -Specifies the compression codec used when writing a 7z archive. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Lzma2` | `0` | LZMA2 compression (default). | -| `Lzma` | `1` | LZMA compression. | -| `Deflate` | `2` | Deflate compression. | -| `BZip2` | `3` | BZip2 compression. | -| `PPMd` | `4` | PPMd compression (Model H, variant used by 7-Zip). | -| `Copy` | `5` | Copy (store without compression). | - -#### `SevenZipEntry` - -Represents a single entry (file or directory) in a 7z archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SevenZipEntry` | `SevenZipEntry()` | | -| `Attributes` | `uint? Attributes { get; set; }` | Gets or sets the Windows file attributes. | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes (-1 if unknown). | -| `Crc` | `uint? Crc { get; set; }` | Gets or sets the CRC-32 of the uncompressed data. | -| `CreationTime` | `DateTime? CreationTime { get; set; }` | Gets or sets the creation time in UTC. | -| `IsDirectory` | `bool IsDirectory { get; set; }` | Gets or sets whether this entry is a directory. | -| `LastWriteTime` | `DateTime? LastWriteTime { get; set; }` | Gets or sets the last write time in UTC. | -| `Method` | `string Method { get; set; }` | Gets or sets the compression method name. | -| `Name` | `string Name { get; set; }` | Gets or sets the file name (including path within the archive). | -| `Size` | `long Size { get; set; }` | Gets or sets the uncompressed size in bytes. | - -#### `SevenZipFilter` - -Specifies an optional pre-filter applied before compression when writing a 7z archive. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No filter. | -| `Copy` | `1` | Copy filter (pass-through, codec 0x00). | -| `BcjX86` | `2` | BCJ x86 filter (codec 0x03030103). | -| `BcjArm` | `3` | BCJ ARM filter (codec 0x03030501). | -| `BcjArmThumb` | `4` | BCJ ARM Thumb filter (codec 0x03030701). | -| `BcjPowerPC` | `5` | BCJ PowerPC filter (codec 0x03030205). | -| `BcjSparc` | `6` | BCJ SPARC filter (codec 0x03030805). | -| `BcjIA64` | `7` | BCJ IA-64 filter (codec 0x03030401). | -| `Delta` | `8` | Delta filter (codec 0x03). | -| `Bcj2` | `9` | BCJ2 x86 filter with 4 sub-streams (codec 0x0303011B). | - -#### `SevenZipFormatDescriptor` - -7-Zip (.7z) archive — LZMA/LZMA2-based container with solid compression and encrypted-header support. References: `https://www.7-zip.org/7z.html` — official 7z format page (Igor Pavlov)`7zFormat.txt` in the 7-Zip / LZMA SDK sources — the structural reference`https://en.wikipedia.org/wiki/7z` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IFormatOptionsSchema`, `IFormatValidator`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SevenZipFormatDescriptor` | `SevenZipFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or same-name updates) files in the 7z archive. Pure additions of new names are served as a genuine O(bytes-added) in-place append: the new files are compressed into one fresh solid block written at the old header's byte offset, leaving every existing solid block byte-identical at its original position (`SevenZipInPlaceAdder`). A same-name update is attempted as an in-place remove of the old entry (`SevenZipInPlaceRemover`, only when it removes a whole folder/solid block) followed by an in-place add of the new content — still O(bytes touched), no re-pack of the untouched blocks. Anything that cannot be served byte-additively — an encoded/encrypted header, a non-trivial packed layout (PackPos != 0, a gap, BCJ2 / AES folders), or an update whose old entry is a proper subset of a multi-file solid block — falls back to the verified extract → re-create rebuild. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Builds a 7z archive from `inputs`. Plans solid blocks by extension similarity, segregates incompressible files, and per-block recommends BCJ x86 filter for executables. | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the 7z archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the 7z archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. Routed through the bounded `OpenEntry` so the per-entry isolation contract holds uniformly across descriptors. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single 7z entry as a read-only `Stream` bounded to its uncompressed size. 7z is solid-block: the underlying reader must decompress the whole containing folder to extract any one entry — the existing in-memory path is preserved — but the returned view is a `BoundedEntryStream` sized to the single entry's logical bytes, so neighbouring entries within the same solid block are physically unreachable through it. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from the 7z archive. A removal that drops one or more entire folders (solid blocks), plus any empty-stream entries, is served as a genuine O(bytes-shifted) in-place remove: the removed folders' packed streams are excised and the packed region is compacted by the gap, so every surviving folder's packed stream stays byte-identical (the ones before a hole at their exact offset, the ones after shifted down) — no re-pack (`SevenZipInPlaceRemover`). A removal that targets a proper subset of a multi-file solid block (the survivors would have to be recompressed), or an archive with an encoded/encrypted header or a non-trivial packed layout, falls back to the verified extract → re-create rebuild. | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the 7z archive: gaps between packed solid blocks and any junk before the compressed metadata or trailing the file. The signature header, solid blocks and end-of-archive metadata are live and preserved, so the archive still extracts byte-identically. Cluster-tip wiping is N/A (7z packs solid blocks with no per-file slack). | - -#### `SevenZipInPlaceAdder` - -Genuine O(bytes-added) in-place append for 7z archives. New files are compressed into one fresh solid block whose packed stream is written at the byte position the old descriptive header occupied; the existing packed region is never re-read or re-packed, so every previously compressed solid block stays byte-identical at its original file offset. Only the small trailing descriptive header (PackInfo / UnpackInfo / SubStreamsInfo / FilesInfo) and the 32-byte signature header are rewritten. The append is attempted only for archives this writer could itself have produced and for pure additions of new names. The following bail out with `NotSupportedException` so the caller can fall back to the verified rebuild: an EncodedHeader (compressed/encrypted metadata) — the trailing header is not a plain `kHeader` structure;`PackPos != 0` or a gap between the end of the packed data and the descriptive header (the new block must start exactly where the old header began);any existing folder whose packed streams cannot be re-emitted verbatim from PackInfo alone — multi-pack-stream chains such as BCJ2, or AES-encrypted folders;a new file whose name collides with an existing entry (a replace would have to touch an existing solid block). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Add` | `static void Add(Stream archive, IReadOnlyList> newFiles, SevenZipCodec codec = 0, int dictionarySize = 8388608)` | Attempts a genuine in-place append of `newFiles` to the 7z archive in `archive`. On success the stream contains the merged archive and its length is trimmed to the new end. Throws `NotSupportedException` for any case that cannot be served as a pure byte-additive append (the caller should then rebuild). | - -#### `SevenZipInPlaceRemover` - -Genuine O(bytes-shifted) in-place removal for 7z archives. A 7z file lives inside a folder (solid block); removing one is byte-additive only when it removes an entire folder's worth of files. Such a removal drops that folder's packed stream and compacts the packed region by the gap — physically shifting only the packed bytes that follow the removed stream — then rewrites the small trailing descriptive header (PackInfo / UnpackInfo / SubStreamsInfo / FilesInfo minus the removed entries) and the 32-byte signature header. Every surviving folder's packed stream stays byte-identical; the ones before the removed stream keep their exact offsets, the ones after move down by the gap without being re-read or re-packed. Removal of empty-stream entries (directories / empty files) carries no packed data and is always served in place. The removal bails out with `NotSupportedException` (so the caller can fall back to the verified rebuild) when it cannot be byte-additive: an EncodedHeader (compressed/encrypted metadata) — the trailing header is not a plain `kHeader` structure;`PackPos != 0` or a gap between the packed data and the header;any folder whose packed stream cannot be re-emitted verbatim from PackInfo alone — multi-pack-stream chains (BCJ2) or AES folders;a removal that targets a proper subset of a multi-file solid block — the surviving members would have to be recompressed. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Remove` | `static void Remove(Stream archive, IReadOnlyCollection entryNames)` | Attempts a genuine in-place removal of `entryNames` from the 7z archive in `archive`. On success the stream contains the compacted archive and its length is trimmed to the new end. Throws `NotSupportedException` for any case that cannot be served as a pure byte-shifting removal (the caller should then rebuild). | - -#### `SevenZipLayoutMap` - -Walks a 7z archive and emits the byte-level layout: signature header, each solid block (packed data), and the compressed metadata at the end. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `SevenZipReader` - -Reads entries from a 7z archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SevenZipReader` | `SevenZipReader(Stream stream, bool leaveOpen = false, string password = null)` | Initializes a new `SevenZipReader` from a seekable stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the 7z archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(int entryIndex)` | Extracts the decompressed data for an entry by index. | -| `Extract` | `void Extract(int entryIndex, Stream output)` | Extracts the decompressed data for an entry into a stream. | - -#### `SevenZipWriter` - -Creates a 7z archive using solid compression with a selectable codec. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SevenZipWriter` | `SevenZipWriter(Stream stream, SevenZipCodec codec, bool leaveOpen = false, int dictionarySize = 8388608, int ppmdOrder = 6, int ppmdMemorySize = 16777216, SevenZipFilter filter = 0, int deltaDistance = 1, string password = null, bool encryptHeaders = false)` | Initializes a new `SevenZipWriter` with an explicit codec. | -| `SevenZipWriter` | `SevenZipWriter(Stream stream, bool leaveOpen = false, int dictionarySize = 8388608)` | Initializes a new `SevenZipWriter`. | -| `AddDirectory` | `void AddDirectory(string name)` | Adds a directory entry. | -| `AddEntry` | `void AddEntry(SevenZipEntry entry, ReadOnlySpan data)` | Adds a file entry from a byte span. | -| `AddEntry` | `void AddEntry(SevenZipEntry entry, Stream data)` | Adds a file entry from a stream. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, SevenZipCodec codec = 0, string password = null)` | Creates a 7z archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `FinishWithBlocks` | `void FinishWithBlocks(IReadOnlyList blockDescs, int maxThreads = 1)` | Finalizes the archive with per-block codec overrides. Each block descriptor specifies which entries go into the block and optionally overrides the codec and filter for that block. Entries not covered by any descriptor are placed into a default block. | -| `Finish` | `void Finish()` | Finalizes the archive by compressing all data and writing the header. All entries are compressed as a single solid block. | -| `Finish` | `void Finish(int maxThreads = 1, long maxBlockSize = 0)` | Finalizes the archive with parallel multi-block compression. Entries are split into solid blocks of at most `maxBlockSize` bytes, and each block is compressed on a separate thread. | - -#### `SevenZipWriter.BlockDescriptor` - -Describes per-block codec/filter overrides for `FinishWithBlocks`. Entry indices refer to file entries (non-directory, non-empty) in the order they were added. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockDescriptor` | `BlockDescriptor()` | | -| `Codec` | `SevenZipCodec? Codec { get; init; }` | Codec override for this block, or null to use the writer's default. | -| `DictionarySize` | `int? DictionarySize { get; init; }` | Dictionary size override, or null to use the writer's default. | -| `EntryIndices` | `int[] EntryIndices { get; init; }` | Indices of file entries belonging to this block (in add-order among file entries). | -| `Filter` | `SevenZipFilter? Filter { get; init; }` | Filter override for this block, or null to use the writer's default. | - -#### `SolidBlockOptimizer` - -Tries multiple solid-block grouping strategies on a 7z archive and returns the one that produces the smallest output. Each strategy extracts all entries, regroups them into solid blocks per the strategy, compresses to measure the result size, and the winning strategy's output is returned. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Optimize` | `static OptimizeResult Optimize(Stream archive, int maxTrials = 5, ProgressCallback onProgress = null)` | Tries up to `maxTrials` candidate grouping strategies and returns the one that produces the smallest archive. | - -#### `SolidBlockOptimizer.OptimizeResult` - -Result of an optimization trial run. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OptimizeResult` | `OptimizeResult()` | | -| `Data` | `byte[] Data { get; init; }` | The re-packed archive bytes (winning strategy). | -| `Trials` | `IReadOnlyList Trials { get; init; }` | Per-strategy trial results, ordered by output size ascending. | -| `WinningStrategy` | `string WinningStrategy { get; init; }` | Name of the winning strategy. | - -#### `SolidBlockOptimizer.ProgressCallback` - -Callback invoked before each trial starts. Parameters: (strategyIndex, totalStrategies, strategyName). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ProgressCallback` | `void SolidBlockOptimizer.ProgressCallback(int index, int total, string strategyName)` | Callback invoked before each trial starts. Parameters: (strategyIndex, totalStrategies, strategyName). | - -#### `SolidBlockOptimizer.TrialResult` - -A single trial run result. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TrialResult` | `TrialResult()` | | -| `Elapsed` | `TimeSpan Elapsed { get; init; }` | | -| `OutputSize` | `long OutputSize { get; init; }` | | -| `StrategyName` | `string StrategyName { get; init; }` | | - -#### `SolidBlockPlanner` - -Groups files into solid blocks by content similarity for better compression. Files with similar extensions are grouped together, incompressible files are separated, and blocks are capped at a configurable maximum size. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultMaxBlockSize` | `const long DefaultMaxBlockSize` | Default maximum solid block size (64 MB, matching WinRAR default). | -| `DetectIncompressible` | `static HashSet DetectIncompressible(IReadOnlyList inputs)` | Detects incompressible files from the input list using entropy analysis. Returns the set of full paths that appear incompressible. | -| `PlanBySimilarity` | `static List PlanBySimilarity(IReadOnlyList inputs, long maxBlockSize = 67108864)` | Plans solid blocks by statistical similarity of file contents rather than extension. Reads each file, computes a fingerprint, and groups similar-content files together. | -| `Plan` | `static List Plan(IReadOnlyList inputs, long maxBlockSize = 67108864, HashSet incompressible = null)` | Plans solid blocks from the given archive inputs. Files grouped by extension similarity, split at `maxBlockSize` boundaries, with incompressible files segregated. | -| `RecommendCodec` | `static SevenZipCodec RecommendCodec(SolidBlock block, SevenZipCodec defaultCodec)` | Recommends the optimal 7z codec for a solid block based on content type. | -| `RecommendFilter` | `static SevenZipFilter RecommendFilter(SolidBlock block)` | Recommends the optimal 7z filter (e.g. BCJ for x86 binaries). | - -#### `SolidBlockPlanner.SolidBlock` - -A block of files to be compressed together in one solid stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SolidBlock` | `SolidBlock()` | | -| `Files` | `List> Files { get; }` | | -| `GroupIndex` | `int GroupIndex { get; init; }` | Extension group index (-1 for catch-all, -2 for incompressible). | -| `IsIncompressible` | `bool IsIncompressible { get; init; }` | | -| `TotalSize` | `long TotalSize { get; }` | | -| `Add` | `void Add(ArchiveInputInfo input, byte[] data)` | | - -### Namespace `FileFormat.Sfar` - -[`SfarEntry`](#sfarentry) · [`SfarFormatDescriptor`](#sfarformatdescriptor) · [`SfarReader`](#sfarreader) · [`SfarWriter`](#sfarwriter) - -#### `SfarEntry` - -One file entry inside a BioWare SFAR archive. SFARs store no in-band paths — only an MD5 hash of the lowercased path. The reader either resolves names from the optional `Filenames.txt` manifest at entry index 0, or falls back to a synthetic `.bin` name. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SfarEntry` | `SfarEntry()` | | -| `BlockTableIndex` | `int BlockTableIndex { get; init; }` | Index of this file's first block in the archive's block-size table. | -| `DataOffset` | `long DataOffset { get; init; }` | Absolute offset of the entry's first block in the archive (5-byte LE on disk). | -| `Name` | `string Name { get; init; }` | The resolved or synthetic name surfaced to callers. | -| `PathHash` | `byte[] PathHash { get; init; }` | Raw 16-byte MD5 hash of the original lowercased forward-slash path. | -| `Size` | `long Size { get; init; }` | Uncompressed payload size in bytes (5-byte LE field on disk; up to 2^40-1). | - -#### `SfarFormatDescriptor` - -BioWare SFAR (Sirius File Archive) — Mass Effect 3 DLC container. References: `https://github.com/ME3Tweaks/LegendaryExplorer` — Legendary Explorer (ME3Tweaks) — modding toolset implementing SFARBioWare's DLC packaging format; no official spec, layout reverse-engineered by the modding community - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SfarFormatDescriptor` | `SfarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a stored-mode SFAR archive containing `inputs`. A synthetic `Filenames.txt` manifest is prepended so the round-trip through `SfarReader` preserves the original names. LZX-packed creation is intentionally not supported. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `SfarReader` - -Read-only parser for BioWare's Sirius File ARchive (Mass Effect 3 DLC) format. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SfarReader` | `SfarReader(Stream stream, bool leaveOpen = false)` | Parses the archive header, entry table and block table from `stream`. | -| `Entries` | `IReadOnlyList Entries { get; }` | All entries discovered in this archive. | -| `IsLzxCompressed` | `bool IsLzxCompressed { get; }` | True when the archive declares `"lzx\0"` in its compression slot. | -| `MaxBlockSize` | `int MaxBlockSize { get; }` | Maximum block size advertised by the archive header (typically 64 KiB). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(SfarEntry entry)` | Decompresses (or copies, for stored blocks) the entry's payload by walking its block list. | - -#### `SfarWriter` - -WORM writer for the BioWare SFAR (Sirius File ARchive) container format used by Mass Effect 3 DLC. Emits the stored variant only — every block is written verbatim, the compression slot is tagged `"\0\0\0\0"` and the on-disk block-size field for each slot is set to the canonical stored-block sentinel (zero, which encodes "full `DefaultMaxBlockSize`"). LZX-packed output is intentionally out of scope. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SfarWriter` | `SfarWriter(Stream output)` | Initializes a new `SfarWriter` targeting `output`. | -| `HashPath` | `static byte[] HashPath(string path)` | Computes the canonical SFAR path hash: MD5 over the UTF-8 bytes of `path` after lowercasing and converting backslashes to forward slashes (the format's path-normalisation rule). | -| `Write` | `void Write(IReadOnlyList> entries)` | Writes a stored-mode SFAR archive containing `entries`. A synthetic `Filenames.txt` manifest is prepended at index 0 so the resulting archive round-trips through `SfarReader` with the original names preserved. | - -### Namespace `FileFormat.Shar` - -[`SharEntry`](#sharentry) · [`SharFormatDescriptor`](#sharformatdescriptor) · [`SharInPlaceModifier`](#sharinplacemodifier) · [`SharReader`](#sharreader) · [`SharWriter`](#sharwriter) - -#### `SharEntry` - -An entry in a shell archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SharEntry` | `SharEntry()` | | -| `Data` | `byte[] Data { get; init; }` | The file data. | -| `FileName` | `string FileName { get; init; }` | The file name. | - -#### `SharFormatDescriptor` - -Shell archive (shar) — self-extracting Unix shell script carrying files as here-documents. References: `https://www.gnu.org/software/sharutils/` — GNU sharutils — shar/unshar reference implementation`https://en.wikipedia.org/wiki/Shar` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SharFormatDescriptor` | `SharFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends file entries to an existing shell archive. Shar's trailing `exit 0` sentinel is overwritten with the new entry's `echo x - name` block (heredoc for text, uudecode for binary) and a fresh `exit 0` sentinel — bytes before the old sentinel are byte-identical after the operation. See `SharInPlaceModifier`. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the SHAR archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the SHAR archive per the requested mode. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | In-place Remove is not implemented for Shar — the heredoc/uudecode block boundaries depend on arbitrary user content and cannot be scanned safely without re-parsing the whole script. Callers should rebuild via the rebuild-based `Defragment` path instead. | - -#### `SharInPlaceModifier` - -Random-access in-place modifier for shell-archive (.shar) files. Shar is a plain-text shell script with a trailing `exit 0` sentinel — the textbook "append before the terminator" shape. Add seeks to the last `exit 0` line, overwrites it with a new `echo x - name` block (heredoc for text, uudecode for binary), and re-writes a fresh `exit 0` sentinel. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream shar, string name, byte[] data)` | Appends a file entry to a shar archive. The byte range before the existing `exit 0` sentinel is not modified. | - -#### `SharReader` - -Reads a shell archive (shar) file. Supports the common 'cat > file << delimiter' and 'sed ... > file << delimiter' patterns. Also decodes uuencoded binary entries. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SharReader` | `SharReader(Stream stream)` | Reads and parses a shar archive from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | The entries found in the shar archive. | - -#### `SharWriter` - -Creates a shell archive (shar) file. Text files use heredoc (cat), binary files use uuencode. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SharWriter` | `SharWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the shar archive. | -| `ToByteArray` | `byte[] ToByteArray()` | Writes the shar archive to a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the shar archive to a stream. | - -### Namespace `FileFormat.Slf` - -[`SlfEntry`](#slfentry) · [`SlfFormatDescriptor`](#slfformatdescriptor) · [`SlfReader`](#slfreader) · [`SlfWriter`](#slfwriter) - -#### `SlfEntry` - -Represents one active entry inside a Sir-Tech SLF library (Jagged Alliance 2). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SlfEntry` | `SlfEntry()` | | -| `LastModified` | `DateTime LastModified { get; init; }` | Gets the entry's last-modified timestamp as decoded from the on-disk Windows FILETIME. | -| `Name` | `string Name { get; init; }` | Gets the entry path relative to the archive's `LibPath` (uses backslashes, e.g. `"sti\\bigicon.sti"`). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry's payload from the start of the SLF stream. | -| `Size` | `long Size { get; init; }` | Gets the entry payload size in bytes. SLF stores payloads uncompressed, so this is the on-disk size. | - -#### `SlfFormatDescriptor` - -Sir-Tech SLF library archive (Jagged Alliance 2). References: `https://github.com/ja2-stracciatella/ja2-stracciatella` — JA2 Stracciatella — open Jagged Alliance 2 engine; its SLF reader is the open referenceSir-Tech's library format; no official spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SlfFormatDescriptor` | `SlfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the SLF archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the SLF archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `SlfReader` - -Reads entries from a Sir-Tech SLF archive (Jagged Alliance 2 resource library). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SlfReader` | `SlfReader(Stream stream, bool leaveOpen = false)` | Initializes a new `SlfReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the active (non-tombstoned) entries in the archive. | -| `LibName` | `string LibName { get; }` | Gets the friendly library name embedded in the SLF header (may be empty). | -| `LibPath` | `string LibPath { get; }` | Gets the virtual path prefix that JA2 mounts entries under (e.g. `"BinaryData\\"`); may be empty. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(SlfEntry entry)` | Extracts the raw payload for an entry. | - -#### `SlfWriter` - -Creates a Sir-Tech SLF library archive (Jagged Alliance 2 resource format). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SlfWriter` | `SlfWriter(Stream stream, bool leaveOpen = false, string libName = "", string libPath = "")` | Initializes a new `SlfWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Serializes the SLF library to the destination stream. | - -### Namespace `FileFormat.Snap` - -[`SnapFormatDescriptor`](#snapformatdescriptor) · [`SnapWriter`](#snapwriter) - -#### `SnapFormatDescriptor` - -Descriptor for Canonical snap packages. A `.snap` file is a SquashFS v4 image whose root contains `meta/snap.yaml`. The descriptor parses that manifest to surface identity metadata in a synthetic `metadata.ini` entry and then exposes every SquashFS entry verbatim under its original path. References: `https://snapcraft.io/docs` — snapcraft documentation — snap package anatomy (SquashFS + meta/snap.yaml)`https://docs.kernel.org/filesystems/squashfs.html` — kernel SquashFS documentation — the container filesystem`https://en.wikipedia.org/wiki/Snap_(software)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SnapFormatDescriptor` | `SnapFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Capabilities supported by this descriptor. | -| `Category` | `FormatCategory Category { get; }` | This format describes an archive container. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | Compound extensions are not used by this format. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Preferred extension. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Human-readable name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Extensions recognised as Snap packages. | -| `Family` | `AlgorithmFamily Family { get; }` | Algorithmic family. | -| `Id` | `string Id { get; }` | Unique format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | No magic bytes are advertised here even though the SquashFS `hsqs` signature is present: detection is extension-based to avoid first-match conflicts with the generic SquashFS descriptor. | -| `Methods` | `IReadOnlyList Methods { get; }` | Compression methods are whatever the embedded SquashFS uses. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a TAR-compound format. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM create — produces a fresh Snap package (SquashFS image) at `output` containing `inputs` plus a synthesised `meta/snap.yaml` when none is supplied. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | Extracts SquashFS contents to `outputDir` and also emits `metadata.ini` when no explicit filter is supplied or when the filter explicitly names it. | -| `List` | `List List(Stream stream, string password)` | Lists a synthetic `metadata.ini` entry derived from `meta/snap.yaml`, followed by every entry inside the SquashFS image. | - -#### `SnapWriter` - -WORM writer that produces a Snap package by wrapping a fresh SquashFS v4 image holding the application payload. Every input becomes a file in the SquashFS at its archive name. When the inputs do not already include `meta/snap.yaml`, a minimal manifest is synthesised so the resulting archive is structurally a Snap and not just a generic SquashFS. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultName` | `const string DefaultName` | Default snap name used when no manifest is provided. | -| `DefaultSummary` | `const string DefaultSummary` | Default summary used when no manifest is provided. | -| `DefaultVersion` | `const string DefaultVersion` | Default snap version used when no manifest is provided. | -| `Write` | `static void Write(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Writes a Snap-shaped SquashFS image to `output`. | - -### Namespace `FileFormat.Snappy` - -[`SnappyFormatDescriptor`](#snappyformatdescriptor) · [`SnappyFrameReader`](#snappyframereader) · [`SnappyFrameWriter`](#snappyframewriter) - -#### `SnappyFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SnappyFormatDescriptor` | `SnappyFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `SnappyFrameReader` - -Reads data from the Snappy framing format (streams). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SnappyFrameReader` | `SnappyFrameReader(Stream input)` | Initializes a new `SnappyFrameReader`. | -| `Read` | `byte[] Read()` | Reads and decompresses the entire Snappy framing stream. | - -#### `SnappyFrameWriter` - -Writes data in the Snappy framing format (streams). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SnappyFrameWriter` | `SnappyFrameWriter(Stream output)` | Initializes a new `SnappyFrameWriter`. | -| `Write` | `void Write(ReadOnlySpan data)` | Writes data as a Snappy framing stream. | - -### Namespace `FileFormat.Spark` - -[`SparkEntry`](#sparkentry) · [`SparkFormatDescriptor`](#sparkformatdescriptor) · [`SparkModifier`](#sparkmodifier) · [`SparkReader`](#sparkreader) · [`SparkWriter`](#sparkwriter) - -#### `SparkEntry` - -Represents the metadata for a single entry in a Spark archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SparkEntry` | `SparkEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | Gets or sets the compressed size in bytes. | -| `Crc16` | `ushort Crc16 { get; init; }` | Gets or sets the CRC-16 of the uncompressed data. | -| `ExecAddress` | `uint ExecAddress { get; init; }` | Gets or sets the RISC OS execution address. | -| `FileAttributes` | `uint FileAttributes { get; init; }` | Gets or sets the RISC OS file attributes. | -| `FileName` | `string FileName { get; init; }` | Gets or sets the filename (up to 13 chars for standard ARC, longer for Spark extensions). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets or sets whether this entry represents a directory. | -| `LastModified` | `DateTime LastModified { get; init; }` | Gets or sets the last-modified timestamp. | -| `LoadAddress` | `uint LoadAddress { get; init; }` | Gets or sets the RISC OS load address. For typed files, bits 8-19 contain the file type and bits 20-31 are 0xFFF. | -| `Method` | `byte Method { get; init; }` | Gets or sets the compression method byte. | -| `OriginalSize` | `uint OriginalSize { get; init; }` | Gets or sets the uncompressed (original) size in bytes. | -| `RiscOsFileType` | `int? RiscOsFileType { get; }` | Gets the RISC OS file type extracted from the load address, or `null` if the load address does not encode a file type (top 12 bits must be 0xFFF). | - -#### `SparkFormatDescriptor` - -RISC OS Spark archive (Acorn/ARM) — ARC-compatible layout with RISC OS file-type extensions. References: David Pilling's Spark / SparkFS (davidpilling.com) — the defining RISC OS archivernspark — portable open unarchiver for Spark/ARC archives`https://en.wikipedia.org/wiki/ARC_(file_format)` — Wikipedia — the base ARC format Spark extends - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SparkFormatDescriptor` | `SparkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Spark archive. Uses `SparkModifier` — Add appends Stored before the EOA marker; Remove walks the top-level entry chain and shifts trailing bytes (no central directory). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the Spark archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the Spark archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `SparkModifier`. | - -#### `SparkModifier` - -Random-access in-place modifier for RISC OS Spark / ARC archives. Spark archives are a chain of variable-size entry blocks terminated by an end-of-archive marker (0x1A 0x00). Add appends a new Stored (method 0x02) entry just before the EOA marker; Remove walks the top-level entry chain, locates the target, and shifts trailing bytes forward to compact (no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream spark, string name, byte[] data)` | Appends a Stored (method 0x02) entry to the archive. Walks the existing entry chain to find the EOA marker, writes a new entry block in its place, then re-writes the EOA marker. I/O cost is one full sequential entry walk plus the new entry's bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream spark, string name, bool wipeData = true)` | Removes the named top-level entry. Returns true if found. Walks the chain to locate the entry, then shifts trailing bytes forward to compact. | - -#### `SparkReader` - -Reads entries from a RISC OS Spark archive (.spk). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SparkReader` | `SparkReader(Stream stream, bool leaveOpen = false)` | Initializes a new `SparkReader` from a stream containing Spark archive data. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive. The archive is parsed on first access. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(SparkEntry entry)` | Extracts and decompresses the data for the specified entry. | - -#### `SparkWriter` - -Creates a RISC OS Spark archive (.spk) by writing entries sequentially to a stream. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SparkWriter` | `SparkWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `SparkWriter`. | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? lastModified = null, uint loadAddress = 0, uint execAddress = 0, uint fileAttributes = 0)` | Adds a file entry to the archive using the Stored method. | -| `BeginDirectory` | `void BeginDirectory(string name, DateTime? lastModified = null, uint loadAddress = 0, uint execAddress = 0, uint fileAttributes = 0)` | Begins a directory entry in the archive. Subsequent calls to `AddFile` and `BeginDirectory` will add entries inside this directory until `EndDirectory` is called. | -| `Dispose` | `void Dispose()` | | -| `EndDirectory` | `void EndDirectory()` | Ends the current directory by writing an end-of-directory marker (method 0x80). | - -### Namespace `FileFormat.SplitFile` - -[`SplitFileEntry`](#splitfileentry) · [`SplitFileFormatDescriptor`](#splitfileformatdescriptor) · [`SplitFileReader`](#splitfilereader) · [`SplitFileWriter`](#splitfilewriter) - -#### `SplitFileEntry` - -Represents the single logical file assembled from split parts. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SplitFileEntry` | `SplitFileEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `PartCount` | `int PartCount { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `SplitFileFormatDescriptor` - -Split-file volume set (.001/.002 ...) — raw sequential byte slices joined back into one file. References: de-facto convention (no formal spec): headerless sequential byte splits, popularized by HJSplit and Total Commander7-Zip and WinRAR use the same numeric-suffix naming for raw split volumes - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SplitFileFormatDescriptor` | `SplitFileFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `SplitFileReader` - -Reads and joins split file parts (.001, .002, ...) into a single logical file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SplitFileReader` | `SplitFileReader(string anyPartPath)` | Opens a split file set from any one of the parts (typically .001). | -| `SplitFileReader` | `SplitFileReader(string baseName, Stream[] partStreams)` | Creates a `SplitFileReader` from pre-ordered part streams. | -| `Entry` | `SplitFileEntry Entry { get; }` | | -| `ExtractTo` | `void ExtractTo(Stream output)` | Writes the joined file to the specified output stream. | -| `Extract` | `byte[] Extract()` | Extracts (joins) all parts into a single byte array. | - -#### `SplitFileWriter` - -Splits a file into numbered parts (.001, .002, ...). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Split` | `static int Split(Stream input, string outputDir, string baseName, long partSize)` | Splits the input stream into parts of the given size. | - -### Namespace `FileFormat.Squeeze` - -[`SqueezeFormatDescriptor`](#squeezeformatdescriptor) · [`SqueezeStream`](#squeezestream) - -#### `SqueezeFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqueezeFormatDescriptor` | `SqueezeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `SqueezeStream` - -Provides static methods for reading and writing the CP/M Squeeze (.sqz / .??q) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output, string originalFilename = "")` | Compresses data from `input` and writes a Squeeze-format stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a Squeeze-format stream from `input` and writes the result to `output`. | - -### Namespace `FileFormat.Sqx` - -[`SqxEntry`](#sqxentry) · [`SqxFormatDescriptor`](#sqxformatdescriptor) · [`SqxReader`](#sqxreader) · [`SqxWriter`](#sqxwriter) - -#### `SqxEntry` - -Represents a file entry in an SQX archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxEntry` | `SqxEntry()` | | -| `ArchiveVersion` | `byte ArchiveVersion { get; set; }` | Gets or sets the archive version required. | -| `Attributes` | `uint Attributes { get; set; }` | Gets or sets the file attributes. | -| `CompFlags` | `byte CompFlags { get; set; }` | Gets or sets the compressor flags byte. | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `Crc32` | `uint Crc32 { get; set; }` | Gets or sets the CRC-32 of the original data. | -| `DictionarySize` | `int DictionarySize { get; }` | Gets the dictionary size for this entry. | -| `ExtraCompFlags` | `ushort ExtraCompFlags { get; set; }` | Gets or sets the extra compressor flags (BCJ/delta). | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name. | -| `Flags` | `ushort Flags { get; set; }` | Gets or sets the block flags. | -| `IsEncrypted` | `bool IsEncrypted { get; }` | Gets whether this entry is encrypted. | -| `IsSolid` | `bool IsSolid { get; }` | Gets whether this entry uses solid compression. | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last modification time. | -| `Method` | `byte Method { get; set; }` | Gets or sets the compression method. | -| `OriginalSize` | `long OriginalSize { get; set; }` | Gets or sets the original (uncompressed) size in bytes. | - -#### `SqxFormatDescriptor` - -SQX archive (SpeedProject Squeez / SpeedCommander) with multiple compression algorithms. References: SpeedProject (www.speedproject.de) — vendor of Squeez/SpeedCommander; published the "SQX Archive Format" description`https://en.wikipedia.org/wiki/SQX` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxFormatDescriptor` | `SqxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the SQX archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the SQX archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `SqxReader` - -Reads entries from an SQX archive (supports V11 and V20 formats). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxReader` | `SqxReader(Stream stream, bool leaveOpen = false, string password = null)` | Initializes a new `SqxReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the archive. | -| `HasRecoveryRecord` | `bool HasRecoveryRecord { get; }` | Gets whether the archive has a recovery record. | -| `IsSolid` | `bool IsSolid { get; }` | Gets whether this is a solid archive. | -| `Dispose` | `void Dispose()` | | -| `ExtractAll` | `byte[][] ExtractAll()` | Extracts all entries in order. Required for solid archives. | -| `ExtractEntry` | `byte[] ExtractEntry(SqxEntry entry)` | Extracts the data for an entry. | -| `VerifyRecoveryRecord` | `bool VerifyRecoveryRecord()` | Verifies the recovery record against the archive data. | - -#### `SqxWriter` - -Creates SQX archives matching the real SQX format specification. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SqxWriter` | `SqxWriter(string password = null, byte method = 1, bool solid = false, int recoveryPercent = 0, int dictSize = 32768)` | Initializes a new `SqxWriter`. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, string password = null)` | Creates an SQX archive split into multiple volumes. | -| `ToArray` | `byte[] ToArray()` | Creates an SQX archive as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the archive to a stream. | - -### Namespace `FileFormat.Stl` - -[`StlFormatDescriptor`](#stlformatdescriptor) - -#### `StlFormatDescriptor` - -STL (stereolithography) 3D model. Two variants: ASCII — starts with `solid \n` then `facet normal`…/`endfacet` blocks.Binary — 80-byte header + `uint32 LE` triangle count + 50 bytes per triangle (12-byte normal + 3×12-byte vertices + 2-byte attribute). Binary detection: `filesize == 84 + 50 * triCount`. ASCII detection: leading `solid ` plus `facet normal` in the first ~1 KB (needed because some malformed binary files begin with the text "solid"). Surfaces `metadata.ini` (variant, triangle count, object name, bounding box) and `triangles.bin` (raw binary facet block — for ASCII this is reconstructed from parsed vertices). References: 3D Systems, "StereoLithography Interface Specification" (1988) — the original definition`https://en.wikipedia.org/wiki/STL_(file_format)` — Wikipedia — documents both ASCII and binary variants - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StlFormatDescriptor` | `StlFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | Read-only archive capabilities. | -| `Category` | `FormatCategory Category { get; }` | Archive category — surfaces synthesised body entries. | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | No compound extensions. | -| `DefaultExtension` | `string DefaultExtension { get; }` | Default extension. | -| `Description` | `string Description { get; }` | Short description. | -| `DisplayName` | `string DisplayName { get; }` | Display name. | -| `Extensions` | `IReadOnlyList Extensions { get; }` | Known extensions. | -| `Family` | `AlgorithmFamily Family { get; }` | Archive family. | -| `Id` | `string Id { get; }` | Format identifier. | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | Binary STL's 80-byte header is user-provided and has no magic; extension-primary. | -| `Methods` | `IReadOnlyList Methods { get; }` | Stored only. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | Not a tar compound format. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Each entry's decoded byte buffer is produced by `BuildEntries` and wrapped in a `BoundedEntryStream` sized to its logical length. | - -### Namespace `FileFormat.StuffIt` - -[`StuffItEntry`](#stuffitentry) · [`StuffItFormatDescriptor`](#stuffitformatdescriptor) · [`StuffItReader`](#stuffitreader) · [`StuffItWriter`](#stuffitwriter) - -#### `StuffItEntry` - -Represents a single file entry in a StuffIt (SIT) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItEntry` | `StuffItEntry()` | | -| `CompressedDataSize` | `long CompressedDataSize { get; set; }` | Gets or sets the compressed size of the data fork in bytes. | -| `CompressedResourceSize` | `long CompressedResourceSize { get; set; }` | Gets or sets the compressed size of the resource fork in bytes. | -| `DataForkSize` | `long DataForkSize { get; set; }` | Gets or sets the uncompressed size of the data fork in bytes. | -| `DataMethod` | `int DataMethod { get; set; }` | Gets or sets the compression method code for the data fork. | -| `FileCreator` | `string FileCreator { get; set; }` | Gets or sets the Mac four-character file creator code. | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name as stored in the archive (up to 63 characters). | -| `FileType` | `string FileType { get; set; }` | Gets or sets the Mac four-character file type code (e.g. "TEXT"). | -| `IsDirectory` | `bool IsDirectory { get; }` | StuffIt classic archives do not support directory entries. | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last modification date/time of the file. | -| `ResourceForkSize` | `long ResourceForkSize { get; set; }` | Gets or sets the uncompressed size of the resource fork in bytes. | -| `ResourceMethod` | `int ResourceMethod { get; set; }` | Gets or sets the compression method code for the resource fork. | - -#### `StuffItFormatDescriptor` - -Macintosh StuffIt (SIT) archive — classic Mac compression with resource/data fork entries. References: `https://github.com/MacPaw/XADMaster` — XADMaster (The Unarchiver) — open StuffIt decoder, the de-facto format reference`https://en.wikipedia.org/wiki/StuffIt` — Wikipedia overviewAladdin Systems StuffIt — proprietary; no official spec published - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItFormatDescriptor` | `StuffItFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the StuffIt archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the StuffIt archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single StuffIt entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the data-fork bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's data-fork size. | - -#### `StuffItReader` - -Reads entries from a StuffIt (SIT) classic archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItReader` | `StuffItReader(Stream stream, bool leaveOpen = false)` | Opens a StuffIt archive from the given stream and parses the entry directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries found in the archive. | -| `Dispose` | `void Dispose()` | | -| `ExtractResourceFork` | `byte[] ExtractResourceFork(StuffItEntry entry)` | Extracts and decompresses the resource fork of the specified entry. | -| `Extract` | `byte[] Extract(StuffItEntry entry)` | Extracts and decompresses the data fork of the specified entry. | - -#### `StuffItWriter` - -Creates a StuffIt (SIT) classic archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItWriter` | `StuffItWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `StuffItWriter`. | -| `AddFileWithResourceFork` | `void AddFileWithResourceFork(string fileName, byte[] dataFork, byte[] resourceFork, string fileType = "TEXT", string fileCreator = "CWIE", DateTime? lastModified = null)` | Adds a file entry to the archive with both data and resource forks. | -| `AddFile` | `void AddFile(string fileName, byte[] data, string fileType = "TEXT", string fileCreator = "CWIE", DateTime? lastModified = null)` | Adds a file entry to the archive with an empty resource fork. | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.StuffItX` - -[`StuffItXEntry`](#stuffitxentry) · [`StuffItXFormatDescriptor`](#stuffitxformatdescriptor) · [`StuffItXReader`](#stuffitxreader) · [`StuffItXWriter`](#stuffitxwriter) - -#### `StuffItXEntry` - -Represents a single entry in a StuffIt X (.sitx) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItXEntry` | `StuffItXEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Gets the compressed size of the entry data in bytes. | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path of the entry within the archive (slash-separated). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets a value indicating whether this entry is a directory. | -| `Method` | `string Method { get; init; }` | Gets a display name for the compression method used. | -| `Name` | `string Name { get; init; }` | Gets the bare file or directory name. | -| `OriginalSize` | `long OriginalSize { get; init; }` | Gets the uncompressed size of the entry data in bytes. | - -#### `StuffItXFormatDescriptor` - -StuffIt X (.sitx) archive (Aladdin/Smith Micro) — proprietary element-stream container. References: `https://github.com/MacPaw/XADMaster` — XADMaster (The Unarchiver) — partial open StuffIt X decoder`https://en.wikipedia.org/wiki/StuffIt` — Wikipedia — covers StuffIt Xproprietary format; the element-stream codecs have no public specification - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItXFormatDescriptor` | `StuffItXFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single StuffIt X entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's original size. | - -#### `StuffItXReader` - -Reads entries from a StuffIt X (.sitx) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItXReader` | `StuffItXReader(Stream stream, bool leaveOpen = false)` | Opens a StuffIt X archive from the given stream and parses its element catalog. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the list of entries discovered during parsing. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(StuffItXEntry entry)` | Extracts and decompresses the data for the specified entry. | - -#### `StuffItXWriter` - -Writes a minimal StuffIt X header. Full element-stream emission with P2 varint encoding and element catalog is not implemented — the reader's element parser is complex and the format is proprietary. This writer produces a valid "StuffIt!" magic envelope that passes detection; file data is embedded but not recoverable through the reader's element parser. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StuffItXWriter` | `StuffItXWriter()` | | -| `WriteTo` | `void WriteTo(Stream output, byte[] embeddedData = null)` | | - -### Namespace `FileFormat.Sup` - -[`SupFormatDescriptor`](#supformatdescriptor) · [`SupReader`](#supreader) · [`SupReader.Epoch`](#supreaderepoch) · [`SupReader.Segment`](#supreadersegment) · [`SupReader.Stream`](#supreaderstream) - -#### `SupFormatDescriptor` - -Pseudo-archive descriptor for Blu-ray PGS (`.sup`) subtitle bitmap streams. Each subtitle epoch (PCS through END inclusive) is exposed as one entry, plus a `metadata.ini` describing the overall stream. References: `https://github.com/mjuhasz/BDSup2Sub` — BDSup2Sub — canonical open tool for PGS (.sup) subtitle streamsPGS is defined in the Blu-ray Disc Read-Only Format specifications (BDA, not public); segment layout community-documented - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SupFormatDescriptor` | `SupFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single SUP entry as a bounded read-only stream. Each subtitle epoch's pre-decoded byte buffer is wrapped in a `BoundedEntryStream` sized to its logical length. | - -#### `SupReader` - -Reader for Blu-ray PGS (Presentation Graphic Stream) subtitle bitmap streams (`.sup`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SupReader` | `SupReader()` | | -| `SegEnd` | `const byte SegEnd` | | -| `SegObjectDefinition` | `const byte SegObjectDefinition` | | -| `SegPaletteDefinition` | `const byte SegPaletteDefinition` | | -| `SegPresentationComposition` | `const byte SegPresentationComposition` | | -| `SegWindowDefinition` | `const byte SegWindowDefinition` | | -| `Read` | `static Stream Read(ReadOnlySpan data)` | Parses an entire `.sup` stream. Stops at first malformed segment without throwing, so partially-recovered files still yield their leading well-formed epochs. | - -#### `SupReader.Epoch` - -A subtitle "epoch" — a PCS segment through the next END segment, inclusive. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Epoch` | `Epoch(uint StartPtsRaw, uint EndPtsRaw, int SegmentCount, byte[] RawBytes)` | A subtitle "epoch" — a PCS segment through the next END segment, inclusive. | -| `EndPtsRaw` | `uint EndPtsRaw { get; init; }` | | -| `RawBytes` | `byte[] RawBytes { get; init; }` | | -| `SegmentCount` | `int SegmentCount { get; init; }` | | -| `StartPtsRaw` | `uint StartPtsRaw { get; init; }` | | - -#### `SupReader.Segment` - -A single PGS segment: header fields plus the raw body bytes. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Segment` | `Segment(uint PtsRaw, uint DtsRaw, byte Type, byte[] Body, int FileOffset)` | A single PGS segment: header fields plus the raw body bytes. | -| `Body` | `byte[] Body { get; init; }` | | -| `DtsRaw` | `uint DtsRaw { get; init; }` | | -| `FileOffset` | `int FileOffset { get; init; }` | | -| `PtsRaw` | `uint PtsRaw { get; init; }` | | -| `Type` | `byte Type { get; init; }` | | - -#### `SupReader.Stream` - -The full parsed file: every segment plus the derived epoch grouping. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Stream` | `Stream(IReadOnlyList Segments, IReadOnlyList Epochs)` | The full parsed file: every segment plus the derived epoch grouping. | -| `Epochs` | `IReadOnlyList Epochs { get; init; }` | | -| `Segments` | `IReadOnlyList Segments { get; init; }` | | - -### Namespace `FileFormat.Swf` - -[`SwfFormatDescriptor`](#swfformatdescriptor) · [`SwfStream`](#swfstream) - -#### `SwfFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SwfFormatDescriptor` | `SwfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `SwfStream` - -Provides static methods for reading and writing SWF (Adobe Flash) files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses an uncompressed SWF from `input` to a CWS (zlib-compressed) SWF written to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an SWF file from `input` and writes the uncompressed result to `output`. | - -### Namespace `FileFormat.Swm` - -[`SwmFormatDescriptor`](#swmformatdescriptor) - -#### `SwmFormatDescriptor` - -Descriptor for a Split WIM (.swm / .swmN) volume — a WIM file that has been chopped into N pieces for size-limited media (DVD, FAT32, etc.). References: `https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/wim-and-esd-windows-image-files-overview` — Microsoft's WIM/ESD overview (DISM `/Split-Image` produces .swm sets)Microsoft "Windows Imaging File Format (WIM)" whitepaper — defines `part_number`/`total_parts` in the shared header`https://wimlib.net` — open-source implementation with full split-WIM support - -Implements `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SwmFormatDescriptor` | `SwmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Each entry's decoded byte buffer is produced by `BuildEntries` and wrapped in a `BoundedEntryStream` sized to its logical length. | - -### Namespace `FileFormat.Szdd` - -[`SzCompressFormatDescriptor`](#szcompressformatdescriptor) · [`SzddFormatDescriptor`](#szddformatdescriptor) · [`SzddStream`](#szddstream) - -#### `SzCompressFormatDescriptor` - -The older "SZ " Microsoft COMPRESS variant (pre-SZDD; QBasic-era `COMPRESS.EXE`). Magic `53 5A 20 88 F0 27 33 D1`, a 12-byte header (8-byte magic + little-endian u32 uncompressed length) and the same 4096-byte ring LZSS body as `SzddFormatDescriptor`. Neither the legacy SZDD reader nor 7-Zip handles this variant; here it is fully read + write (`Compress` emits the "SZ " header, `Decompress` auto-detects either variant). - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SzCompressFormatDescriptor` | `SzCompressFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `SzddFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SzddFormatDescriptor` | `SzddFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `SzddStream` - -Reader and writer for the Microsoft SZDD / COMPRESS.EXE file format. SZDD uses a custom LZSS variant with a 4096-byte ring buffer, 8-item flag bytes, and packed offset/length pairs encoded LSB-first. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressQBasic` | `static byte[] CompressQBasic(ReadOnlySpan data)` | Compresses `data` in the older "SZ " (QBasic) COMPRESS variant and returns the result. The body is the same LZSS stream as SZDD, wrapped in the 12-byte "SZ " header (8-byte magic + little-endian u32 uncompressed length). Round-trips through `Decompress`. | -| `CompressQBasic` | `static void CompressQBasic(Stream input, Stream output)` | Stream overload of `CompressQBasic`. | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, char missingChar = '_')` | Compresses `data` in SZDD format and returns the result as a new byte array. | -| `Compress` | `static void Compress(Stream input, Stream output, char missingChar = '_')` | Compresses `input` in SZDD format and writes the result to `output`. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses an SZDD-encoded byte array and returns the raw data. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an SZDD-encoded stream and writes the raw data to `output`. | -| `GetMissingChar` | `static char GetMissingChar(Stream input)` | Returns the "missing character" stored in the SZDD header — the last character of the original filename extension before it was replaced with `'_'`. | - -### Namespace `FileFormat.Tar` - -[`TarEntry`](#tarentry) · [`TarFormatDescriptor`](#tarformatdescriptor) · [`TarHeaderFormat`](#tarheaderformat) · [`TarLayoutMap`](#tarlayoutmap) · [`TarModifier`](#tarmodifier) · [`TarReader`](#tarreader) · [`TarWriter`](#tarwriter) - -#### `TarEntry` - -Represents a single entry in a TAR archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TarEntry` | `TarEntry()` | | -| `Gid` | `int Gid { get; set; }` | Gets or sets the group ID of the owner. | -| `GroupName` | `string GroupName { get; set; }` | Gets or sets the group name of the owner. | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets whether this entry represents a directory. | -| `IsFile` | `bool IsFile { get; }` | Gets whether this entry represents a regular file. | -| `LinkName` | `string LinkName { get; set; }` | Gets or sets the link target name for hard or symbolic links. | -| `Mode` | `int Mode { get; set; }` | Gets or sets the file mode (Unix permissions). | -| `ModifiedTime` | `DateTimeOffset ModifiedTime { get; set; }` | Gets or sets the last modification time. | -| `Name` | `string Name { get; set; }` | Gets or sets the file name (including path within the archive). | -| `Offset` | `long Offset { get; set; }` | Gets or sets the byte offset within the original file for multi-volume entries. | -| `RealSize` | `long RealSize { get; set; }` | Gets or sets the real size of the file for multi-volume continuation entries. | -| `Size` | `long Size { get; set; }` | Gets or sets the uncompressed size in bytes. | -| `TypeFlag` | `byte TypeFlag { get; set; }` | Gets or sets the type flag indicating the entry type. | -| `Uid` | `int Uid { get; set; }` | Gets or sets the user ID of the owner. | -| `UserName` | `string UserName { get; set; }` | Gets or sets the user name of the owner. | - -#### `TarFormatDescriptor` - -Unix tape archive (tar) — 512-byte header blocks; ustar/GNU/pax variants; container only, no compression. References: `https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html` — POSIX pax — defines the ustar header and pax extended headers`https://www.gnu.org/software/tar/manual/` — GNU tar manual — GNU extensions (long names, sparse files)`https://en.wikipedia.org/wiki/Tar_(computing)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFormatDescriptor`, `IFormatOptionsSchema`, `IFormatValidator`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TarFormatDescriptor` | `TarFormatDescriptor()` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | TAR has no fixed media geometry, so the only canonical size is the archive's minimal terminated length: every live entry plus the two-block zero terminator, rounded up to the configured blocking factor. | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing TAR archive. Uses `TarModifier` for true random-access I/O — Add is O(touched bytes) (append before terminator); Remove is O(image-size-after-target) because TAR has no central directory and trailing entries must be shifted. | -| `CreateFromStreams` | `void CreateFromStreams(Stream target, IEnumerable inputs, FormatCreateOptions options)` | Large-file-safe streaming variant of `Create`. TAR encodes each entry's size in its header before any payload byte, so the pre-known `Size` lets the writer emit the header and then copy the payload in 64 KB chunks via `AddStreamingEntry` — peak memory is bounded by the copy buffer regardless of entry size. Output is byte-identical to `Create` for the same inputs. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the TAR archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the TAR archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. Routed through the bounded `OpenEntry` so the per-entry isolation contract holds uniformly across descriptors. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single TAR entry as a read-only `Stream` bounded to its data size. TAR is positional — each entry's data starts at a known offset followed by 512-byte block padding. The `BoundedEntryStream` wrapper guarantees the padding and next entry's header bytes are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing TAR archive. Uses `TarModifier` for in-place compaction. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | Drops any bytes trailing the end-of-archive marker (left behind by truncating writers, tape padding, or external concatenation) by walking the entries and re-terminating at the minimal length. File data is copied through byte-identically — no header is rewritten, so the output is the exact prefix of the input up to and including the terminator (padded to the blocking factor). When the input already has no trailing junk the output is byte-identical to the input. | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the TAR archive: intra-block padding after each entry's data (the 512-byte alignment slack), and any junk trailing the two-block end-of-archive marker. Header blocks, file data and the terminator are live and preserved, so every entry still extracts byte-identically. Cluster-tip wiping is N/A — the layout map already classifies per-entry alignment padding as Free. | - -#### `TarHeaderFormat` - -Creates a TAR archive by writing entries sequentially. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Ustar` | `0` | POSIX 1003.1-1988 ustar. Long names fall back to GNU LongName when needed. | -| `Gnu` | `1` | GNU extensions. Long names use the GNU @LongLink convention. | -| `Pax` | `2` | POSIX 1003.1-2001 PAX. Long names + large sizes use PAX extended headers. | - -#### `TarLayoutMap` - -Walks a TAR archive sequentially and emits the byte-level layout: each 512-byte header block as MetadataReserved, each file's data (padded to 512) as Used, and the trailing 2x512 zero blocks as MetadataReserved. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `TarModifier` - -Random-access in-place modifier for TAR archives. Add appends a new entry just before the trailing zero blocks — touches only the new entry's bytes plus the (small) terminator. Remove walks the header chain to locate the target, then shifts trailing bytes forward to close the gap (necessary because TAR has no central directory). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream tar, string name, byte[] data)` | Appends a regular file entry. Walks the existing header chain to find the trailing zero blocks, writes the new header + data + zero blocks in their place, and truncates to the new length. | -| `RemoveFile` | `static bool RemoveFile(Stream tar, string name, bool wipeData = true)` | Removes the named entry. Returns true if found. The trailing portion of the file is shifted forward to close the gap (TAR has no central directory; readers walk headers sequentially, so we must compact). | - -#### `TarReader` - -Reads entries sequentially from a TAR archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TarReader` | `TarReader(Stream stream, bool leaveOpen = false)` | Initializes a new `TarReader` from a stream. | -| `CopyEntryDataTo` | `void CopyEntryDataTo(Stream destination)` | Copies the current entry's data straight to `destination` without materialising it, then consumes the block padding. Required for entries larger than a byte[] can hold. | -| `Dispose` | `void Dispose()` | | -| `GetEntryStream` | `Stream GetEntryStream()` | Returns a stream for reading the data of the current entry. | -| `GetNextEntry` | `TarEntry GetNextEntry()` | Reads the next entry from the archive. | -| `Skip` | `void Skip()` | Skips past the data of the current entry. | - -#### `TarWriter` - -Writes a TAR archive to a destination stream. Defaults to the `Ustar` dialect; switchable to GNU/PAX via the constructor for long-name or large-size scenarios. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TarWriter` | `TarWriter(Stream stream, bool leaveOpen = false, TarHeaderFormat format = 0, int blockingFactor = 1)` | Initializes a new `TarWriter`. | -| `AddEntry` | `void AddEntry(TarEntry entry, ReadOnlySpan data)` | Adds an entry to the archive with data from a byte span. | -| `AddEntry` | `void AddEntry(TarEntry entry, Stream data = null)` | Adds an entry to the archive with data from a stream. | -| `AddStreamingEntry` | `void AddStreamingEntry(TarEntry entry, long size, Stream data)` | Adds an entry whose payload is streamed from `data` in bounded chunks rather than buffered into RAM. The entry's logical `size` must be known up front (TAR encodes it in the header before any payload byte), so this writes the header with the supplied size, then copies exactly `size` bytes from `data` in 64 KB chunks, then the 512-byte padding. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries)` | Creates a TAR archive split into multiple volumes with GNU multi-volume continuation headers. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the end-of-archive marker (two 512-byte zero blocks) and pads the output to a multiple of `blockingFactor * 512` bytes. | - -### Namespace `FileFormat.Tfc` - -[`TfcEntry`](#tfcentry) · [`TfcFormatDescriptor`](#tfcformatdescriptor) · [`TfcReader`](#tfcreader) · [`TfcWriter`](#tfcwriter) - -#### `TfcEntry` - -Represents a single texture mip-level bundle inside a Mass Effect TFC cache. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TfcEntry` | `TfcEntry()` | | -| `BlockSize` | `uint BlockSize { get; init; }` | Nominal block size declared by the bundle (typically 128 KiB). | -| `CompressedSize` | `long CompressedSize { get; init; }` | Sum of per-block compressed sizes, as declared in the bundle's chunk header. | -| `IsCompressed` | `bool IsCompressed { get; init; }` | True when `CompressedSize` differs from `UncompressedSize`; blocks are LZX-compressed. | -| `Name` | `string Name { get; init; }` | Synthetic bundle name (zero-padded, e.g. `bundle_00000.bin`). | -| `Offset` | `long Offset { get; init; }` | Absolute offset of the bundle's chunk header within the TFC stream. | -| `Size` | `long Size { get; init; }` | Total size of the entry's payload in bytes (block-size table + block data). | -| `UncompressedSize` | `long UncompressedSize { get; init; }` | Sum of per-block uncompressed sizes, as declared in the bundle's chunk header. | - -#### `TfcFormatDescriptor` - -Unreal Engine 3 Texture File Cache (TFC) as shipped by Mass Effect — opaque compressed texture bundles. References: `https://github.com/ME3Tweaks/LegendaryExplorer` — Legendary Explorer (ME3Tweaks) — implements Mass Effect TFC handlingUnreal Engine 3 streamed-texture cache; no official spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TfcFormatDescriptor` | `TfcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `TfcReader` - -Reads bundles from a Mass Effect Texture File Cache (.tfc) stream. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TfcReader` | `TfcReader(Stream stream, bool leaveOpen = false)` | Parses bundle headers from `stream`. | -| `Entries` | `IReadOnlyList Entries { get; }` | All bundles discovered while walking the TFC from offset 0. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(TfcEntry entry)` | Reads the bundle's raw payload — the per-block size table followed by all block bytes — into a new buffer. | - -#### `TfcWriter` - -Creates a Mass Effect TFC cache by emitting one stored bundle per added payload. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TfcWriter` | `TfcWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `TfcWriter`. | -| `AddBundle` | `void AddBundle(byte[] uncompressedData, uint blockSize = 131072)` | Queues a stored bundle to be emitted on flush. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes all queued bundles to the stream and marks the writer as finished. | - -### Namespace `FileFormat.Tnef` - -[`TnefEntry`](#tnefentry) · [`TnefFormatDescriptor`](#tnefformatdescriptor) · [`TnefReader`](#tnefreader) · [`TnefWriter`](#tnefwriter) - -#### `TnefEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `TnefEntry` | `TnefEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `TnefFormatDescriptor` - -Microsoft TNEF (winmail.dat) email attachment container. References: [MS-OXTNEF]: Transport Neutral Encapsulation Format (Microsoft Open Specifications, learn.microsoft.com)`https://github.com/Yeraze/ytnef` — ytnef — open TNEF decoder`https://en.wikipedia.org/wiki/Transport_Neutral_Encapsulation_Format` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TnefFormatDescriptor` | `TnefFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the TNEF archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the TNEF archive per the requested mode. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `TnefReader` - -Reads MS-TNEF (Transport Neutral Encapsulation Format) files, commonly known as winmail.dat. Extracts file attachments from the TNEF stream. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TnefReader` | `TnefReader(Stream stream, bool leaveOpen = false)` | | -| `TnefSignature` | `const uint TnefSignature` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Key` | `ushort Key { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(TnefEntry entry)` | | - -#### `TnefWriter` - -Creates MS-TNEF (winmail.dat) files with file attachments. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TnefWriter` | `TnefWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.U8` - -[`U8Constants`](#u8constants) · [`U8Entry`](#u8entry) · [`U8FormatDescriptor`](#u8formatdescriptor) · [`U8Reader`](#u8reader) · [`U8Writer`](#u8writer) - -#### `U8Constants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `DataAlignment` | `const int DataAlignment` | | -| `DefaultFirstNodeOffset` | `const uint DefaultFirstNodeOffset` | | -| `HeaderSize` | `const int HeaderSize` | | -| `MaxNameLength` | `const int MaxNameLength` | | -| `NodeSize` | `const int NodeSize` | | -| `TypeDirectory` | `const byte TypeDirectory` | | -| `TypeFile` | `const byte TypeFile` | | -| `Magic` | `static ReadOnlySpan Magic { get; }` | | - -#### `U8Entry` - -Represents a single entry (file or directory) inside a Nintendo U8 archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `U8Entry` | `U8Entry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets a value indicating whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the full path of this entry, with `/` separators (no leading slash). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of this entry's data inside the archive (files only). | -| `Size` | `long Size { get; init; }` | Gets the size in bytes of this entry's data (files only; 0 for directories). | - -#### `U8FormatDescriptor` - -Nintendo U8 archive (Wii / Wii U / 3DS) — node table + string pool + aligned file data. References: `https://wiibrew.org/wiki/U8_archive` — WiiBrew wiki — community U8 archive documentationWiimms SZS Tools (wszst) — maintained implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `U8FormatDescriptor` | `U8FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the U8 archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the U8 archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `U8Reader` - -Reads a Nintendo U8 archive (Wii / Wii U / 3DS / Switch). All multi-byte integers are big-endian. The directory tree is encoded depth-first using parent indices and exclusive end-index markers — see `WalkTree`. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `U8Reader` | `U8Reader(Stream stream, bool leaveOpen = false)` | Initializes a new `U8Reader` from a stream. | -| `DataOffset` | `uint DataOffset { get; }` | Gets the offset where file data starts, as declared in the header. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the archive, with full `/`-separated paths. | -| `FirstNodeOffset` | `uint FirstNodeOffset { get; }` | Gets the offset of the first node, as declared in the header. | -| `NodeTableSize` | `uint NodeTableSize { get; }` | Gets the combined size of node table + string table, as declared in the header. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(U8Entry entry)` | Extracts the raw bytes for a file entry. | - -#### `U8Writer` - -Creates a Nintendo U8 archive. Caller adds files by forward-slash-separated path plus payload bytes; intermediate directories are inferred. `Finish` builds the depth-first node table, packs the string table, and lays out file data. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `U8Writer` | `U8Writer(Stream stream, bool leaveOpen = false)` | Initializes a new `U8Writer`. | -| `AddEntry` | `void AddEntry(string path, byte[] data)` | Adds a file at `path` (using `/` separators). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalizes and writes the archive. | - -### Namespace `FileFormat.Uharc` - -[`UharcEntry`](#uharcentry) · [`UharcFormatDescriptor`](#uharcformatdescriptor) · [`UharcReader`](#uharcreader) · [`UharcWriter`](#uharcwriter) - -#### `UharcEntry` - -Represents a single entry in a UHARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UharcEntry` | `UharcEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | Gets the compressed size in bytes. | -| `Crc32` | `uint Crc32 { get; init; }` | Gets the CRC-32 (IEEE polynomial) of the uncompressed data. | -| `FileName` | `string FileName { get; init; }` | Gets the filename stored in the archive (UTF-8, '/' separators). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `LastModified` | `DateTime LastModified { get; init; }` | Gets the last-modification date/time. | -| `Method` | `byte Method { get; init; }` | Gets the compression method (0 = LZP, 255 = Store). | -| `OriginalSize` | `uint OriginalSize { get; init; }` | Gets the uncompressed size in bytes. | - -#### `UharcFormatDescriptor` - -UHARC high-compression archive (PPM/LZP/delta) by Uwe Herklotz. References: UHARC by Uwe Herklotz — closed-source archiver; the bundled UHARC documentation is the only official descriptionno public format specification; container layout reverse-engineered from the DOS/Win32 binaries - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UharcFormatDescriptor` | `UharcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the UHARC archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the UHARC archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `UharcReader` - -Reads entries from a UHARC archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UharcReader` | `UharcReader(Stream stream, bool leaveOpen = false)` | Initializes a new `UharcReader` and parses the archive directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries present in the archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(UharcEntry entry)` | Extracts and decompresses the data for the given entry. | - -#### `UharcWriter` - -Creates a UHARC archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UharcWriter` | `UharcWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `UharcWriter` and writes the archive header. | -| `AddDirectory` | `void AddDirectory(string name, DateTime? lastModified = null)` | Adds a directory entry to the archive (zero data). | -| `AddFile` | `void AddFile(string fileName, byte[] data, DateTime? lastModified = null)` | Adds a file entry to the archive. Compresses with LZP, falling back to Store if the compressed output is not smaller. | -| `Dispose` | `void Dispose()` | | - -### Namespace `FileFormat.Umx` - -[`UmxEntry`](#umxentry) · [`UmxFormatDescriptor`](#umxformatdescriptor) · [`UmxReader`](#umxreader) · [`UmxWriter`](#umxwriter) - -#### `UmxEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `UmxEntry` | `UmxEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `UmxFormatDescriptor` - -Unreal Engine 1 UMX music package — tracker modules (S3M/IT/XM/MOD) wrapped in Unreal package serialization. References: `https://www.gildor.org/` — Gildor's UE tools (UE Viewer) — reference for the Unreal package formatEpic MegaGames Unreal package (UPKG) serialized-object format; music objects embed standard tracker modules - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UmxFormatDescriptor` | `UmxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `UmxReader` - -Reads Unreal Engine UMX music packages. Extracts embedded tracker modules (S3M, IT, XM, MOD) from the Unreal Package container. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UmxReader` | `UmxReader(Stream stream, bool leaveOpen = false)` | | -| `UmxMagic` | `const uint UmxMagic` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(UmxEntry entry)` | | - -#### `UmxWriter` - -Writes a minimal UMX (Unreal Package) file with a valid header. File data is embedded after the header but not yet recoverable through the reader (full export table + compact-index music encoding not implemented — the reader expects a specific "Music" class layout). This WORM writer produces structurally-valid UMX detection + version metadata. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UmxWriter` | `UmxWriter()` | | -| `WriteTo` | `void WriteTo(Stream output, byte[] embeddedData = null)` | | - -### Namespace `FileFormat.UnityBundle` - -[`UnityBundleFormatDescriptor`](#unitybundleformatdescriptor) · [`UnityBundleReader`](#unitybundlereader) · [`UnityBundleReader.Node`](#unitybundlereadernode) · [`UnityBundleReader.StorageBlock`](#unitybundlereaderstorageblock) - -#### `UnityBundleFormatDescriptor` - -Unity Asset Bundle (`.unity3d` / `.assets` / `.bundle`) — the UnityFS container that ships serialized Unity assets bundled for runtime loading. Each bundled asset is listed as a Node entry (path from the internal directory). Storage blocks can be stored, LZMA, or LZ4/LZ4HC-compressed; all four are supported. References: `https://docs.unity3d.com/Manual/AssetBundlesIntro.html` — official Unity AssetBundle documentation`https://github.com/K0lb3/UnityPy` — UnityPy — open UnityFS parser`https://github.com/Perfare/AssetStudio` — AssetStudio — widely used bundle inspector - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnityBundleFormatDescriptor` | `UnityBundleFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `UnityBundleReader` - -Reads Unity Asset Bundles (`.unity3d` / `.assets` / `.bundle`). The modern UnityFS layout stores a compressed BlocksInfo record that describes a sequence of storage blocks (concatenated into one data stream) and a directory of nodes (assets) that slice that stream by offset/size. Supported signatures: `UnityFS\0` (modern, UnityFS version 6+), `UnityWeb\0`/`UnityRaw\0` (legacy, header parsed only — no node directory is extracted since the classic format uses a different container). Only the UnityFS variant surfaces assets. Compression for BlocksInfo and individual storage blocks is indicated by the low 6 bits of a flags field: 0 = none, 1 = LZMA (raw, 5-byte properties + stream), 2 = LZ4, 3 = LZ4HC (same block format as LZ4). - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnityBundleReader` | `UnityBundleReader(byte[] data)` | | -| `Blocks` | `IReadOnlyList Blocks { get; }` | Storage blocks described by BlocksInfo. Empty when the bundle isn't UnityFS. | -| `CanExtract` | `bool CanExtract { get; }` | True if every block in the bundle uses a compression we can decode. | -| `CompressedBlocksInfoSize` | `uint CompressedBlocksInfoSize { get; }` | Compressed BlocksInfo size (bytes). | -| `Flags` | `uint Flags { get; }` | Raw flags field (low 6 bits = BlocksInfo compression, bit 6 = dir combined, bit 7 = at end). | -| `FormatVersion` | `uint FormatVersion { get; }` | File-format version from the header (typically 6 or 7). | -| `Nodes` | `IReadOnlyList Nodes { get; }` | Asset node directory. Empty when the bundle isn't UnityFS. | -| `Signature` | `string Signature { get; }` | The signature string (e.g. "UnityFS"). | -| `TotalSize` | `long TotalSize { get; }` | Total bundle size from the header. | -| `UncompressedBlocksInfoSize` | `uint UncompressedBlocksInfoSize { get; }` | Uncompressed BlocksInfo size (bytes). | -| `UnityRevision` | `string UnityRevision { get; }` | Unity engine revision (e.g. "2019.4.11f1"). | -| `UnityVersion` | `string UnityVersion { get; }` | Unity version (e.g. "5.x.x"). | -| `ExtractNode` | `byte[] ExtractNode(Node node)` | Returns the decompressed bytes of a single asset node. Nodes are resolved against the concatenated (decompressed) storage stream. Throws when the bundle isn't UnityFS or when any contributing storage block uses an unsupported compression type. | -| `GetDataStream` | `byte[] GetDataStream()` | Returns (or materializes) the concatenated, decompressed storage data stream described by `Blocks`. | - -#### `UnityBundleReader.Node` - -A single asset (node) inside the reconstructed data stream. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Node` | `Node(long Offset, long Size, uint Flags, string Path)` | A single asset (node) inside the reconstructed data stream. | -| `Flags` | `uint Flags { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Path` | `string Path { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `UnityBundleReader.StorageBlock` - -A single UnityFS storage block (compression unit inside the bundle). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `StorageBlock` | `StorageBlock(uint UncompressedSize, uint CompressedSize, ushort Flags)` | A single UnityFS storage block (compression unit inside the bundle). | -| `CompressedSize` | `uint CompressedSize { get; init; }` | | -| `Flags` | `ushort Flags { get; init; }` | | -| `UncompressedSize` | `uint UncompressedSize { get; init; }` | | - -### Namespace `FileFormat.UnrealPak` - -[`UnrealPakFormatDescriptor`](#unrealpakformatdescriptor) · [`UnrealPakReader`](#unrealpakreader) · [`UnrealPakReader.UnrealPakEntry`](#unrealpakreaderunrealpakentry) - -#### `UnrealPakFormatDescriptor` - -Unreal Engine 4/5 `.pak` archive. Entries are stored or zlib-compressed and are listed through an index block at the end of the file. Encrypted PAKs and Oodle-compressed entries are listed but not extracted. References: format defined by Epic's UnrealPak tool / `IPlatformFilePak` in the Unreal Engine sources (github.com/EpicGames/UnrealEngine, EULA-gated)`https://github.com/panzi/u4pak` — u4pak — open reader/packer for UE4 .pak archives - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnrealPakFormatDescriptor` | `UnrealPakFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single Unreal Pak entry as a bounded read-only stream. The entry's bytes are decoded (zlib if needed) by the reader and wrapped in a `BoundedEntryStream` sized to the uncompressed length. Encrypted or unsupported-compression entries return an empty bounded stream. | - -#### `UnrealPakReader` - -Reads Unreal Engine 4/5 `.pak` archives. A PAK file has three parts: Entry payloads at the start of the file.An index block listing filenames and their offsets/sizes.A fixed-size footer (last 44..~220 bytes) containing magic + version + index location. This reader targets versions 3–11 (UE 4.15 through UE 5.x) for unencrypted archives with either stored or zlib-compressed entries. Oodle compression and AES encryption are reported (via `UnsupportedReason`) but not decoded. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnrealPakReader` | `UnrealPakReader(Stream stream)` | | -| `Magic` | `const uint Magic` | | -| `CompressionMethods` | `IReadOnlyList CompressionMethods { get; }` | Compression method names recorded in the footer (v8+). Index 0 is always None. | -| `Entries` | `IReadOnlyList Entries { get; }` | File entries parsed from the index. | -| `IsIndexEncrypted` | `bool IsIndexEncrypted { get; }` | True if the index was marked AES-encrypted; nothing can be listed in that case. | -| `MountPoint` | `string MountPoint { get; }` | The mount-point prefix stored in the index. | -| `PakVersion` | `uint PakVersion { get; }` | The PAK version number parsed from the footer (3..11+). | -| `Extract` | `byte[] Extract(UnrealPakEntry entry)` | Returns the decompressed bytes of an entry. Throws `NotSupportedException` when the entry uses AES or an unsupported compression method (e.g. Oodle). | - -#### `UnrealPakReader.UnrealPakEntry` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UnrealPakEntry` | `UnrealPakEntry(string Path, long Offset, long Size, long UncompressedSize, uint CompressionMethod, bool IsEncrypted, string UnsupportedReason)` | | -| `CompressionMethod` | `uint CompressionMethod { get; init; }` | | -| `IsEncrypted` | `bool IsEncrypted { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Path` | `string Path { get; init; }` | | -| `Size` | `long Size { get; init; }` | | -| `UncompressedSize` | `long UncompressedSize { get; init; }` | | -| `UnsupportedReason` | `string UnsupportedReason { get; init; }` | | - -### Namespace `FileFormat.Upx` - -[`UpxElfImage`](#upxelfimage) · [`UpxElfImage.Block`](#upxelfimageblock) · [`UpxElfImage.Image`](#upxelfimageimage) · [`UpxElfImage.LoadSegment`](#upxelfimageloadsegment) · [`UpxExecutablePackerHandler`](#upxexecutablepackerhandler) · [`UpxFilters`](#upxfilters) · [`UpxFormatDescriptor`](#upxformatdescriptor) · [`UpxReader`](#upxreader) · [`UpxReader.ContainerKind`](#upxreadercontainerkind) · [`UpxReader.DetectionConfidence`](#upxreaderdetectionconfidence) · [`UpxReader.DetectionEvidence`](#upxreaderdetectionevidence) · [`UpxReader.Info`](#upxreaderinfo) · [`UpxReader.PackerHeader`](#upxreaderpackerheader) · [`UpxReader.PackerHeaderLayout`](#upxreaderpackerheaderlayout) · [`UpxReader.PeSection`](#upxreaderpesection) - -#### `UpxElfImage` - -Parser and rebuilder for the ELF flavour of the UPX container. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TryRead` | `static Image TryRead(ReadOnlySpan image, long maximumDecompressedSize, out string error)` | Parses the UPX ELF container and decompresses every block. Returns `null` when the image is not a UPX ELF container we can follow; `error` then carries the reason. | - -#### `UpxElfImage.Block` - -One compressed (or stored) block plus the b_info that describes it. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Block` | `Block(int HeaderOffset, int DataOffset, uint UncompressedSize, uint CompressedSize, byte Method, byte FilterId, byte FilterCto, bool Stored)` | One compressed (or stored) block plus the b_info that describes it. | -| `CompressedSize` | `uint CompressedSize { get; init; }` | | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `FilterCto` | `byte FilterCto { get; init; }` | | -| `FilterId` | `byte FilterId { get; init; }` | | -| `HeaderOffset` | `int HeaderOffset { get; init; }` | | -| `Method` | `byte Method { get; init; }` | | -| `Stored` | `bool Stored { get; init; }` | | -| `UncompressedSize` | `uint UncompressedSize { get; init; }` | | - -#### `UpxElfImage.Image` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Image` | `Image(byte Version, byte Format, ushort LoaderSize, uint OriginalFileSize, uint BlockSize, IReadOnlyList Blocks, IReadOnlyList HoleBlocks, IReadOnlyList OriginalLoads, IReadOnlyList BlockData, IReadOnlyList HoleData, byte[] Payload, byte[] Original, IReadOnlyList Notes)` | | -| `BlockData` | `IReadOnlyList BlockData { get; init; }` | | -| `BlockSize` | `uint BlockSize { get; init; }` | | -| `Blocks` | `IReadOnlyList Blocks { get; init; }` | | -| `Format` | `byte Format { get; init; }` | | -| `HoleBlocks` | `IReadOnlyList HoleBlocks { get; init; }` | | -| `HoleData` | `IReadOnlyList HoleData { get; init; }` | | -| `LoaderSize` | `ushort LoaderSize { get; init; }` | | -| `Notes` | `IReadOnlyList Notes { get; init; }` | | -| `OriginalFileSize` | `uint OriginalFileSize { get; init; }` | | -| `OriginalLoads` | `IReadOnlyList OriginalLoads { get; init; }` | | -| `Original` | `byte[] Original { get; init; }` | | -| `Payload` | `byte[] Payload { get; init; }` | | -| `Version` | `byte Version { get; init; }` | | - -#### `UpxElfImage.LoadSegment` - -A PT_LOAD of the original (unpacked) image, in file-offset order. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LoadSegment` | `LoadSegment(long FileOffset, long FileSize)` | A PT_LOAD of the original (unpacked) image, in file-offset order. | -| `FileOffset` | `long FileOffset { get; init; }` | | -| `FileSize` | `long FileSize { get; init; }` | | - -#### `UpxExecutablePackerHandler` - -Implements `IExecutablePackerHandler`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UpxExecutablePackerHandler` | `UpxExecutablePackerHandler()` | | -| `Capabilities` | `ExecutableUnpackCapabilities Capabilities { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Id` | `string Id { get; }` | | -| `Detect` | `DetectionResult Detect(ReadOnlySpan image)` | | -| `Parse` | `PackedExecutable Parse(ReadOnlySpan image, DetectionResult detection)` | | -| `Unpack` | `UnpackResult Unpack(PackedExecutable packed, UnpackOptions options)` | | - -#### `UpxFilters` - -Reverses the byte transforms UPX applies to a block before compressing it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CallTrickWithMarker` | `const byte CallTrickWithMarker` | x86 relative call/jump conversion keyed by a marker byte. | -| `TryReverse` | `static bool TryReverse(byte[] data, byte filterId, byte filterCto, out string error)` | Reverses `filterId` over `data` in place. Returns `false` and fills `error` when the filter is one we cannot undo, so callers can surface the block untouched rather than silently hand back wrong bytes. | - -#### `UpxFormatDescriptor` - -Pseudo-archive descriptor for UPX-packed executables. The archive facade stays compatible with CW's List/Extract model, while the actual unpacking work is delegated to `UpxExecutablePackerHandler`. - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UpxFormatDescriptor` | `UpxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `UpxReader` - -Reader for UPX-packed executables. Parses both PE and ELF variants and surfaces the compressed payload regions + UPX packer header so a caller can inspect the metadata, pipe it through `upx -d`, or feed the compressed stream to a UCL/LZMA decompressor without executing the stub. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UpxReader` | `UpxReader()` | | -| `SectionNames` | `static readonly string[] SectionNames` | PE-style 8-byte section names used by canonical UPX output. | -| `PackerMagic` | `static ReadOnlySpan PackerMagic { get; }` | 4-byte magic "UPX!" (0x55 0x50 0x58 0x21) present in untampered packer headers. | -| `FormatName` | `static string FormatName(byte format)` | Decodes the `format` byte from a UPX header to a human-readable name. | -| `LocateCompressedPayload` | `static byte[] LocateCompressedPayload(Info info)` | Locates the compressed payload bytes inside a UPX-packed image based on the PackHeader trailer. Returns null when no header is available — callers without a header have no anchor to identify the start of the compressed region (UPX places it immediately before the trailer). | -| `MethodName` | `static string MethodName(byte method)` | Decodes the `method` byte from a UPX packer header into a human-readable compression algorithm name. Unrecognised values are returned as `method_` so callers can still surface them in metadata. | -| `Read` | `static Info Read(ReadOnlySpan data)` | | - -#### `UpxReader.ContainerKind` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Pe` | `0` | | -| `Elf` | `1` | | -| `MachO` | `2` | | -| `Unknown` | `3` | | - -#### `UpxReader.DetectionConfidence` - -Aggregated detection confidence after combining all heuristic layers. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No UPX evidence found. | -| `Heuristic` | `1` | Structural shape suggests UPX (renamed sections, packed-binary fingerprint) but no header found. | -| `Confirmed` | `2` | Found the PackHeader struct (with or without intact "UPX!" magic) — high confidence. | - -#### `UpxReader.DetectionEvidence` - -Cumulative evidence collected by individual fingerprint checks. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DetectionEvidence` | `DetectionEvidence(bool SectionNamesMatch, bool ToolingBannerPresent, bool PackHeaderFound, bool PackHeaderMagicIntact, bool StructuralFingerprintMatch, int FingerprintScore, string FingerprintReasoning)` | Cumulative evidence collected by individual fingerprint checks. | -| `FingerprintReasoning` | `string FingerprintReasoning { get; init; }` | | -| `FingerprintScore` | `int FingerprintScore { get; init; }` | | -| `PackHeaderFound` | `bool PackHeaderFound { get; init; }` | | -| `PackHeaderMagicIntact` | `bool PackHeaderMagicIntact { get; init; }` | | -| `SectionNamesMatch` | `bool SectionNamesMatch { get; init; }` | | -| `StructuralFingerprintMatch` | `bool StructuralFingerprintMatch { get; init; }` | | -| `ToolingBannerPresent` | `bool ToolingBannerPresent { get; init; }` | | - -#### `UpxReader.Info` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Info` | `Info(ContainerKind Kind, DetectionConfidence Confidence, DetectionEvidence Evidence, IReadOnlyList PeSections, PackerHeader Header, string ToolingString, uint? PeEntryPointRva, int PeEntryPointSectionIndex, byte[] Image)` | | -| `Confidence` | `DetectionConfidence Confidence { get; init; }` | | -| `Evidence` | `DetectionEvidence Evidence { get; init; }` | | -| `Header` | `PackerHeader Header { get; init; }` | | -| `Image` | `byte[] Image { get; init; }` | | -| `IsUpxPacked` | `bool IsUpxPacked { get; }` | Convenience property for callers that just want a yes/no answer. | -| `Kind` | `ContainerKind Kind { get; init; }` | | -| `PeEntryPointRva` | `uint? PeEntryPointRva { get; init; }` | | -| `PeEntryPointSectionIndex` | `int PeEntryPointSectionIndex { get; init; }` | | -| `PeSections` | `IReadOnlyList PeSections { get; init; }` | | -| `ToolingString` | `string ToolingString { get; init; }` | | - -#### `UpxReader.PackerHeader` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PackerHeader` | `PackerHeader(int Offset, bool MagicIntact, byte Version, byte Format, byte Method, byte Level, uint UncompressedSize, uint CompressedSize, uint UncompressedAdler32, uint CompressedAdler32, uint FilterId, uint FilterCtoSize, byte Filter, byte FilterCto, byte NumCto, byte ChecksumType, PackerHeaderLayout Layout)` | | -| `ChecksumType` | `byte ChecksumType { get; init; }` | | -| `CompressedAdler32` | `uint CompressedAdler32 { get; init; }` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | | -| `FilterCtoSize` | `uint FilterCtoSize { get; init; }` | | -| `FilterCto` | `byte FilterCto { get; init; }` | | -| `FilterId` | `uint FilterId { get; init; }` | | -| `Filter` | `byte Filter { get; init; }` | | -| `Format` | `byte Format { get; init; }` | | -| `Layout` | `PackerHeaderLayout Layout { get; init; }` | | -| `Level` | `byte Level { get; init; }` | | -| `MagicIntact` | `bool MagicIntact { get; init; }` | | -| `Method` | `byte Method { get; init; }` | | -| `NumCto` | `byte NumCto { get; init; }` | | -| `Offset` | `int Offset { get; init; }` | | -| `UncompressedAdler32` | `uint UncompressedAdler32 { get; init; }` | | -| `UncompressedSize` | `uint UncompressedSize { get; init; }` | | -| `Version` | `byte Version { get; init; }` | | - -#### `UpxReader.PackerHeaderLayout` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Legacy` | `0` | | -| `ModernPe` | `1` | | - -#### `UpxReader.PeSection` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PeSection` | `PeSection(string Name, uint VirtualSize, uint VirtualAddress, uint RawSize, uint RawOffset, uint Characteristics)` | | -| `Characteristics` | `uint Characteristics { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `RawOffset` | `uint RawOffset { get; init; }` | | -| `RawSize` | `uint RawSize { get; init; }` | | -| `VirtualAddress` | `uint VirtualAddress { get; init; }` | | -| `VirtualSize` | `uint VirtualSize { get; init; }` | | - -### Namespace `FileFormat.UuEncoding` - -[`UuEncoder`](#uuencoder) · [`UuEncodingFormatDescriptor`](#uuencodingformatdescriptor) - -#### `UuEncoder` - -Classic Unix-to-Unix encoding for binary-to-text conversion. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static ValueTuple Decode(Stream input)` | Decodes UUEncoded text back to binary. | -| `Encode` | `static void Encode(Stream input, Stream output, string filename, int mode = 644)` | Encodes binary data into UUEncoded text. | - -#### `UuEncodingFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UuEncodingFormatDescriptor` | `UuEncodingFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.VobSub` - -[`VobSubFormatDescriptor`](#vobsubformatdescriptor) · [`VobSubReader`](#vobsubreader) · [`VobSubReader.Index`](#vobsubreaderindex) · [`VobSubReader.IndexEntry`](#vobsubreaderindexentry) · [`VobSubReader.Pair`](#vobsubreaderpair) - -#### `VobSubFormatDescriptor` - -Pseudo-archive descriptor for VobSub DVD subtitles. The primary file is the textual `.idx`; the binary `.sub` sibling is resolved by replacing the extension. Each subtitle frame from the `.sub` is exposed as `subtitle_NNN.bin`. References: `http://sam.zoy.org/writings/dvd/subtitles/` — Sam Hocevar's classic DVD subtitle (SPU/RLE) format descriptionVobSub / DirectVobSub (Gabest) — the defining tool producing .idx/.sub pairs - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VobSubFormatDescriptor` | `VobSubFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `ExtractPair` | `void ExtractPair(byte[] idxBytes, byte[] subBytes, string outputDir, string[] files)` | Extracts entries given both files explicitly (preferred when the caller has filesystem access and can locate the sibling .sub). | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `ListPair` | `List ListPair(byte[] idxBytes, byte[] subBytes)` | Lists entries given both files explicitly (preferred when the caller has filesystem access and can locate the sibling .sub). | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single VobSub entry as a bounded read-only stream. The `metadata.ini` + `index.idx` + per-frame entries each produce a decoded byte buffer; the matched buffer is wrapped in a `BoundedEntryStream` sized to its logical length. | - -#### `VobSubReader` - -Reader for VobSub DVD subtitle pairs (`.idx` + `.sub`). - -| Member | Signature | Summary | -| --- | --- | --- | -| `VobSubReader` | `VobSubReader()` | | -| `ReadIndex` | `static Index ReadIndex(string text)` | Parses an .idx text file. Unknown directives are ignored. | -| `Read` | `static Pair Read(byte[] idxBytes, ReadOnlySpan subBytes)` | UTF-8 conveniance wrapper for tests / disk-backed scenarios. | -| `Read` | `static Pair Read(string idxText, ReadOnlySpan subBytes)` | Convenience overload: reads the .idx text from `idxText` and slices the supplied .sub byte stream into per-frame byte arrays. | -| `SliceFrames` | `static IReadOnlyList SliceFrames(Index index, ReadOnlySpan sub)` | Slices the .sub byte stream into per-subtitle byte arrays using the index entries' `filepos` values as boundaries. The bytes between consecutive `filepos` values form one frame; the final frame extends to end-of-file. | - -#### `VobSubReader.Index` - -Parsed contents of an .idx file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Index` | `Index(int Width, int Height, IReadOnlyList Palette, string Language, IReadOnlyList Entries)` | Parsed contents of an .idx file. | -| `Entries` | `IReadOnlyList Entries { get; init; }` | | -| `Height` | `int Height { get; init; }` | | -| `Language` | `string Language { get; init; }` | | -| `Palette` | `IReadOnlyList Palette { get; init; }` | | -| `Width` | `int Width { get; init; }` | | - -#### `VobSubReader.IndexEntry` - -One subtitle frame entry from the .idx file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IndexEntry` | `IndexEntry(TimeSpan Timestamp, long FilePos)` | One subtitle frame entry from the .idx file. | -| `FilePos` | `long FilePos { get; init; }` | | -| `Timestamp` | `TimeSpan Timestamp { get; init; }` | | - -#### `VobSubReader.Pair` - -Header/Body bundle of a parsed VobSub pair. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pair` | `Pair(Index Index, IReadOnlyList Frames)` | Header/Body bundle of a parsed VobSub pair. | -| `Frames` | `IReadOnlyList Frames { get; init; }` | | -| `Index` | `Index Index { get; init; }` | | - -### Namespace `FileFormat.Vpk` - -[`VpkEntry`](#vpkentry) · [`VpkFormatDescriptor`](#vpkformatdescriptor) · [`VpkReader`](#vpkreader) · [`VpkWriter`](#vpkwriter) - -#### `VpkEntry` - -Entry in a VPK archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VpkEntry` | `VpkEntry()` | | -| `ArchiveIndex` | `ushort ArchiveIndex { get; init; }` | Which archive part contains data (0x7FFF = in _dir file). | -| `Crc32` | `uint Crc32 { get; init; }` | CRC32 of the file data. | -| `DirectoryPath` | `string DirectoryPath { get; init; }` | Directory path within the archive. | -| `Extension` | `string Extension { get; init; }` | File extension (without dot). | -| `FileName` | `string FileName { get; init; }` | File name without extension. | -| `FullPath` | `string FullPath { get; }` | Full path: dir/name.ext | -| `Length` | `uint Length { get; init; }` | Length of file data in archive. | -| `Offset` | `uint Offset { get; init; }` | Offset within the archive file. | -| `PreloadBytes` | `byte[] PreloadBytes { get; init; }` | Preload data bytes embedded in directory. | - -#### `VpkFormatDescriptor` - -Valve Pak (VPK) game resource archive — directory-tree index, optionally split across numbered data packs. References: `https://developer.valvesoftware.com/wiki/VPK` — Valve Developer Community — VPK format and tool documentation`https://github.com/ValvePython/vpk` — open VPK implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VpkFormatDescriptor` | `VpkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the VPK archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the VPK archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the archive: any byte not covered by a live extent in the layout map (headers, entry data and directory structures are live and preserved, so the archive still lists and extracts identically). Cluster-tip wiping is N/A (entries are stored byte-exact with no per-file slack). | - -#### `VpkReader` - -Reads Valve Pak (VPK) archives used by Source engine games. Supports v1 and v2 format. Single-file and multi-part archives. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VpkReader` | `VpkReader(Stream stream)` | | -| `Signature` | `const uint Signature` | VPK signature: 0x55AA1234 | -| `DataOffset` | `long DataOffset { get; }` | Gets the byte offset where embedded file data begins. | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Version` | `int Version { get; }` | | -| `Extract` | `byte[] Extract(VpkEntry entry)` | Extracts entry data. Only works for single-file VPKs (archiveIndex 0x7FFF). | - -#### `VpkWriter` - -Creates single-file VPK v1 archives (all data in _dir file, archiveIndex = 0x7FFF). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VpkWriter` | `VpkWriter(Stream stream, bool leaveOpen = false)` | | -| `AddFile` | `void AddFile(string path, byte[] data)` | Adds a file to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the VPK file. | - -### Namespace `FileFormat.Vpp` - -[`VppEntry`](#vppentry) · [`VppFormatDescriptor`](#vppformatdescriptor) · [`VppReader`](#vppreader) · [`VppWriter`](#vppwriter) - -#### `VppEntry` - -Represents a single file entry in a VPP_PC v1 archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppEntry` | `VppEntry()` | | -| `Name` | `string Name { get; init; }` | Gets the entry name (up to 59 ASCII characters; null-terminator excluded). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry data within the archive stream. | -| `Size` | `long Size { get; init; }` | Gets the size of the entry data in bytes (unaligned, i.e. payload length). | - -#### `VppFormatDescriptor` - -Volition Package (VPP v1) — Red Faction 1 / Summoner game archive. References: `https://github.com/gibbed/Gibbed.Volition` — Gibbed.Volition — community tools for Volition package formatsVolition's game archive; no official spec, layout community-documented - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppFormatDescriptor` | `VppFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the VPP archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the VPP archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `VppReader` - -Reads entries from a Volition Package (VPP_PC v1) archive — Red Faction 1 / Summoner era. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppReader` | `VppReader(Stream stream, bool leaveOpen = false)` | Initializes a new `VppReader` from a stream. | -| `DeclaredTotalSize` | `long DeclaredTotalSize { get; }` | Gets the total file size declared in the header (not the actual stream length). | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive in declaration order. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(VppEntry entry)` | Extracts the raw bytes for a given entry. | - -#### `VppWriter` - -Creates a Volition Package (VPP_PC v1) archive — Red Faction 1 / Summoner era. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppWriter` | `VppWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `VppWriter`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the VPP_PC archive to the stream and finalises the header. | - -### Namespace `FileFormat.VppV2` - -[`VppV2Entry`](#vppv2entry) · [`VppV2FormatDescriptor`](#vppv2formatdescriptor) · [`VppV2Reader`](#vppv2reader) · [`VppV2Writer`](#vppv2writer) - -#### `VppV2Entry` - -Represents a single file entry in a VPP v2 (Saint's Row 2) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppV2Entry` | `VppV2Entry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Gets the on-disk payload size in bytes (equals `DataSize` when stored uncompressed). | -| `DataOffset` | `long DataOffset { get; init; }` | Gets the absolute byte offset of the entry payload within the archive stream. | -| `DataSize` | `long DataSize { get; init; }` | Gets the uncompressed payload size in bytes. | -| `IsCompressed` | `bool IsCompressed { get; init; }` | Gets a value indicating whether this entry's payload is zlib-compressed (raw deflate). | -| `Name` | `string Name { get; init; }` | Gets the entry's full name (path) as stored in the name table. | - -#### `VppV2FormatDescriptor` - -Volition Package v2 (Saint's Row 2 era) descriptor — handles `.vpp_pc` archives with optional per-entry zlib compression. References: `https://github.com/gibbed/Gibbed.Volition` — Gibbed.Volition — community tools for Volition package formatsVolition's package format for Saints Row 2 (.vpp_pc); no official spec, reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppV2FormatDescriptor` | `VppV2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the VPP v2 archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the VPP v2 archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `VppV2Reader` - -Reads entries from a Volition Package v2 archive (Saint's Row 2 era, .vpp_pc). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppV2Reader` | `VppV2Reader(Stream stream, bool leaveOpen = false)` | Initializes a new `VppV2Reader` from a stream. | -| `DeclaredArchiveSize` | `long DeclaredArchiveSize { get; }` | Gets the total archive size declared in the header. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the archive in declaration order. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(VppV2Entry entry)` | Extracts the (decompressed) raw bytes for a given entry. | - -#### `VppV2Writer` - -Creates a Volition Package v2 archive (Saint's Row 2 era, .vpp_pc). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VppV2Writer` | `VppV2Writer(Stream stream, bool leaveOpen = false, CompressionLevel compressionLevel = 0)` | Initializes a new `VppV2Writer`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the archive contents to the stream and finalises the header. | - -### Namespace `FileFormat.Vsdx` - -[`VsdxFormatDescriptor`](#vsdxformatdescriptor) - -#### `VsdxFormatDescriptor` - -Microsoft Visio VSDX drawing — an OPC ZIP package. References: [MS-VSDX]: Visio Graphics Service File Format (Microsoft Open Specifications, learn.microsoft.com)`https://ecma-international.org/publications-and-standards/standards/ecma-376/` — ECMA-376 Part 2 — Open Packaging Conventions, the container VSDX uses`https://en.wikipedia.org/wiki/Microsoft_Visio` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VsdxFormatDescriptor` | `VsdxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) parts inside an existing VSDX package. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended part's local file header + compressed data are read or written; pre-existing entries stay byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (VSDX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (VSDX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named parts; uses `ZipModifier`. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros every dead byte in the package: gaps between entries not covered by a live extent in the ZIP layout map. Local headers, entry data, the central directory and EOCD are live and preserved. Cluster-tip wiping is N/A (ZIP packs entries back to back with no per-file slack). | - -### Namespace `FileFormat.Wacz` - -[`WaczFormatDescriptor`](#waczformatdescriptor) - -#### `WaczFormatDescriptor` - -Descriptor for the WACZ (Web Archive Collection Zipped) format — a ZIP container that wraps one or more WARC files together with a Frictionless-Data manifest, page index and optional resource bundles. References: `https://specs.webrecorder.net/wacz/1.1.1/` — the WACZ 1.1.1 specification (Webrecorder)`https://webrecorder.net` — Webrecorder, the format's author and reference tooling (py-wacz, ReplayWeb.page) - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WaczFormatDescriptor` | `WaczFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The synthetic `metadata.ini` entry is materialised on the fly; all other entries delegate to the inner `ZipReader` and are wrapped in a `BoundedEntryStream` sized to the entry's uncompressed length. | - -### Namespace `FileFormat.Wad` - -[`WadEntry`](#wadentry) · [`WadFormatDescriptor`](#wadformatdescriptor) · [`WadReader`](#wadreader) · [`WadWriter`](#wadwriter) - -#### `WadEntry` - -Represents a single lump entry in a WAD archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WadEntry` | `WadEntry()` | | -| `DataOffset` | `int DataOffset { get; init; }` | Gets the offset of the lump data from the start of the WAD file. | -| `IsMarker` | `bool IsMarker { get; }` | Gets whether this entry is a marker lump (zero-size lumps such as "MAP01", "S_START", etc.). | -| `Name` | `string Name { get; init; }` | Gets the lump name (up to 8 uppercase ASCII characters). | -| `Size` | `int Size { get; init; }` | Gets the size of the lump data in bytes. | - -#### `WadFormatDescriptor` - -Doom WAD (IWAD/PWAD) — the id Software lump-directory game-data archive. References: `https://doomwiki.org/wiki/WAD` — Doom Wiki — definitive community WAD documentationMatthew S. Fell, "The Unofficial Doom Specs" — the original public format documentation`https://en.wikipedia.org/wiki/Doom_WAD` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WadFormatDescriptor` | `WadFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the WAD archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the WAD archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `WadReader` - -Reads entries from an id Software WAD archive (Doom/Heretic/Hexen). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WadReader` | `WadReader(Stream stream, bool leaveOpen = false)` | Initializes a new `WadReader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all lump entries in the WAD. | -| `IsIwad` | `bool IsIwad { get; }` | Gets whether the WAD is an Internal WAD (IWAD). | -| `IsPwad` | `bool IsPwad { get; }` | Gets whether the WAD is a Patch WAD (PWAD). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(WadEntry entry)` | Extracts the data for a given lump entry. | - -#### `WadWriter` - -Creates an id Software WAD archive (Doom/Heretic/Hexen). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WadWriter` | `WadWriter(Stream stream, bool leaveOpen = false, bool isIwad = false)` | Initializes a new `WadWriter`. | -| `AddLump` | `void AddLump(string name, byte[] data)` | Adds a lump with data. | -| `AddMarker` | `void AddMarker(string name)` | Adds a zero-size marker lump (e.g., "MAP01", "S_START", "S_END"). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the WAD archive to the stream and finishes writing. | - -### Namespace `FileFormat.Wad2` - -[`Wad2Entry`](#wad2entry) · [`Wad2FormatDescriptor`](#wad2formatdescriptor) · [`Wad2Modifier`](#wad2modifier) · [`Wad2Reader`](#wad2reader) · [`Wad2Writer`](#wad2writer) - -#### `Wad2Entry` - -Represents a single entry in a WAD2/WAD3 texture archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Wad2Entry` | `Wad2Entry()` | | -| `CompressedSize` | `int CompressedSize { get; init; }` | Gets the on-disk (compressed) size of the entry data in bytes. | -| `Compression` | `byte Compression { get; init; }` | Gets the compression method (0=none, 1=LZSS). | -| `DataOffset` | `int DataOffset { get; init; }` | Gets the offset of the entry data from the start of the WAD file. | -| `Name` | `string Name { get; init; }` | Gets the entry name (up to 16 ASCII characters). | -| `Size` | `int Size { get; init; }` | Gets the uncompressed size of the entry data in bytes. | -| `Type` | `byte Type { get; init; }` | Gets the entry type byte (e.g. 0x40=palette, 0x43=texture, 0x44=MIP texture). | - -#### `Wad2FormatDescriptor` - -WAD2 texture/lump archive used by Quake (WAD3 variant used by GoldSrc/Half-Life). References: id Software "Quake Specifications" v3.4 — documents the WAD2 lump directory`https://developer.valvesoftware.com/wiki/WAD` — Valve Developer Community — the WAD3 (GoldSrc) variant - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Wad2FormatDescriptor` | `Wad2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends (or replaces by name) entries inside an existing WAD2/WAD3 archive. WAD's directory lives at the END of the file with a pointer in the 12-byte header, so Add only has to: Truncate the trailing directory.Append the new entry's bytes at the new EOF.Re-emit the directory (old entries + new entry).Patch the 4-byte numEntries and 4-byte dirOffset fields in the header. The 4-byte magic at `[0, 4)` and the data region `[12, oldDirOffset)` survive byte-identical — that's the contract. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the WAD2 archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the WAD2 archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing WAD2/WAD3 archive. For each entry, walks the directory to find it, rewrites the data region with that entry's bytes dropped, re-emits the directory, and patches the header. | - -#### `Wad2Modifier` - -In-place WAD2/WAD3 archive modifier. The Quake/Half-Life WAD container places the 32-byte directory at the END of the file (after entry data), with a pointer in the 12-byte header at offset 8. That makes Add a localised mutation: Truncate the file at the old `dirOffset` (drop the trailing directory).Append the new entry's bytes at the new EOF.Append the rebuilt directory (old entries + new entry) at the new EOF.Patch the 12-byte header so `numEntries` and `dirOffset` reflect the new layout.Byte-identity contract: the magic at `[0, 4)` and the data region `[12, oldDirOffset)` are byte-identical after Add (no pre-existing entry's bytes move). Only the header's `numEntries`/`dirOffset` fields and the directory itself are re-emitted. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddEntry` | `static void AddEntry(Stream archive, string name, byte[] data, byte entryType = 67)` | Appends an entry to a WAD2/WAD3 archive in place. Preserves bytes `[0, 4)` and `[12, oldDirOffset)` byte-identical. | -| `RemoveEntry` | `static bool RemoveEntry(Stream archive, string name)` | Removes the named entry from a WAD2/WAD3 archive. Walks the directory to find the entry, then rebuilds the data region with that entry dropped (its bytes are removed and trailing data shifted forward), re-emits the directory with updated offsets, and patches the header. Returns false if no entry by that name exists. | - -#### `Wad2Reader` - -Reads entries from a Quake/Half-Life WAD2 or WAD3 texture archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Wad2Reader` | `Wad2Reader(Stream stream, bool leaveOpen = false)` | Initializes a new `Wad2Reader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the WAD archive. | -| `IsWad3` | `bool IsWad3 { get; }` | Gets whether the archive uses WAD3 magic (Half-Life). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(Wad2Entry entry)` | Extracts the raw data for a given entry. | - -#### `Wad2Writer` - -Creates a Quake/Half-Life WAD2 or WAD3 texture archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Wad2Writer` | `Wad2Writer(Stream stream, bool leaveOpen = false, bool isWad3 = true)` | Initializes a new `Wad2Writer`. | -| `AddEntry` | `void AddEntry(string name, byte[] data, byte type = 67)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the WAD archive to the stream and finishes writing. | - -### Namespace `FileFormat.War` - -[`WarFormatDescriptor`](#warformatdescriptor) - -#### `WarFormatDescriptor` - -Java Web Application Archive (WAR) — a ZIP/JAR with WEB-INF layout. References: `https://jakarta.ee/specifications/servlet/` — Jakarta Servlet specification — defines WAR packaging`https://en.wikipedia.org/wiki/WAR_(file_format)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WarFormatDescriptor` | `WarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing WAR archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (WAR is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (WAR is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Warc` - -[`WarcEntry`](#warcentry) · [`WarcFormatDescriptor`](#warcformatdescriptor) · [`WarcReader`](#warcreader) · [`WarcWriter`](#warcwriter) - -#### `WarcEntry` - -Represents a single record in a WARC archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WarcEntry` | `WarcEntry()` | | -| `ContentLength` | `long ContentLength { get; set; }` | Gets or sets the Content-Length header value in bytes. | -| `ContentType` | `string ContentType { get; set; }` | Gets or sets the Content-Type header value, or null if not present. | -| `Date` | `string Date { get; set; }` | Gets or sets the WARC-Date header value, or null if not present. | -| `PayloadOffset` | `long PayloadOffset { get; set; }` | Gets or sets the byte offset of the payload within the source stream. | -| `RecordId` | `string RecordId { get; set; }` | Gets or sets the WARC-Record-ID header value. | -| `TargetUri` | `string TargetUri { get; set; }` | Gets or sets the WARC-Target-URI header value, or null if not present. | -| `Type` | `string Type { get; set; }` | Gets or sets the WARC-Type header value (e.g. "response", "warcinfo", "resource"). | - -#### `WarcFormatDescriptor` - -Descriptor for WARC (Web ARChive, ISO 28500) files — the record-oriented container web crawlers use to store captured HTTP transactions and metadata. References: ISO 28500:2017 "WARC file format" — the defining standard`https://iipc.github.io/warc-specifications/` — IIPC-maintained WARC specifications and proposals`https://en.wikipedia.org/wiki/WARC_(file_format)` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WarcFormatDescriptor` | `WarcFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the WARC archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the WARC archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `WarcReader` - -Reads WARC records sequentially from a stream. Supports WARC/1.0 and WARC/1.1. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WarcReader` | `WarcReader(Stream stream, bool leaveOpen = false)` | Initializes a new `WarcReader` from a stream. | -| `Dispose` | `void Dispose()` | | -| `ReadAll` | `List> ReadAll()` | Reads all records from the archive, returning each entry with its payload bytes. | -| `ReadNext` | `ValueTuple? ReadNext()` | Reads the next record from the stream. | - -#### `WarcWriter` - -Writes WARC/1.0 archives. Each input becomes one record (default type "resource"); the existing `WarcReader` roundtrips them. Per the WARC spec each record looks like: - -| Member | Signature | Summary | -| --- | --- | --- | -| `WarcWriter` | `WarcWriter()` | | -| `AddRecord` | `void AddRecord(WarcEntry entry, byte[] payload)` | Adds a record. Required: `Type`; recommended: `TargetUri`, `Date`. | -| `AddResource` | `void AddResource(string targetUri, byte[] payload, string contentType = null, DateTime? date = null)` | Convenience helper for the common "I just have files to wrap" case -- emits one "resource" record per file. | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Wbn` - -[`CborWalker`](#cborwalker) · [`CborWalker.Header`](#cborwalkerheader) · [`WbnConstants`](#wbnconstants) · [`WbnFormatDescriptor`](#wbnformatdescriptor) · [`WbnReader`](#wbnreader) · [`WbnWriter`](#wbnwriter) - -#### `CborWalker` - -Minimal RFC 8949 CBOR walker — enough to recognise major types, read item headers, and skip over arbitrary items so callers can locate specific positions inside a well-formed bundle. Indefinite-length encodings, tag chaining, and break codes are handled. Floats and unsupported simple values are skipped without interpretation. The walker never throws on an unsupported type — it returns false so the caller can downgrade to partial parsing. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TryReadByteStringRaw` | `static byte[] TryReadByteStringRaw(Stream s, in Header h)` | Reads one CBOR byte string body with raw bytes preserved. Use when the caller already consumed the header. | -| `TryReadByteString` | `static byte[] TryReadByteString(Stream s)` | Reads one CBOR byte string. Returns null on type mismatch, malformed input, or truncation. Indefinite-length byte strings are concatenated. | -| `TryReadHeader` | `static bool TryReadHeader(Stream s, out Header header)` | Reads one CBOR header. Returns false at EOF or on malformed leading-byte argument. | -| `TryReadTextString` | `static string TryReadTextString(Stream s)` | Reads one CBOR text string. Returns null on type mismatch, malformed input, or truncation. Indefinite-length text strings are concatenated. | -| `TrySkip` | `static bool TrySkip(Stream s, int depth = 0)` | Skips one complete CBOR item starting at the current stream position. Returns false if the item is malformed or truncated; on false, the stream position is undefined. | - -#### `CborWalker.Header` - -One decoded CBOR header. `MajorType` is in 0..7. `Value` is the argument: positive integers, lengths, or simple values. Indefinite lengths are signalled by `IsIndefinite`. - -Implements `IEquatable
`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Header` | `Header(byte MajorType, ulong Value, bool IsIndefinite)` | One decoded CBOR header. `MajorType` is in 0..7. `Value` is the argument: positive integers, lengths, or simple values. Indefinite lengths are signalled by `IsIndefinite`. | -| `IsIndefinite` | `bool IsIndefinite { get; init; }` | | -| `MajorType` | `byte MajorType { get; init; }` | | -| `Value` | `ulong Value { get; init; }` | | - -#### `WbnConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `BreakStopCode` | `const byte BreakStopCode` | CBOR break stop-code, used inside indefinite-length items. | -| `MagicLength` | `const int MagicLength` | | -| `Magic` | `static readonly byte[] Magic` | Web Bundle magic header. Decodes as a CBOR array-of-4 (0x84) whose first element is a length-8 byte string (0x48) containing the UTF-8 bytes of the globe + package emojis (U+1F310 + U+1F4E6). | -| `MajorTypeArray` | `const byte MajorTypeArray` | | -| `MajorTypeByteString` | `const byte MajorTypeByteString` | | -| `MajorTypeMap` | `const byte MajorTypeMap` | | -| `MajorTypeNegativeInt` | `const byte MajorTypeNegativeInt` | | -| `MajorTypeSimpleOrFloat` | `const byte MajorTypeSimpleOrFloat` | | -| `MajorTypeTag` | `const byte MajorTypeTag` | | -| `MajorTypeTextString` | `const byte MajorTypeTextString` | | -| `MajorTypeUnsignedInt` | `const byte MajorTypeUnsignedInt` | | -| `VersionFieldLength` | `const int VersionFieldLength` | Length of the version field that immediately follows the magic byte string. Encoded as a CBOR length-4 byte string (0x44 + 4 bytes). | - -#### `WbnFormatDescriptor` - -Web Bundle / Bundled HTTP Exchanges (`.wbn`) read-only pseudo-archive. Validates the CBOR-array preamble, walks just enough of the outer structure to surface the version tag, primary URL, and resource count, then emits a `FULL.wbn` passthrough alongside a `metadata.ini` summary. Per-resource extraction is intentionally out of scope — it requires a full CBOR decoder plus HTTP request/response framing to rebuild the embedded URL tree. References: `https://datatracker.ietf.org/doc/draft-ietf-wpack-bundled-responses/` — IETF WPACK "Web Bundles" (Bundled HTTP Responses) draft`https://github.com/WICG/webpackage` — WICG web packaging incubation — spec text and reference tooling - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WbnFormatDescriptor` | `WbnFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM create — emits a Web Bundle whose `index` section contains one entry per non-directory input. See `WbnWriter` for the detailed wire layout. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Handles the synthetic `FULL.wbn` passthrough and the `metadata.ini` summary; both are wrapped in a `BoundedEntryStream` sized to the entry's logical length. | - -#### `WbnReader` - -Read-only walker for Web Bundle (Bundled HTTP Exchanges) files. Validates the magic prefix and uses a minimal CBOR walker to extract the version string, primary URL, and resource count from the `index` section. Web Bundle b1 (no primary URL element) and b2 (with primary URL) layouts are tolerated. The walker downgrades to `ParseStatus` = "partial" if any structural surprise is encountered. Resource bodies are not extracted — they live inside the responses section as CBOR-encoded HTTP response triples and would require a full CBOR decoder plus an HTTP framing pass to surface as individual files. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WbnReader` | `WbnReader(Stream stream)` | | -| `MagicOk` | `bool MagicOk { get; }` | True if the leading 10 magic bytes matched the Web Bundle CBOR-array-of-4 + emoji-byte-string preamble. | -| `ParseStatus` | `string ParseStatus { get; }` | "full" when magic, version, and (for b2) primary URL plus index were all walked successfully. "partial" otherwise — never throws on structural mismatch. | -| `PrimaryUrl` | `string PrimaryUrl { get; }` | Primary URL string for b2 bundles; "unknown" for b1 bundles or when extraction failed. | -| `ResourceCount` | `int ResourceCount { get; }` | Number of URL keys discovered in the `index` section. 0 when the section is absent or could not be walked. | -| `Version` | `string Version { get; }` | Parsed version tag — typically "b1" or "b2". "unknown" if the version field could not be decoded. | - -#### `WbnWriter` - -WORM writer for Web Bundle (`.wbn`) files. Emits the canonical 10-byte CBOR-array-of-4 + emoji-byte-string preamble, a four-byte version field, an optional primary URL, a section-lengths byte string declaring an `index` section, and the corresponding `index` section as a CBOR map keyed by resource URL → `[offset, length]` pairs. Each input is treated as one HTTP response: its raw bytes become the stored body. The URL key is taken from the input's `ArchiveName`. The minimum required CBOR encoder is implemented inline so this project does not gain an external CBOR dependency. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultPrimaryUrl` | `const string DefaultPrimaryUrl` | Default primary URL emitted when no inputs provide one. | -| `DefaultVersion` | `const string DefaultVersion` | Default version tag emitted when none is supplied via options. | -| `Write` | `static void Write(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Writes a Web Bundle from `inputs` to `output`. | - -### Namespace `FileFormat.Wheel` - -[`WheelFormatDescriptor`](#wheelformatdescriptor) - -#### `WheelFormatDescriptor` - -Descriptor for a Python wheel distribution (`.whl`) — a ZIP archive that obeys the on-disk layout mandated by PEP 427. References: `https://peps.python.org/pep-0427/` — PEP 427, the original wheel binary-package specification`https://packaging.python.org/en/latest/specifications/binary-distribution-format/` — the living binary-distribution (wheel) format spec that superseded the PEP text - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WheelFormatDescriptor` | `WheelFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The synthetic `metadata.ini` entry is materialised on the fly; all other entries are delegated to the inner `ZipReader` and wrapped in a `BoundedEntryStream` sized to the entry's uncompressed length. | - -### Namespace `FileFormat.Wim` - -[`WimConstants`](#wimconstants) · [`WimFormatDescriptor`](#wimformatdescriptor) · [`WimHeader`](#wimheader) · [`WimReader`](#wimreader) · [`WimReader.WimFileEntry`](#wimreaderwimfileentry) · [`WimResourceEntry`](#wimresourceentry) · [`WimWriter`](#wimwriter) - -#### `WimConstants` - -Constants for the Windows Imaging (WIM) file format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AttributeArchive` | `const uint AttributeArchive` | Directory-entry attribute bit marking an ordinary file. | -| `AttributeDirectory` | `const uint AttributeDirectory` | Directory-entry attribute bit marking a directory. | -| `CompressionLzms` | `const uint CompressionLzms` | LZMS compression. | -| `CompressionLzx` | `const uint CompressionLzx` | LZX compression. | -| `CompressionNone` | `const uint CompressionNone` | No compression — resources are stored verbatim. | -| `CompressionXpressHuffman` | `const uint CompressionXpressHuffman` | XPRESS Huffman compression. | -| `CompressionXpress` | `const uint CompressionXpress` | XPRESS (LZ Xpress plain) compression. | -| `DefaultChunkSize` | `const int DefaultChunkSize` | Default chunk size for compressed resources: 32 768 bytes (32 KB). | -| `DirEntryFixedSize` | `const int DirEntryFixedSize` | Size of the fixed part of a directory entry, ahead of the file name. | -| `EmptySecurityDataSize` | `const int EmptySecurityDataSize` | Size of an empty security-descriptor block: a total length and an entry count, both of which an image without descriptors still has to carry. | -| `FlagCompression` | `const uint FlagCompression` | Flag bit indicating resources may be compressed. A reader that does not see this bit treats the WIM as uncompressed however the algorithm bits read, so it has to be set alongside them. | -| `FlagLzmsCompression` | `const uint FlagLzmsCompression` | Flag bit indicating the WIM uses LZMS compression. | -| `FlagLzxCompression` | `const uint FlagLzxCompression` | Flag bit indicating the WIM uses LZX compression. | -| `FlagRpFix` | `const uint FlagRpFix` | Flag bit indicating reparse-point path fixups have been applied. Set on every image written here: with no reparse points there is nothing left to fix, which is the state the bit describes. | -| `FlagXpressCompression` | `const uint FlagXpressCompression` | Flag bit indicating the WIM uses XPRESS compression. | -| `FlagXpressHuffmanCompression` | `const uint FlagXpressHuffmanCompression` | Flag bit indicating the WIM uses the second XPRESS arrangement, which differs from the first in chunk size rather than in encoding. | -| `HashLength` | `const int HashLength` | Length of the SHA-1 hash identifying a resource. | -| `HeaderSize` | `const int HeaderSize` | Total size of the WIM file header in bytes (version 1.13). | -| `LookupTableEntrySize` | `const int LookupTableEntrySize` | Size of a single lookup table entry in the resource table, in bytes. Each entry holds: RESHDR_DISK_SHORT (24 bytes) + part number (2) + ref count (4) + SHA-1 hash (20). | -| `LzxWindowBits` | `const int LzxWindowBits` | Default LZX window size exponent used by WIM (window = 2^15 = 32 768 bytes). | -| `MagicLength` | `const int MagicLength` | Length of the magic signature in bytes. | -| `NoSecurityDescriptor` | `const int NoSecurityDescriptor` | The security-descriptor index meaning "none". Written as -1 rather than 0, which would name the first descriptor of a table we do not write. | -| `ReshdrDiskShortSize` | `const int ReshdrDiskShortSize` | Size of a RESHDR_DISK_SHORT structure (packed size+flags, offset, original size). | -| `ResourceFlagCompressed` | `const uint ResourceFlagCompressed` | Resource flag bit 2: resource data is compressed. | -| `ResourceFlagFree` | `const uint ResourceFlagFree` | Resource flag bit 0: the entry describes free space, not a resource. | -| `ResourceFlagMetadata` | `const uint ResourceFlagMetadata` | Resource flag bit 1: resource contains image metadata. | -| `ResourceFlagSpanned` | `const uint ResourceFlagSpanned` | Resource flag bit 3: resource data continues in another part. | -| `ResourceFlagUncompressed` | `const uint ResourceFlagUncompressed` | Resource flag: resource is stored uncompressed. | -| `SolidChunkSize` | `const int SolidChunkSize` | Chunk size an LZMS image uses. | -| `VersionSolid` | `const uint VersionSolid` | The version an LZMS image carries instead, with 128 KB chunks rather than 32 KB. An LZMS resource is only ever found in one of these, so writing the ordinary version alongside LZMS would mark the container as ours. | -| `Version` | `const uint Version` | WIM format version field value for version 1.13 (0x00010D00, little-endian). | -| `Magic` | `static ReadOnlySpan Magic { get; }` | The WIM file magic bytes: "MSWIM\0\0\0" (8 bytes). | - -#### `WimFormatDescriptor` - -Windows Imaging Format (WIM) — file-based disk image with single-instance resource storage. References: Microsoft, "Windows Imaging File Format (WIM)" white paper — the vendor format description`https://wimlib.net/` — wimlib — open implementation with detailed format documentation`https://en.wikipedia.org/wiki/Windows_Imaging_Format` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimFormatDescriptor` | `WimFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single WIM resource as a bounded read-only `Stream`. Resolves `entryName` to a resource index through the named-files metadata, then wraps the decompressed bytes in a `BoundedEntryStream` sized to the file size. | - -#### `WimHeader` - -Represents the WIM file header (208 bytes, version 1.13). - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimHeader` | `WimHeader()` | | -| `BootIndex` | `uint BootIndex { get; init; }` | Gets the index of the bootable image (0 = none). | -| `BootMetadataResource` | `WimResourceEntry BootMetadataResource { get; init; }` | Gets the resource entry describing the boot metadata location (may be absent). | -| `ChunkSize` | `uint ChunkSize { get; init; }` | Gets the uncompressed chunk size for compressed resources. | -| `CompressionType` | `uint CompressionType { get; init; }` | Gets the compression type for resources in this WIM. | -| `Guid` | `Guid Guid { get; init; }` | Gets the identifier shared by every part of one WIM. Readers use it to tell the parts of a split image apart from parts of some other image that happen to be in the same directory. | -| `ImageCount` | `uint ImageCount { get; init; }` | Gets the number of images contained in the WIM. | -| `IntegrityTableResource` | `WimResourceEntry IntegrityTableResource { get; init; }` | Gets the resource entry describing the integrity table (may be absent). | -| `OffsetTableResource` | `WimResourceEntry OffsetTableResource { get; init; }` | Gets the resource entry describing the resource table location. | -| `PartNumber` | `ushort PartNumber { get; init; }` | Gets the index of this part within a split WIM (1-based). | -| `TotalParts` | `ushort TotalParts { get; init; }` | Gets the total number of parts in a split WIM (1 for non-split). | -| `Version` | `uint Version { get; init; }` | Gets the WIM format version number. | -| `WimFlags` | `uint WimFlags { get; init; }` | Gets the header flags field (encodes compression type and other attributes). | -| `XmlDataResource` | `WimResourceEntry XmlDataResource { get; init; }` | Gets the resource entry describing the XML metadata location. | -| `Read` | `static WimHeader Read(Stream stream)` | Reads a `WimHeader` from the given stream. The stream must be positioned at the start of the file. | -| `Write` | `void Write(Stream stream)` | Writes this header to the given stream at its current position. The stream must be positioned at the start of the file. Exactly `HeaderSize` bytes are written. | - -#### `WimReader` - -Reads resources from a WIM (Windows Imaging) file. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimReader` | `WimReader(Stream stream)` | Opens a WIM file from a seekable stream. | -| `Header` | `WimHeader Header { get; }` | Gets the parsed WIM file header. | -| `Resources` | `IReadOnlyList Resources { get; }` | Gets the list of resource entries from the resource table. | -| `Dispose` | `void Dispose()` | Releases all resources used by this `WimReader`. Does not close the underlying stream. | -| `GetNamedFiles` | `List GetNamedFiles()` | Parses image metadata resources and returns named file entries. For WIM files created by external tools (e.g., 7-Zip) that embed directory metadata, this resolves file names to resource indices. | -| `ReadResource` | `byte[] ReadResource(int index)` | Reads and decompresses the resource at the given index. | - -#### `WimReader.WimFileEntry` - -Represents a named file entry extracted from WIM image metadata. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimFileEntry` | `WimFileEntry(string FileName, int ResourceIndex, long FileSize)` | Represents a named file entry extracted from WIM image metadata. | -| `FileName` | `string FileName { get; init; }` | The file name (leaf name, no path). | -| `FileSize` | `long FileSize { get; init; }` | Uncompressed file size from the directory entry. | -| `ResourceIndex` | `int ResourceIndex { get; init; }` | Index into `Resources` for this file's data, or -1 if not found. | - -#### `WimResourceEntry` - -Represents a reshuffled table entry referencing a region of data within a WIM file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimResourceEntry` | `WimResourceEntry(long CompressedSize, long OriginalSize, long Offset, uint Flags, byte[] Hash = null)` | Represents a reshuffled table entry referencing a region of data within a WIM file. | -| `CompressedSize` | `long CompressedSize { get; init; }` | Compressed size of the resource data in bytes. | -| `Flags` | `uint Flags { get; init; }` | Resource flags (see `ResourceFlagCompressed`). | -| `Hash` | `byte[] Hash { get; init; }` | SHA-1 hash identifying the resource (20 bytes, or empty for header entries). | -| `IsCompressed` | `bool IsCompressed { get; }` | Gets a value indicating whether the resource is stored in compressed form. | -| `IsMetadata` | `bool IsMetadata { get; }` | Gets a value indicating whether the resource is a metadata resource. | -| `Offset` | `long Offset { get; init; }` | Absolute byte offset of the resource within the WIM file. | -| `OriginalSize` | `long OriginalSize { get; init; }` | Uncompressed size of the resource data in bytes. | - -#### `WimWriter` - -Writes a WIM (Windows Imaging) file to a stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WimWriter` | `WimWriter(Stream output, uint compressionType = 1, int chunkSize = 32768)` | Initializes a new `WimWriter`. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IReadOnlyList resources, uint compressionType = 1)` | Creates a WIM file split into multiple volumes. | -| `Write` | `void Write(IReadOnlyList> files)` | Writes a complete WIM file holding one image of the given named files. | -| `Write` | `void Write(IReadOnlyList resources)` | Writes a complete WIM file holding the given resources, naming them `resource_0`, `resource_1` and so on. | - -### Namespace `FileFormat.Wrapster` - -[`WrapsterEntry`](#wrapsterentry) · [`WrapsterFormatDescriptor`](#wrapsterformatdescriptor) · [`WrapsterModifier`](#wrapstermodifier) · [`WrapsterReader`](#wrapsterreader) · [`WrapsterWriter`](#wrapsterwriter) - -#### `WrapsterEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `WrapsterEntry` | `WrapsterEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `WrapsterFormatDescriptor` - -Wrapster container — arbitrary files disguised as an MP3 (v1/v2/v3) for Napster-era sharing. References: Wrapster (ca. 2000) — the defining Napster-era tool; no formal spec ever publishedlayout reverse-engineered from the tool's output (fake MP3 framing + embedded file table) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WrapsterFormatDescriptor` | `WrapsterFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files in a Wrapster archive. Implementation reads all entries, mutates the list, and re-emits the archive — Wrapster's directory references absolute offsets so true random-access is impossible. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the Wrapster archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the Wrapster archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `WrapsterModifier`. | - -#### `WrapsterModifier` - -In-place modifier for Wrapster v2 archives. Wrapster's directory is embedded at the start of the file and references absolute data offsets, so any structural change requires rewriting the directory and shifting data. Implementation reads all entries, mutates the list in memory, and re-emits the archive via `WrapsterWriter`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream wrap, string name, byte[] data)` | Adds (or replaces by name) a file in a Wrapster archive. | -| `RemoveFile` | `static bool RemoveFile(Stream wrap, string name)` | Removes a named entry. Returns true if found. | - -#### `WrapsterReader` - -Reads Wrapster files — data files disguised as MP3 files. Supports v1/v2 ("wrapster" signature) and v3 ("wwapster" signature). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WrapsterReader` | `WrapsterReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Version` | `int Version { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(WrapsterEntry entry)` | | - -#### `WrapsterWriter` - -Creates Wrapster v2 files — data wrapped in fake MP3 frames. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WrapsterWriter` | `WrapsterWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Xar` - -[`XarEntry`](#xarentry) · [`XarFormatDescriptor`](#xarformatdescriptor) · [`XarModifier`](#xarmodifier) · [`XarReader`](#xarreader) · [`XarWriter`](#xarwriter) - -#### `XarEntry` - -Represents a single file entry in a XAR archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XarEntry` | `XarEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | Compressed size in bytes. | -| `FileName` | `string FileName { get; init; }` | File name (path within archive). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether this entry is a directory. | -| `LastModified` | `DateTime? LastModified { get; init; }` | Last modification date. | -| `Method` | `string Method { get; init; }` | Compression method name (e.g., "zlib", "bzip2", "none"). | -| `OriginalSize` | `long OriginalSize { get; init; }` | Uncompressed size in bytes. | - -#### `XarFormatDescriptor` - -eXtensible ARchive (XAR) — gzip-compressed XML table of contents + heap; used by Apple installer packages. References: `https://github.com/mackyle/xar` — maintained xar sources (format documentation in the repository)`https://en.wikipedia.org/wiki/Xar_(archiver)` — Wikipedia overvieworiginally released as an OpenDarwin/Apple open-source project - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XarFormatDescriptor` | `XarFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing XAR archive. Uses `XarModifier` for true random-access I/O — only the header, the compressed XML TOC, the new entry's heap bytes, and (when the TOC changes size) the heap-shift delta are read or written. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the XAR archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the XAR archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing XAR archive. Uses `XarModifier` for random-access I/O on the TOC. | - -#### `XarModifier` - -Random-access in-place modifier for XAR archives. Reads the existing header + compressed XML TOC, mutates the parsed XML, recompresses, and rewrites only the header + new TOC at the start of the file. The heap (raw entry data) is shifted just enough to absorb the change in TOC size — never re-encoded or re-hashed. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream xar, string name, byte[] data, DateTime? lastModified = null)` | Adds a regular file entry to an existing XAR archive. The new entry's data is zlib-compressed and appended to the end of the heap; the TOC is then recompressed and rewritten at the start of the file with the heap shifted by the TOC-size delta. | -| `RemoveFile` | `static bool RemoveFile(Stream xar, string name, bool wipeData = true)` | Removes the named entry from a XAR archive. Returns true if the entry was found and dropped from the TOC. When `wipeData` is true (default) the orphan heap bytes are zeroed in place. The heap itself is not compacted: XAR readers locate entries by explicit ``, so leaving gaps is legal. | - -#### `XarReader` - -Reads XAR (eXtensible ARchive) archives. XAR is Apple's archive format used for .pkg installers. Header: "xar!" magic, header size, version, TOC compressed/uncompressed sizes, checksum algo. TOC is zlib-compressed XML listing all entries. Data is stored in a heap after the TOC. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XarReader` | `XarReader(Stream stream)` | Creates a new XAR reader for the given stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | All entries in the archive. | -| `HeapStart` | `long HeapStart { get; }` | Byte offset where the data heap begins (after header + TOC). | -| `Extract` | `byte[] Extract(XarEntry entry)` | Extracts the data for a given entry. | - -#### `XarWriter` - -Creates XAR (eXtensible ARchive) archives. Entries are zlib-compressed by default. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XarWriter` | `XarWriter(Stream output, bool leaveOpen = false)` | Creates a new XAR writer. | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? modified = null)` | Adds a file to the archive. | -| `Dispose` | `void Dispose()` | Writes the archive and flushes. | - -### Namespace `FileFormat.Xlsx` - -[`XlsxFormatDescriptor`](#xlsxformatdescriptor) - -#### `XlsxFormatDescriptor` - -Office Open XML spreadsheet (.xlsx) — an OPC ZIP package. References: `https://ecma-international.org/publications-and-standards/standards/ecma-376/` — ECMA-376 Office Open XML File Formats (also ISO/IEC 29500)`https://en.wikipedia.org/wiki/Office_Open_XML` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XlsxFormatDescriptor` | `XlsxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing XLSX archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (XLSX is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (XLSX is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Xpi` - -[`XpiFormatDescriptor`](#xpiformatdescriptor) - -#### `XpiFormatDescriptor` - -Mozilla XPI extension package (ZIP-based) for Firefox/Thunderbird. References: `https://extensionworkshop.com/` — Mozilla Extension Workshop — extension packaging documentation`https://en.wikipedia.org/wiki/XPInstall` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XpiFormatDescriptor` | `XpiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing XPI archive. Routes to `ZipModifier` for true random-access I/O — only the central directory, EOCD, and the appended file's local file header + compressed data are read or written. Pre-existing entry LFH + payload bytes at original offsets remain byte-identical. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag delegating to ZIP (XPI is a ZIP variant). | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag delegating to ZIP (XPI is a ZIP variant). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. Delegates to the underlying ZIP reader and wraps the decoded byte buffer in a `BoundedEntryStream` sized to the entry's uncompressed length, so block padding and adjacent entries are physically unreachable through the returned view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZipModifier`. | - -### Namespace `FileFormat.Xz` - -[`XzBuildingBlock`](#xzbuildingblock) · [`XzFormatDescriptor`](#xzformatdescriptor) · [`XzStream`](#xzstream) - -#### `XzBuildingBlock` - -Exposes XZ (LZMA2 inside the .xz container) as a benchmarkable building block. Produces a complete .xz stream — stream header with the magic 0xFD "7zXZ" 0x00, one block carrying the LZMA2 filter chain, the index and the stream footer ending in "YZ" — so the payload is self-terminating and no extra uncompressed-size header is prepended. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XzBuildingBlock` | `XzBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `XzFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XzFormatDescriptor` | `XzFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The tunable XZ knobs: LZMA2 effort level and dictionary size. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `XzStream` - -Stream for reading and writing XZ format data. - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XzStream` | `XzStream(Stream stream, CompressionStreamMode mode, int dictionarySize = 8388608, bool leaveOpen = false)` | Initializes a new `XzStream`. | -| `XzStream` | `XzStream(Stream stream, CompressionStreamMode mode, int dictionarySize, byte checkType, IEnumerable> preFilters, LzmaCompressionLevel level, bool leaveOpen = false)` | Initializes a new `XzStream` with a specific check type, pre-filters and LZMA2 compression level. | -| `XzStream` | `XzStream(Stream stream, CompressionStreamMode mode, int dictionarySize, byte checkType, IEnumerable> preFilters, bool leaveOpen = false)` | Initializes a new `XzStream` with a specific check type and pre-filters. | -| `XzStream` | `XzStream(Stream stream, CompressionStreamMode mode, int dictionarySize, byte checkType, bool leaveOpen = false)` | Initializes a new `XzStream` with a specific check type. | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | - -### Namespace `FileFormat.YEnc` - -[`YEncDecoder`](#yencdecoder) · [`YEncEncoder`](#yencencoder) · [`YEncFormatDescriptor`](#yencformatdescriptor) - -#### `YEncDecoder` - -yEnc binary-to-text decoder for Usenet binary encoding. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static ValueTuple Decode(Stream input)` | Decodes yEnc-encoded data. | - -#### `YEncEncoder` - -yEnc binary-to-text encoder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Encode` | `static void Encode(Stream output, string filename, byte[] data)` | Encodes binary data as yEnc. | - -#### `YEncFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YEncFormatDescriptor` | `YEncFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Yaz0` - -[`Yaz0FormatDescriptor`](#yaz0formatdescriptor) · [`Yaz0Stream`](#yaz0stream) - -#### `Yaz0FormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Yaz0FormatDescriptor` | `Yaz0FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `Yaz0Stream` - -Provides static methods for compressing and decompressing data in the Yaz0 format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses all data from `input` and writes a Yaz0 stream to `output`. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a Yaz0 stream from `input` and writes the uncompressed data to `output`. | - -### Namespace `FileFormat.Ypf` - -[`YpfConstants`](#ypfconstants) · [`YpfCrc32`](#ypfcrc32) · [`YpfEntry`](#ypfentry) · [`YpfFormatDescriptor`](#ypfformatdescriptor) · [`YpfHash`](#ypfhash) · [`YpfReader`](#ypfreader) · [`YpfWriter`](#ypfwriter) - -#### `YpfConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressionStored` | `const byte CompressionStored` | | -| `CompressionZlib` | `const byte CompressionZlib` | | -| `Crc32Polynomial` | `const uint Crc32Polynomial` | | -| `HeaderSize` | `const int HeaderSize` | | -| `Magic` | `static readonly byte[] Magic` | | -| `ReservedSize` | `const int ReservedSize` | | -| `SupportedVersion` | `const uint SupportedVersion` | | -| `TypeUnspecified` | `const byte TypeUnspecified` | | - -#### `YpfCrc32` - -Standard CRC-32 (IEEE 802.3 / zlib polynomial 0xEDB88320). Inlined here because FileFormat.* projects only reference `Compression.Registry`, not `Compression.Core` where the shared (and hardware-accelerated) `Crc32` lives. YPF stores this CRC over the on-disk compressed entry bytes (per spec), so a tiny dependency-free table-driven implementation is sufficient. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compute` | `static uint Compute(ReadOnlySpan data)` | Computes the standard CRC-32 of the given bytes. | - -#### `YpfEntry` - -One entry in a YPF v480 archive. `IsCorrupt` is set by `YpfReader` when the stored CRC doesn't match the recomputed CRC of the on-disk compressed bytes. The reader doesn't throw on CRC mismatch — callers can still extract the bytes and decide what to do. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YpfEntry` | `YpfEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; init; }` | On-disk compressed byte count (equals `RawSize` when stored). | -| `Compression` | `byte Compression { get; init; }` | Compression method: 0=stored, 1=zlib. | -| `Crc32` | `uint Crc32 { get; init; }` | CRC-32 of the on-disk COMPRESSED bytes (per YPF/PSF spec). | -| `IsCorrupt` | `bool IsCorrupt { get; init; }` | True when the recomputed CRC of the on-disk bytes didn't match `Crc32`. | -| `NameHash` | `uint NameHash { get; init; }` | The 32-bit name hash stored in the entry record. Engines use it for fast lookup; we recompute on write but don't validate on read so externally-produced archives load. | -| `Name` | `string Name { get; init; }` | The file name as stored in the entry table (raw ASCII, not deobfuscated). | -| `Offset` | `uint Offset { get; init; }` | Absolute byte offset of this entry's data within the file. | -| `RawSize` | `uint RawSize { get; init; }` | Original (uncompressed) byte count. | -| `Type` | `byte Type { get; init; }` | Type byte: 0=unspecified, 1=script, 2=picture, 3=sound. | - -#### `YpfFormatDescriptor` - -YPF resource archive of the YU-RIS / YukaScript visual-novel engine. References: `https://github.com/morkt/GARbro` — GARbro — implements YPF extraction for the YU-RIS engineYU-RIS engine's packaging format; no official spec, reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YpfFormatDescriptor` | `YpfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the YPF archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the YPF archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `YpfHash` - -32-bit name hash used inside YPF v480 entry records. Real YukaScript readers don't strictly validate this hash, so any deterministic hash works for round-trip self-consistency. We use a simple `h * 0x1003F + lower(c)` rolling hash — case-insensitive so writers don't need to normalize file names. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hash` | `static uint Hash(string name)` | Computes the 32-bit YPF name hash for `name`. | - -#### `YpfReader` - -Reads a YPF v480 archive (YukaScript engine — Yu-No remake, Iyashi VN engine, etc.). Names in real engine archives are XOR-obfuscated against a key derived from the version; for round-trip parity with `YpfWriter` we treat names as raw ASCII. Real engine archives may need a separate deobfuscation pass before being handed to this reader. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YpfReader` | `YpfReader(Stream stream, bool leaveOpen = false)` | Opens a YPF archive from `stream`. | -| `Entries` | `IReadOnlyList Entries { get; }` | All entries parsed from the archive's entry table. | -| `Version` | `uint Version { get; }` | The version field from the header (always 480 for supported archives). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(YpfEntry entry)` | Reads, decompresses, and CRC-checks the bytes for the given entry. | - -#### `YpfWriter` - -Writes a YPF v480 archive. Per spec, the per-entry CRC is computed over the on-disk COMPRESSED bytes (a frequent foot-gun if mistakenly applied to the uncompressed payload). Name hashes are produced via `YpfHash` on raw (non-obfuscated) names so the archive round-trips identically through `YpfReader`. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `YpfWriter` | `YpfWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `YpfWriter` bound to `stream`. | -| `AddEntry` | `void AddEntry(string name, byte[] data, byte type = 0)` | Adds a file to the archive. Compresses with zlib unless that would inflate the payload. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Serializes the header, entry table, and all payloads to the output stream. | - -### Namespace `FileFormat.Zap` - -[`ZapEntry`](#zapentry) · [`ZapFormatDescriptor`](#zapformatdescriptor) · [`ZapReader`](#zapreader) · [`ZapWriter`](#zapwriter) - -#### `ZapEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZapEntry` | `ZapEntry()` | | -| `CompressedSize` | `long CompressedSize { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `ZapFormatDescriptor` - -Amiga ZAP disk archive — LZ77+RLE backward-bitstream disk packer. References: `https://aminet.net/` — Aminet — distribution home of the Amiga ZAP disk archiverno formal spec; format known from the tool's own documentation and depacker sources - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZapFormatDescriptor` | `ZapFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `ZapReader` - -Reads ZAP (Zap disk archiver) Amiga disk images. Each track is independently compressed with LZ77+RLE using a backward bitstream. Magic: "ZAP\0" at offset 0. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZapReader` | `ZapReader(Stream stream, bool leaveOpen = false)` | | -| `ZapMagic` | `static readonly byte[] ZapMagic` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(ZapEntry entry)` | | - -#### `ZapWriter` - -Writes ZAP (Amiga Disk Archiver) images. Tracks are stored uncompressed -- the reader's `IsCompressed = compSize < TrackSize` heuristic treats `compSize == TrackSize` as a stored track and skips the LZ77+RLE backward-bitstream decoder. Implementing the encoder isn't necessary for WORM creation; tracks just round-trip verbatim. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZapWriter` | `ZapWriter()` | | -| `TrackSize` | `const int TrackSize` | | -| `AddTrack` | `void AddTrack(int trackNumber, ReadOnlySpan data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Zip` - -[`ParallelZipCreator`](#parallelzipcreator) · [`ZipCompressionMethod`](#zipcompressionmethod) · [`ZipEncryptionMethod`](#zipencryptionmethod) · [`ZipEntry`](#zipentry) · [`ZipFormatDescriptor`](#zipformatdescriptor) · [`ZipLayoutMap`](#ziplayoutmap) · [`ZipModifier`](#zipmodifier) · [`ZipReader`](#zipreader) · [`ZipWriter`](#zipwriter) - -#### `ParallelZipCreator` - -Parallel ZIP creation: entries are compressed independently in parallel, then written sequentially via `AddRawEntry`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CreateZipParallel` | `static void CreateZipParallel(Stream output, IReadOnlyList inputs, string password, ZipCompressionMethod method, DeflateCompressionLevel level, HashSet incompressible, int maxThreads, ZipEncryptionMethod encryptionMethod = 1)` | Compresses ZIP entries in parallel and writes them sequentially. Only Deflate / Deflate64 / Store benefit from pre-compression; other methods fall through to sequential `AddEntry`. | - -#### `ZipCompressionMethod` - -ZIP compression methods. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Store` | `0` | No compression (store). | -| `Shrink` | `1` | Shrink (LZW with partial clearing). | -| `Reduce1` | `2` | Reduce with compression factor 1. | -| `Reduce2` | `3` | Reduce with compression factor 2. | -| `Reduce3` | `4` | Reduce with compression factor 3. | -| `Reduce4` | `5` | Reduce with compression factor 4. | -| `Implode` | `6` | Implode (LZ77 + Shannon-Fano trees). | -| `Deflate` | `8` | Deflate compression. | -| `Deflate64` | `9` | Deflate64 (Enhanced Deflate) compression. | -| `BZip2` | `12` | BZip2 compression. | -| `Lzma` | `14` | LZMA compression. | -| `Zstd` | `93` | Zstandard compression. | -| `Ppmd` | `98` | PPMd version I, Rev 1 compression. | -| `WinZipAes` | `99` | WinZip AES encryption (actual method stored in extra field). | - -#### `ZipEncryptionMethod` - -ZIP encryption method selection. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `None` | `0` | No encryption. | -| `Aes256` | `1` | WinZip AES-256 encryption (AE-2). | -| `PkzipTraditional` | `2` | Traditional PKZIP encryption (weak, for compatibility). | - -#### `ZipEntry` - -Represents a single entry in a ZIP archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZipEntry` | `ZipEntry()` | | -| `Comment` | `string Comment { get; set; }` | Gets or sets the file comment. | -| `CompressedSize` | `long CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `CompressionMethod` | `ZipCompressionMethod CompressionMethod { get; set; }` | Gets or sets the compression method. | -| `Crc32` | `uint Crc32 { get; set; }` | Gets or sets the CRC-32 of the uncompressed data. | -| `ExternalAttributes` | `uint ExternalAttributes { get; set; }` | Gets or sets the external file attributes. | -| `ExtraField` | `byte[] ExtraField { get; set; }` | Gets or sets the extra field data. | -| `FileName` | `string FileName { get; set; }` | Gets or sets the file name (including path within the archive). | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets whether this entry is a directory. | -| `IsEncrypted` | `bool IsEncrypted { get; set; }` | Gets or sets whether this entry is encrypted. | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last modification date/time. | -| `UncompressedSize` | `long UncompressedSize { get; set; }` | Gets or sets the uncompressed size in bytes. | - -#### `ZipFormatDescriptor` - -ZIP archive — the universal container with per-entry compression methods. References: `https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT` — PKWARE APPNOTE.TXT — the canonical .ZIP file format specification`https://en.wikipedia.org/wiki/ZIP_(file_format)` — Wikipedia overviewInfo-ZIP zip/unzip — long-standing open reference implementations - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFormatDescriptor`, `IFormatOptionsSchema`, `IFormatValidator`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZipFormatDescriptor` | `ZipFormatDescriptor()` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | A ZIP has no fixed media geometry; the single canonical size is the archive's minimal terminated length — the last byte of the end-of-central- directory record (plus its comment). Anything past that is trailing junk. | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ZIP archive. Uses `ZipModifier` for true O(touched bytes) random-access I/O — only the central directory, the EOCD, and the appended file's local file header + compressed data are read or written. | -| `CreateFromStreams` | `void CreateFromStreams(Stream target, IEnumerable inputs, FormatCreateOptions options)` | Large-file-safe streaming variant of `Create` for the STORE method. STORE entries are uncompressed, so the local header can be written with the pre-known `Size` up front and the payload copied in 64 KB chunks while the CRC is computed incrementally and patched back into the header — peak memory is the copy buffer regardless of entry size. Output is byte-identical to `Create` with `Method=store`. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Builds a ZIP archive from `inputs`. Honors all of `FormatCreateOptions`: method, level, dict-size, threads, password, encryption mode, and incompressibility hints. | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts every entry then re-creates the archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts every entry then re-creates the archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. Routed through the bounded `OpenEntry` so the per-entry isolation contract holds uniformly across descriptors. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single ZIP entry as a read-only `Stream` bounded to its uncompressed size. The DEFLATE / store / etc. decoder runs against the entry's local-header bytes, the result is wrapped in a `BoundedEntryStream` sized to `UncompressedSize` so the next entry's bytes — which immediately follow in the source — can never bleed into the returned view even if the underlying decoder over-reads by a chunk boundary. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing ZIP archive. Uses `ZipModifier` for O(touched bytes) random-access I/O. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | Drops any bytes trailing the end-of-central-directory record — tape/disk padding, a stale second EOCD left by an in-place editor, or data appended after the archive was finalized. The central directory, every local file entry and the EOCD (including its comment) are copied through byte-identically, so the shrunk archive lists and extracts identically. When there is no trailing junk the output is byte-identical to the input. | -| `ValidateHeader` | `ValidationResult ValidateHeader(ReadOnlySpan header, long fileSize)` | | -| `ValidateIntegrity` | `ValidationResult ValidateIntegrity(Stream stream)` | | -| `ValidateStructure` | `ValidationResult ValidateStructure(Stream stream)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all dead bytes in the ZIP archive: gaps between local file entries, orphan data left after `RemoveFile`, and any padding regions not covered by the layout map. | - -#### `ZipLayoutMap` - -Walks the ZIP central directory and emits the byte-level layout of every local file header, compressed data payload, the central directory itself, and the EOCD record as `DefragBlockInfo` tiles. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `ZipModifier` - -Random-access in-place modifier for ZIP archives. Reads and writes only the central directory, the EOCD record, and (for new files) the appended local file header + compressed data — never the entire archive payload. Lets callers operate on multi-GB ZIP files without rebuild cost. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream zip, string name, byte[] data, DateTime? lastModified = null)` | Adds a file to an existing ZIP archive, encoding it with Deflate. If an entry with the same name already exists the caller should `RemoveFile` it first; this method just appends. | -| `RemoveFile` | `static bool RemoveFile(Stream zip, string name, bool wipeData = true)` | Removes a named entry from a ZIP archive. Returns true if found and removed. When `wipeData` is true (default) the orphan LFH+data bytes are zeroed; otherwise they remain readable in-place but are no longer referenced by any CD entry. | - -#### `ZipReader` - -Reads entries from a ZIP archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZipReader` | `ZipReader(Stream stream, bool leaveOpen = false, string password = null)` | Initializes a new `ZipReader` from a stream. | -| `Comment` | `string Comment { get; }` | Gets the archive comment. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries in the ZIP archive. | -| `Dispose` | `void Dispose()` | | -| `ExtractEntryRaw` | `ValueTuple ExtractEntryRaw(ZipEntry entry)` | Extracts the raw compressed bytes for an entry without decompressing. Returns the method, CRC-32, uncompressed size, and raw bitstream. Useful for restreaming between formats sharing the same codec (e.g., ZIP Deflate → Gzip). | -| `ExtractEntry` | `byte[] ExtractEntry(ZipEntry entry)` | | -| `OpenEntry` | `Stream OpenEntry(ZipEntry entry)` | Opens a stream to read the decompressed data for an entry. | -| `TryCopyEntryTo` | `bool TryCopyEntryTo(ZipEntry entry, Stream destination)` | Extracts the data for an entry. | - -#### `ZipWriter` - -Creates a ZIP archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZipWriter` | `ZipWriter(Stream stream, bool leaveOpen = false, DeflateCompressionLevel compressionLevel = 6, string password = null, ZipEncryptionMethod encryptionMethod = 1)` | Initializes a new `ZipWriter`. | -| `Bzip2BlockSize` | `int Bzip2BlockSize { get; set; }` | BZip2 block size multiplier 1-9 (N × 100 KB). Used when method is BZip2. | -| `Comment` | `string Comment { get; set; }` | Gets or sets the archive comment. | -| `LzmaDictionarySize` | `int LzmaDictionarySize { get; set; }` | LZMA dictionary size in bytes (4096 to 1GB). Used when method is LZMA. | -| `LzmaLevel` | `LzmaCompressionLevel LzmaLevel { get; set; }` | LZMA compression level. Used when method is LZMA. | -| `PpmdMemorySizeMB` | `int PpmdMemorySizeMB { get; set; }` | PPMd memory size in megabytes (1-256). Used when method is PPMd. | -| `PpmdOrder` | `int PpmdOrder { get; set; }` | PPMd model order (2-16). Used when method is PPMd. | -| `AddDirectory` | `void AddDirectory(string name, DateTime? lastModified = null)` | Adds a directory entry. | -| `AddEntry` | `void AddEntry(string fileName, byte[] data, ZipCompressionMethod method = 8, DateTime? lastModified = null)` | Adds a file entry from a byte array. | -| `AddRawEntry` | `void AddRawEntry(string fileName, byte[] compressedData, ZipCompressionMethod method, uint crc32, long uncompressedSize, DateTime? lastModified = null)` | Adds a pre-compressed entry. The data is already compressed and will not be re-compressed. Useful for restreaming between formats (e.g., Gzip → ZIP) or for injecting optimally-compressed data. | -| `AddStreamingStoredEntry` | `void AddStreamingStoredEntry(string fileName, long size, Stream data, DateTime? lastModified = null)` | Adds a STORE (uncompressed) entry whose payload is streamed from `data` in bounded 64 KB chunks rather than buffered into RAM. The local file header is written up front with the pre-known `size` (STORE ⇒ compressed size = uncompressed size) and a placeholder CRC, the payload is copied while the CRC is computed incrementally, and the 4-byte CRC field in the just-written header is patched in place. Peak memory is the 64 KB copy buffer regardless of `size`. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries, ZipCompressionMethod method = 8, string password = null)` | Creates a ZIP archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the central directory and finishes the archive. | - -### Namespace `FileFormat.Zlib` - -[`ZlibConstants`](#zlibconstants) · [`ZlibFormatDescriptor`](#zlibformatdescriptor) · [`ZlibRawHelper`](#zlibrawhelper) · [`ZlibStream`](#zlibstream) - -#### `ZlibConstants` - -Constants for the zlib compressed data format (RFC 1950). - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressionMethodDeflate` | `const int CompressionMethodDeflate` | Deflate compression method identifier. | -| `DefaultWindowBits` | `const int DefaultWindowBits` | Default window size exponent (15 → 32 KB window). | -| `HeaderSize` | `const int HeaderSize` | Size of the zlib header in bytes (CMF + FLG). | -| `LevelDefault` | `const int LevelDefault` | Compressor used default algorithm. | -| `LevelFast` | `const int LevelFast` | Compressor used fast algorithm. | -| `LevelFastest` | `const int LevelFastest` | Compressor used fastest algorithm. | -| `LevelMaximum` | `const int LevelMaximum` | Compressor used maximum compression. | -| `TrailerSize` | `const int TrailerSize` | Size of the Adler-32 trailer in bytes. | - -#### `ZlibFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZlibFormatDescriptor` | `ZlibFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The Deflate compression level applied to the Zlib payload. The optimizer searches these tiers to find the smallest output for the input. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `ZlibRawHelper` - -Low-level helpers for working with raw Deflate bitstreams inside Zlib framing. Enables zero-decompression restreaming between formats sharing the Deflate codec. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Unwrap` | `static ValueTuple Unwrap(ReadOnlySpan zlibData)` | Extracts the raw Deflate bitstream from Zlib data without decompressing. Also returns the Adler-32 checksum from the trailer. | -| `Wrap` | `static byte[] Wrap(ReadOnlySpan deflateData, uint adler32)` | Wraps a raw Deflate bitstream in Zlib framing. The caller must provide the Adler-32 of the uncompressed data. | - -#### `ZlibStream` - -Compresses and decompresses data in the zlib format (RFC 1950). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static byte[] Compress(ReadOnlySpan data, DeflateCompressionLevel level = 6)` | Compresses a byte span to zlib format. | -| `Compress` | `static void Compress(Stream input, Stream output, DeflateCompressionLevel level = 6, int windowBits = 15)` | Compresses data to zlib format. | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan data)` | Decompresses zlib-formatted data from a byte span. | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses zlib-formatted data. | - -### Namespace `FileFormat.Zling` - -[`ZlingFormatDescriptor`](#zlingformatdescriptor) · [`ZlingStream`](#zlingstream) - -#### `ZlingFormatDescriptor` - -Implements `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZlingFormatDescriptor` | `ZlingFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | - -#### `ZlingStream` - -Zling: ROLZ + Huffman block compressor by Zhang Li. Format: blocks of (uint8 flag, uint32 LE encpos, uint32 LE rlen, uint32 LE olen, olen bytes). flag=1 means more data follows, flag=0 is the final block. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | - -### Namespace `FileFormat.Zoo` - -[`ZooCompressionMethod`](#zoocompressionmethod) · [`ZooConstants`](#zooconstants) · [`ZooEntry`](#zooentry) · [`ZooFormatDescriptor`](#zooformatdescriptor) · [`ZooModifier`](#zoomodifier) · [`ZooReader`](#zooreader) · [`ZooWriter`](#zoowriter) - -#### `ZooCompressionMethod` - -Compression method used for a `ZooEntry`. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Store` | `0` | File data is stored verbatim with no compression. | -| `Lzw` | `1` | File data is compressed using LZW (9–13 bit, LSB-first). | - -#### `ZooConstants` - -Constants for the Zoo archive format. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ArchiveHeaderSize` | `const int ArchiveHeaderSize` | Total size in bytes of the archive header. | -| `DefaultHeaderText` | `const string DefaultHeaderText` | Default archive header text (ASCII, null-terminated, padded to 20 bytes). | -| `DirectoryEntryFixedSize` | `const int DirectoryEntryFixedSize` | Size in bytes of the fixed part of a directory entry (before the filename). Covers: tag(4) + type(1) + method(1) + nextOffset(4) + dataOffset(4) + date(2) + time(2) + crc16(2) + origSize(4) + compSize(4) + majorVer(1) + minorVer(1) + deleted(1) + structure(1) + commentOffset(4) + commentLength(2) = 38 bytes. | -| `LzwMaxBits` | `const int LzwMaxBits` | Maximum LZW code width in bits (standard Zoo). | -| `LzwMinBits` | `const int LzwMinBits` | Initial LZW code width in bits. | -| `Magic` | `const uint Magic` | Magic number present in the archive header and every directory entry (0xFDC4A7DC). | -| `MajorVersion` | `const byte MajorVersion` | Major version number written into headers created by this library. | -| `MaxShortNameLength` | `const int MaxShortNameLength` | Maximum short filename length (13 bytes including null terminator, so 12 characters). | -| `MethodLzw` | `const byte MethodLzw` | Compression method: file is compressed with LZW (variable-width, 9–13 bits, LSB-first). | -| `MethodStore` | `const byte MethodStore` | Compression method: file is stored without compression. | -| `MinorVersion` | `const byte MinorVersion` | Minor version number written into headers created by this library. | -| `TypeFile` | `const byte TypeFile` | Entry type for a standard file entry. | -| `TypeLongName` | `const byte TypeLongName` | Entry type for a file entry that carries a long (extended) filename. | - -#### `ZooEntry` - -Represents a single file entry in a Zoo archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZooEntry` | `ZooEntry()` | | -| `CompressedSize` | `uint CompressedSize { get; set; }` | Gets or sets the compressed size in bytes. | -| `CompressionMethod` | `ZooCompressionMethod CompressionMethod { get; set; }` | Gets or sets the compression method. | -| `Crc16` | `ushort Crc16 { get; set; }` | Gets or sets the CRC-16 (ARC polynomial) of the uncompressed data. | -| `EffectiveName` | `string EffectiveName { get; }` | Gets the effective display name: `LongFileName` when available, otherwise `FileName`. | -| `FileName` | `string FileName { get; set; }` | Gets or sets the short filename (up to 12 characters, DOS 8.3 style). | -| `IsDeleted` | `bool IsDeleted { get; set; }` | Gets or sets whether this entry has been marked as deleted. | -| `LastModified` | `DateTime LastModified { get; set; }` | Gets or sets the last-modification date/time. | -| `LongFileName` | `string LongFileName { get; set; }` | Gets or sets the long filename. When non-null and non-empty the entry is written as type 2 (long-name entry); otherwise it is written as type 1. | -| `MajorVersion` | `byte MajorVersion { get; set; }` | Gets or sets the major version of the tool that created the entry. | -| `MinorVersion` | `byte MinorVersion { get; set; }` | Gets or sets the minor version of the tool that created the entry. | -| `OriginalSize` | `uint OriginalSize { get; set; }` | Gets or sets the uncompressed size in bytes. | - -#### `ZooFormatDescriptor` - -Zoo archive — early DOS/Unix compressor by Rahul Dhesi (LZW/LZH methods). References: `https://en.wikipedia.org/wiki/Zoo_(file_format)` — Wikipedia overviewRahul Dhesi's zoo 2.10 sources — the defining implementation (widely mirrored) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZooFormatDescriptor` | `ZooFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Zoo archive. Uses `ZooModifier` — Add walks the linked-list chain to the tail, writes a Stored entry at end-of-stream, and patches the previous tail's `nextOffset` link. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the Zoo archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the Zoo archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single Zoo entry as a bounded read-only `Stream`. The reader's per-entry extractor returns the fully-decompressed bytes; they are wrapped in a `BoundedEntryStream` sized to the entry's original size. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries; uses `ZooModifier`. | - -#### `ZooModifier` - -Random-access in-place modifier for Zoo archives. Zoo entries are linked together via an explicit `nextOffset` field in each directory header (the archive header at offset 0 carries `firstEntryOffset` at byte 24); the chain terminates with `nextOffset = 0`. Add walks to the tail entry, writes a new Stored entry at end-of-stream, and patches the previous tail's `nextOffset` (or `firstEntryOffset` for an empty archive) to point at the new header. Remove walks to find the target, shifts trailing bytes forward to compact, then rewrites all affected `nextOffset` / `dataOffset` link fields whose values pointed past the removed region. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream zoo, string name, byte[] data)` | Appends a Stored entry to the archive. Walks the directory chain to find the tail, writes a fresh entry at end-of-stream, and patches the previous-tail's `nextOffset` link (or `firstEntryOffset` if the archive was empty) to point at the new entry. | -| `RemoveFile` | `static bool RemoveFile(Stream zoo, string name, bool wipeData = true)` | Removes the named entry by unlinking it and compacting. Returns true when the entry was found. Walks the chain, shifts trailing bytes forward by the removed entry's size, then rewrites every `nextOffset` / `dataOffset` field whose value originally pointed past the removed region (those targets all moved by the same fixed delta). | - -#### `ZooReader` - -Reads entries from a Zoo archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZooReader` | `ZooReader(Stream stream, bool leaveOpen = false)` | Initializes a new `ZooReader` and reads the directory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries present in the archive (deleted entries are included; check `IsDeleted`). | -| `Dispose` | `void Dispose()` | | -| `ExtractEntry` | `byte[] ExtractEntry(ZooEntry entry)` | Extracts and decompresses the data for an entry. | - -#### `ZooWriter` - -Creates a Zoo archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZooWriter` | `ZooWriter(Stream stream, bool leaveOpen = false, ZooCompressionMethod defaultMethod = 1)` | Initializes a new `ZooWriter`. | -| `AddEntry` | `void AddEntry(string fileName, byte[] data, ZooCompressionMethod? method = null, DateTime? lastModified = null)` | Adds a file entry to the archive. | -| `CreateSplit` | `static byte[][] CreateSplit(long maxVolumeSize, IEnumerable> entries)` | Creates a Zoo archive split into multiple volumes. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Finalises the archive by patching all `nextOffset` chain pointers. Must be called (or the writer disposed) for a valid archive. | - -### Namespace `FileFormat.Zpaq` - -[`Component`](#component) · [`ComponentType`](#componenttype) · [`ZpaqBuildingBlock`](#zpaqbuildingblock) · [`ZpaqConstants`](#zpaqconstants) · [`ZpaqEntry`](#zpaqentry) · [`ZpaqFormatDescriptor`](#zpaqformatdescriptor) · [`ZpaqRangeCoder`](#zpaqrangecoder) · [`ZpaqRangeDecoder`](#zpaqrangedecoder) · [`ZpaqRangeEncoder`](#zpaqrangeencoder) · [`ZpaqReader`](#zpaqreader) · [`ZpaqWriter`](#zpaqwriter) · [`ZpaqlVm`](#zpaqlvm) - -#### `Component` - -Represents a single prediction component in the ZPAQL context-mixing model. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Component` | `Component()` | | -| `Aux` | `int Aux { get; set; }` | Auxiliary state (match length, mixer weights, etc.). | -| `Context` | `int Context { get; set; }` | Current hashed context value. | -| `Memory` | `int[] Memory { get; set; }` | Component memory (CM counters, ICM byte histories, etc.). | -| `Param1` | `int Param1 { get; set; }` | First parameter (meaning depends on type, e.g. log2 of table size). | -| `Param2` | `int Param2 { get; set; }` | Second parameter (meaning depends on type). | -| `Param3` | `int Param3 { get; set; }` | Third parameter (meaning depends on type). | -| `Prediction` | `int Prediction { get; set; }` | Current prediction (0..65535, probability of next bit being 1). | -| `Type` | `ComponentType Type { get; set; }` | The component type. | - -#### `ComponentType` - -Component type identifiers for the ZPAQL context-mixing prediction model. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Const` | `0` | Constant prediction (always predicts 50/50). | -| `Cm` | `1` | Context model — 2^n counters indexed by hashed context. | -| `Icm` | `2` | Indirect context model — byte history maps to a counter. | -| `Match` | `3` | Match model — predicts by finding a previous matching context. | -| `Avg` | `4` | Average of two component predictions. | -| `Mix2` | `5` | Two-input adaptive mixer. | -| `Mix` | `6` | N-input adaptive mixer. | -| `Isse` | `7` | Indirect secondary symbol estimation. | -| `Sse` | `8` | Direct secondary symbol estimation. | - -#### `ZpaqBuildingBlock` - -Exposes the ZPAQ context-mixing codec — the compression stage that the ZPAQ journaling archiver wraps — as a benchmarkable building block. Prepends a 4-byte LE uncompressed size header for round-trip support. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqBuildingBlock` | `ZpaqBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ZpaqConstants` - -Constants for the ZPAQ archive format (level 1 journaling). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BlockTypeCompressed` | `const byte BlockTypeCompressed` | Block type byte: compressed data block (contains ZPAQL program + compressed payload). | -| `BlockTypeData` | `const byte BlockTypeData` | Block type byte: data block in a journaling transaction. Each data block holds the (ZPAQL-compressed) payload for one or more files. | -| `BlockTypeHeader` | `const byte BlockTypeHeader` | Block type byte: comment/filename header block in a journaling transaction. In a level-1 journaling archive this block carries the transaction date, filenames and per-file attributes for one transaction. | -| `BlockTypeIndex` | `const byte BlockTypeIndex` | Block type byte: hash/index block that closes a journaling transaction. Contains SHA-1 hashes of the uncompressed file data. | -| `FileTimeSize` | `const int FileTimeSize` | Size of the Windows FILETIME timestamp stored in journaling header blocks (8 bytes). | -| `Level1` | `const byte Level1` | Compression level byte for ZPAQ level 1 archives. | -| `Level2` | `const byte Level2` | Compression level byte for ZPAQ level 2 archives. | -| `MinBlockHeaderSize` | `const int MinBlockHeaderSize` | Minimum number of bytes in a valid block header (3-byte prefix + 1 level byte + 1 type byte = 5 bytes). | -| `WindowsToUnixEpochTicks` | `const long WindowsToUnixEpochTicks` | Windows FILETIME ticks (100-nanosecond intervals) from the Windows epoch (1601-01-01) to the Unix epoch (1970-01-01), used when converting timestamps. | -| `BlockPrefix` | `static ReadOnlySpan BlockPrefix { get; }` | The 3-byte block locator prefix present at the start of every ZPAQ block ("zPQ"). | - -#### `ZpaqEntry` - -Represents a single file entry recorded in a ZPAQ journaling archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressedSize` | `long CompressedSize { get; }` | Gets the compressed size of the data block(s) that carry this file's data. This is the total byte count of the raw (still-compressed) data blocks associated with this entry. | -| `FileName` | `string FileName { get; }` | Gets the filename as stored in the archive. Path separators are always forward slashes; directory entries end with '/'. | -| `IsDirectory` | `bool IsDirectory { get; }` | Gets a value indicating whether this entry represents a directory. | -| `LastModified` | `DateTime? LastModified { get; }` | Gets the last-modified timestamp decoded from the journal header, or `null` when the timestamp could not be recovered. | -| `Size` | `long Size { get; }` | Gets the uncompressed size of the file in bytes as reported by the archive. This value is zero for directory entries and for files whose size could not be determined from the journal (e.g. when the header block is compressed). | -| `Version` | `int Version { get; }` | Gets the zero-based transaction index in which this entry was recorded. Each append to a ZPAQ archive constitutes a new transaction; the most recent transaction with a given filename defines the file's current state. | - -#### `ZpaqFormatDescriptor` - -ZPAQ journaling archive with content-defined deduplication and configurable context-mixing compression. References: `http://mattmahoney.net/dc/zpaq.html` — official ZPAQ page and Level 2 format specification (Matt Mahoney)`https://github.com/zpaq/zpaq` — reference implementation`https://en.wikipedia.org/wiki/ZPAQ` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqFormatDescriptor` | `ZpaqFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the ZPAQ archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the ZPAQ archive per the requested mode. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `ZpaqRangeCoder` - -Shared constants and the safety argument of the ZPAQ binary range coder. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CarryEdge` | `const uint CarryEdge` | Value at or above which the top byte of `low` may still be bumped by a carry. | -| `FlushBytes` | `const int FlushBytes` | Number of `low` bytes the encoder pushes out when the message ends. | -| `MaximumProbability` | `const int MaximumProbability` | Largest probability of a 1 bit the coder accepts. | -| `MinimumProbability` | `const int MinimumProbability` | Smallest probability of a 1 bit the coder accepts. | -| `ProbabilityBits` | `const int ProbabilityBits` | Number of fractional bits in a probability, so probabilities span 0..2^16. | -| `RangeMinimum` | `const uint RangeMinimum` | Lower bound of the normalised range; the coder renormalises below this. | -| `Split` | `static uint Split(uint range, int probabilityOfOne)` | Computes the split point between the 1 subrange and the 0 subrange. | - -#### `ZpaqRangeDecoder` - -Carry-propagating binary range decoder, the exact mirror of `ZpaqRangeEncoder`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqRangeDecoder` | `ZpaqRangeDecoder(byte[] input, int offset)` | Creates a decoder reading from the given buffer, priming its code word from the first `FlushBytes` bytes. | -| `Range` | `uint Range { get; }` | Gets the current range, for tests that assert the coder invariant. | -| `DecodeBit` | `int DecodeBit(int probabilityOfOne)` | Decodes one bit against the given probability. | - -#### `ZpaqRangeEncoder` - -Carry-propagating binary range encoder. See `ZpaqRangeCoder` for the invariant that keeps both subranges non-empty. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqRangeEncoder` | `ZpaqRangeEncoder(Stream output)` | Creates an encoder writing its bytes to the given stream. | -| `Range` | `uint Range { get; }` | Gets the current range, for tests that assert the coder invariant. | -| `EncodeBit` | `void EncodeBit(int bit, int probabilityOfOne)` | Codes one bit against the given probability. | -| `Flush` | `void Flush()` | Pushes out the remaining bytes of `low`, ending the coded stream. | - -#### `ZpaqReader` - -Reads the journaling index of a ZPAQ archive, exposing the files recorded across all transactions. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqReader` | `ZpaqReader(Stream stream, bool leaveOpen = false)` | Opens a ZPAQ archive stream and scans its journal. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets the entries discovered by scanning the archive journal. The list reflects the last recorded state of each file across all transactions (i.e. later transactions that mention the same filename supersede earlier ones in the final view). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `Stream Extract(ZpaqEntry entry)` | Returns the entry's uncompressed bytes as a stream when the data block was STORED (the layout this toolkit's `ZpaqWriter` emits). | - -#### `ZpaqWriter` - -Writes a ZPAQ level-1 journaling archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqWriter` | `ZpaqWriter(Stream stream, bool leaveOpen = false)` | Initializes a new ZPAQ writer that writes to the specified stream. | -| `AddDirectory` | `void AddDirectory(string dirName, DateTime? lastModified = null)` | Adds a directory entry to the archive. | -| `AddFile` | `void AddFile(string fileName, byte[] data, DateTime? lastModified = null)` | Adds a file entry to the archive with the given name and data. | -| `Dispose` | `void Dispose()` | | - -#### `ZpaqlVm` - -ZPAQL virtual machine for ZPAQ compression and decompression. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZpaqlVm` | `ZpaqlVm(ReadOnlySpan program)` | Parses a ZPAQL program header from a binary span and constructs the VM. | -| `ZpaqlVm` | `ZpaqlVm(byte[] hcomp, byte[] pcomp, int hh, int hm, Component[] components = null)` | Creates a ZPAQL VM with the specified program and component configuration. | -| `A` | `uint A { get; set; }` | Gets or sets register A (32-bit accumulator). | -| `B` | `uint B { get; set; }` | Gets or sets register B (32-bit, also indexes M[]). | -| `C` | `uint C { get; set; }` | Gets or sets register C (32-bit, also indexes M[]). | -| `Components` | `Component[] Components { get; }` | Gets the context-mixing components. | -| `D` | `uint D { get; set; }` | Gets or sets register D (32-bit, also indexes M[]). | -| `F` | `bool F { get; set; }` | Gets or sets the flag register (1-bit). | -| `H` | `uint[] H { get; }` | Gets the H[] context array. H values are set by the HCOMP program and used as context indices for the prediction components. | -| `M` | `byte[] M { get; }` | Gets the M[] byte array used by the HCOMP/PCOMP programs. | -| `OutputByte` | `Action OutputByte { get; set; }` | Event invoked when the PCOMP program executes an OUT instruction. | -| `Predict` | `int Predict()` | Computes a combined prediction from all components. | -| `Reset` | `void Reset()` | Resets the VM state (registers, arrays, components) without changing the program or component configuration. | -| `RunHcomp` | `void RunHcomp(int input)` | Executes the HCOMP program with the given input byte. This should be called after each decoded byte to update the context hashes in H[]. | -| `RunPcomp` | `void RunPcomp(int input)` | Executes the PCOMP (post-processing) program with the given input byte. | -| `Squash` | `static int Squash(int x)` | Squash function: maps a logistic value (-2048..2047) to a probability (0..65535). squash(x) = 65536 / (1 + exp(-x / 64)). | -| `Stretch` | `static int Stretch(int p)` | Stretch function: inverse of squash, maps probability (1..65534) to logistic. | -| `Update` | `void Update(int bit)` | Updates all components after a decoded bit. | - -### Namespace `FileFormat.Zstd` - -[`ZstdBuildingBlock`](#zstdbuildingblock) · [`ZstdCompressionLevel`](#zstdcompressionlevel) · [`ZstdFormatDescriptor`](#zstdformatdescriptor) · [`ZstdStream`](#zstdstream) - -#### `ZstdBuildingBlock` - -Exposes Zstandard as a benchmarkable building block. Produces a spec-compliant Zstandard frame (magic 0xFD2FB528, frame header, data blocks, content checksum), so the payload is self-terminating and no extra uncompressed-size header is prepended. - -Implements `IBuildingBlock`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZstdBuildingBlock` | `ZstdBuildingBlock()` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `Compress` | `byte[] Compress(ReadOnlySpan data)` | | -| `Decompress` | `byte[] Decompress(ReadOnlySpan data)` | | - -#### `ZstdCompressionLevel` - -Compression level for Zstandard. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Fastest` | `1` | Fastest compression: chain depth 4. | -| `Fast` | `3` | Fast compression: chain depth 16. | -| `Default` | `6` | Default compression: chain depth 64. | -| `Best` | `9` | Best compression: chain depth 128. | - -#### `ZstdFormatDescriptor` - -Implements `IFormatDescriptor`, `IFormatOptionsSchema`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZstdFormatDescriptor` | `ZstdFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Compression level 1..9 (higher = smaller/slower). The optimizer searches these to find the smallest output for the given input. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CompressOptimal` | `void CompressOptimal(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Compress` | `void Compress(Stream input, Stream output, FormatCreateOptions options)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `WrapCompress` | `Stream WrapCompress(Stream output)` | | -| `WrapDecompress` | `Stream WrapDecompress(Stream input)` | | - -#### `ZstdStream` - -Stream for reading and writing Zstandard (zstd) compressed data (RFC 8878). Wraps an underlying stream and provides transparent compression or decompression. - -Inherits `CompressionStream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ZstdStream` | `ZstdStream(Stream stream, CompressionStreamMode mode, ZstdCompressionLevel level, bool leaveOpen = false, ZstdDictionary dictionary = null)` | Initializes a new `ZstdStream` with a typed compression level. | -| `ZstdStream` | `ZstdStream(Stream stream, CompressionStreamMode mode, int compressionLevel = 3, bool leaveOpen = false, ZstdDictionary dictionary = null)` | Initializes a new `ZstdStream`. | -| `CompressBlock` | `protected override void CompressBlock(byte[] buffer, int offset, int count)` | | -| `DecompressBlock` | `protected override int DecompressBlock(byte[] buffer, int offset, int count)` | | -| `FinishCompression` | `protected override void FinishCompression()` | | +Every public and protected member of all 794 types, generated from the built assembly and its XML documentation, is in [REFERENCE.md](https://github.com/Hawkynt/CompressionWorkbench/blob/main/Hawkynt.FileFormats.Archives/REFERENCE.md). diff --git a/Hawkynt.FileFormats.Audio/README.md b/Hawkynt.FileFormats.Audio/README.md index 25c34af63..4cf9a4f8c 100644 --- a/Hawkynt.FileFormats.Audio/README.md +++ b/Hawkynt.FileFormats.Audio/README.md @@ -357,1672 +357,7 @@ The audio package is built against the repository's shared Core version and shou -### Namespace `Codec.ALaw` - -[`ALawCodec`](#alawcodec) - -#### `ALawCodec` - -G.711 A-law codec: 8-bit logarithmic samples decoded to 16-bit linear PCM. European-style companding used in WAV format code 6 and AIFC `alaw`/`ALAW`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecodeSample` | `static short DecodeSample(byte a)` | Decodes one A-law byte to a 16-bit signed linear sample. Based on the ITU-T G.711 reference implementation (toggle every even bit, extract sign/exponent/mantissa, apply bias, then shift by exponent). | -| `Decode` | `static short[] Decode(ReadOnlySpan alaw)` | Decodes a full A-law byte buffer to 16-bit linear PCM. | -| `EncodeSample` | `static byte EncodeSample(short pcm)` | Encodes one 16-bit signed linear sample to an A-law byte (used for test round-trip). | -| `Encode` | `static byte[] Encode(ReadOnlySpan pcm)` | Encodes a 16-bit linear PCM buffer to A-law bytes (used for tests). | - -### Namespace `Codec.Aac` - -[`AacAdtsReader`](#aacadtsreader) · [`AacBitReader`](#aacbitreader) · [`AacCodec`](#aaccodec) · [`AacDecoder`](#aacdecoder) · [`AacElementType`](#aacelementtype) · [`AacObjectType`](#aacobjecttype) · [`AacStreamInfo`](#aacstreaminfo) · [`AdtsHeader`](#adtsheader) - -#### `AacAdtsReader` - -Parser for ADTS (Audio Data Transport Stream) framing as defined by ISO/IEC 13818-7 §5.4.1. ADTS wraps raw AAC frames in a self-synchronising header with a 12-bit sync word (`0xFFF`), sample-rate index, channel configuration and frame length. - -| Member | Signature | Summary | -| --- | --- | --- | -| `LongHeaderLength` | `const int LongHeaderLength` | ADTS header length with CRC (protection absent=0). | -| `SampleRateTable` | `static readonly int[] SampleRateTable` | Sample-rate lookup (indices 0..12). Indices 13..14 are reserved, 15 is explicit. | -| `ShortHeaderLength` | `const int ShortHeaderLength` | Minimum ADTS header length (protection absent=1, no CRC). | -| `BuildHeader` | `static byte[] BuildHeader(int profile, int sampleRateIndex, int channelConfig, int frameLength, bool mpeg2 = false, int bufferFullness = 2047, int numRawBlocks = 0)` | Builds a 7-byte ADTS header with the given fields (used by tests). | -| `ParseHeader` | `static AdtsHeader ParseHeader(ReadOnlySpan buffer, int offset = 0)` | Parses a 7- or 9-byte ADTS header starting at `offset` in `buffer`. Throws `InvalidDataException` if the sync word or layer bits don't match. | - -#### `AacBitReader` - -MSB-first bit reader used for AAC/ADTS parsing. Bits are consumed from the most significant bit of each byte downwards, matching the order specified by ISO/IEC 14496-3 (AAC) and ISO/IEC 13818-7 (ADTS). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AacBitReader` | `AacBitReader(byte[] data)` | | -| `AacBitReader` | `AacBitReader(byte[] data, int offset, int length)` | | -| `BitsRemaining` | `long BitsRemaining { get; }` | Total bits remaining in the stream. | -| `BytePosition` | `int BytePosition { get; }` | Current byte position, rounded up if any bits have been consumed in the current byte. | -| `ByteAlign` | `void ByteAlign()` | Aligns to the next byte boundary, if not already aligned. | -| `PeekBits` | `uint PeekBits(int count)` | Peeks `count` bits (1..32) without advancing the cursor. | -| `ReadBits` | `uint ReadBits(int count)` | Reads `count` bits (1..32) MSB-first and returns them right-aligned. | -| `SkipBits` | `void SkipBits(int count)` | Skips `count` bits (may be larger than 32). | - -#### `AacCodec` - -Top-level AAC-LC decoder. Wraps an `AacAdtsReader` for framing and an `AacDecoder` for raw_data_block decoding. Output is interleaved little-endian signed 16-bit PCM. Supported: AAC-LC (object type 2) in ADTS framing, mono & stereo, standard sample rates 8 kHz – 48 kHz. Not supported (raises `NotSupportedException` with a clear message): HE-AAC (SBR), HE-AAC v2 (PS), Main/SSR/LTP profiles, ER profiles, MPEG-2 raw, xHE-AAC / USAC, >2 channels, ADIF / LATM / LOAS framing. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an AAC ADTS stream into interleaved little-endian signed 16-bit PCM on `output`. | -| `ParseAudioSpecificConfig` | `static ValueTuple ParseAudioSpecificConfig(ReadOnlySpan asc)` | Inspects the AudioSpecificConfig (used by MP4-in-ISOBMFF and LATM) and rejects HE-AAC / PS / non-LC explicitly. Returns the parsed object type and sample rate index for callers that need them. | -| `ReadCoreSampleRate` | `static int ReadCoreSampleRate(Stream input)` | The base (core) sample rate of an AAC stream — never SBR-doubled. | -| `ReadStreamInfo` | `static AacStreamInfo ReadStreamInfo(Stream input)` | Reads the first ADTS header to surface stream-level metadata without decoding any audio. Useful for archive-descriptor probes. | - -#### `AacDecoder` - -Decoder for the AAC raw_data_block (RDB). Iterates over the syntactic elements (SCE/CPE/LFE/CCE/DSE/PCE/FIL/END) inside one RDB, decoding the AAC-LC core (no SBR/PS) into interleaved 16-bit PCM. CCE is rejected (NotSupported); DSE, PCE and FIL (including any SBR extension payload) are parsed and skipped. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AacDecoder` | `AacDecoder(AacObjectType objectType, int sampleRateIndex, int channelConfiguration)` | Constructs a decoder configured for the given header parameters. | -| `Channels` | `int Channels { get; }` | Channels in the output PCM (1 for mono, 2 for stereo). | -| `CoreSampleRate` | `int CoreSampleRate { get; }` | The base (core) sample rate of the stream in Hz. | -| `EffectiveSampleRate` | `int EffectiveSampleRate { get; }` | The effective output sample rate: doubled when SBR has been detected, otherwise the core rate. SBR reconstruction is gated, so the emitted PCM is still the core band — this value reflects the bitstream's signalled bandwidth. | -| `FrameSamplesPerChannel` | `int FrameSamplesPerChannel { get; }` | The number of decoded PCM samples per channel per AAC frame (always 1024 for LC). | -| `SbrDetected` | `bool SbrDetected { get; }` | True once an SBR (Spectral Band Replication) extension with a valid header has been observed. HE-AAC streams report their core sample rate doubled; the PCM itself remains the AAC-LC core band (SBR reconstruction is gated, see `AacSbr`). | -| `DecodeRawDataBlock` | `short[] DecodeRawDataBlock(AacBitReader reader)` | Decodes a single raw_data_block, returning interleaved 16-bit PCM (one frame: `FrameSamplesPerChannel` samples × `Channels`). | - -#### `AacElementType` - -AAC element type identifiers (3-bit syntactic element id, ISO/IEC 14496-3 §4.5.2.1). - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Sce` | `0` | Single channel element (mono channel). | -| `Cpe` | `1` | Channel pair element (stereo). | -| `Cce` | `2` | Coupling channel element. | -| `Lfe` | `3` | LFE (low-frequency effects) channel. | -| `Dse` | `4` | Data stream element. | -| `Pce` | `5` | Program config element. | -| `Fil` | `6` | Fill element. | -| `End` | `7` | End of raw_data_block. | - -#### `AacObjectType` - -AAC MPEG Audio Object Types (subset). Values match ISO/IEC 14496-3 Table 1.16. ADTS stores this minus 1 in its 2-bit `profile` field. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Null` | `0` | | -| `AacMain` | `1` | | -| `AacLc` | `2` | | -| `AacSsr` | `3` | | -| `AacLtp` | `4` | | -| `Sbr` | `5` | | -| `AacScalable` | `6` | | -| `TwinVQ` | `7` | | -| `Celp` | `8` | | -| `Hvxc` | `9` | | -| `Er_AacLc` | `17` | | -| `Er_AacLtp` | `19` | | -| `Er_AacScalable` | `20` | | -| `Ps` | `29` | | - -#### `AacStreamInfo` - -Stream-level information about an AAC bitstream extracted from its first frame header (ADTS) or AudioSpecificConfig (raw / MP4). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AacStreamInfo` | `AacStreamInfo(int SampleRate, int Channels, int Profile, long DurationSamples, bool Sbr = false)` | Stream-level information about an AAC bitstream extracted from its first frame header (ADTS) or AudioSpecificConfig (raw / MP4). | -| `Channels` | `int Channels { get; init; }` | Number of decoded PCM channels (1 or 2 for AAC-LC mono/stereo). | -| `DurationSamples` | `long DurationSamples { get; init; }` | Estimated total decoded samples per channel (-1 if unknown). | -| `Profile` | `int Profile { get; init; }` | AAC profile / object type as the integer value of `AacObjectType`. | -| `SampleRate` | `int SampleRate { get; init; }` | Output sample rate in Hz. Doubled when SBR (HE-AAC) is detected. | -| `Sbr` | `bool Sbr { get; init; }` | True when a Spectral Band Replication (HE-AAC) header was detected. The reported `SampleRate` is the doubled effective rate; the decoded PCM is still the AAC-LC core band (SBR audio reconstruction is gated, see `AacSbr`). | - -#### `AdtsHeader` - -Parsed contents of a single 7-byte (CRC-absent) ADTS header + the 2 CRC bytes when `ProtectionAbsent` is `false`. `Profile` is the ADTS field (0..3); add 1 to obtain the MPEG-4 `AacObjectType`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdtsHeader` | `AdtsHeader(bool IsMpeg2, bool ProtectionAbsent, int Profile, int SampleRateIndex, int SampleRate, int ChannelConfiguration, int FrameLength, int BufferFullness, int NumberOfRawDataBlocks, int HeaderLengthBytes)` | Parsed contents of a single 7-byte (CRC-absent) ADTS header + the 2 CRC bytes when `ProtectionAbsent` is `false`. `Profile` is the ADTS field (0..3); add 1 to obtain the MPEG-4 `AacObjectType`. | -| `BufferFullness` | `int BufferFullness { get; init; }` | | -| `ChannelConfiguration` | `int ChannelConfiguration { get; init; }` | | -| `FrameLength` | `int FrameLength { get; init; }` | | -| `HeaderLengthBytes` | `int HeaderLengthBytes { get; init; }` | | -| `IsMpeg2` | `bool IsMpeg2 { get; init; }` | | -| `NumberOfRawDataBlocks` | `int NumberOfRawDataBlocks { get; init; }` | | -| `ObjectType` | `AacObjectType ObjectType { get; }` | The decoded object type (profile+1). | -| `Profile` | `int Profile { get; init; }` | | -| `ProtectionAbsent` | `bool ProtectionAbsent { get; init; }` | | -| `SampleRateIndex` | `int SampleRateIndex { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | - -### Namespace `Codec.Flac` - -[`FlacCodec`](#flaccodec) · [`FlacCodec.AudioProperties`](#flaccodecaudioproperties) - -#### `FlacCodec` - -FLAC codec: decodes a FLAC stream to interleaved little-endian PCM, and reads STREAMINFO metadata without a full decode. Moved out of `FileFormat.Flac` so it can be reused by any container that carries FLAC payloads (Matroska audio tracks, MP4 FLAC-in-ISOBMFF, …) without depending on the container descriptor. Supports CONSTANT, VERBATIM, FIXED (orders 0–4) and LPC subframes with Rice-coded residuals. Stereo channel-assignment modes (left/side, side/right, mid/side) are decorrelated before output. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses a FLAC stream into raw interleaved little-endian PCM on `output`. | -| `ReadAudioProperties` | `static AudioProperties ReadAudioProperties(ReadOnlySpan flacBytes)` | Reads STREAMINFO without a full decode; used by archive descriptors to build per-channel WAV headers. | - -#### `FlacCodec.AudioProperties` - -STREAMINFO fields callers need to drive channel-splitting / PCM-header construction. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AudioProperties` | `AudioProperties(int SampleRate, int Channels, int BitsPerSample, long TotalSamples)` | STREAMINFO fields callers need to drive channel-splitting / PCM-header construction. | -| `BitsPerSample` | `int BitsPerSample { get; init; }` | | -| `Channels` | `int Channels { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | -| `TotalSamples` | `long TotalSamples { get; init; }` | | - -### Namespace `Codec.Gsm610` - -[`Gsm610Codec`](#gsm610codec) - -#### `Gsm610Codec` - -GSM 06.10 full-rate speech decoder (ETSI EN 300 961). Each 33-byte frame decodes to 160 × 16-bit PCM samples at 8 kHz. This implementation provides a structurally correct decoder that unpacks the bitstream into LAR/LTP/RPE parameters, applies RPE grid positioning and the LTP + short-term synthesis filters. The spectral accuracy is approximate — producing audibly recognisable output for most frames but not a bit-exact match to the ETSI reference. This is acceptable because the decoder is primarily used to surface per-channel PCM in container-parity contexts (WAV format code 0x0031, AIFC `GSM` compression ID); bit-exact GSM decoding would require an additional ~1000 LOC of fixed-point arithmetic and a full port of the ETSI Annex-A tables. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FrameBytes` | `const int FrameBytes` | Size of one encoded GSM 06.10 frame in bytes. | -| `FrameSamples` | `const int FrameSamples` | Number of PCM samples produced per decoded frame. | -| `DecodeRaw` | `static short[] DecodeRaw(ReadOnlySpan gsm)` | Decodes a buffer of raw 33-byte GSM 06.10 frames (single mono stream) to 16-bit PCM. This is the "toast"/`.gsm` on-disk layout — a bare concatenation of frames with no container. Each frame's first byte carries the signature nibble `0xD` in its high four bits (the magic byte ranges `0xD0..0xDF`). | -| `Decode` | `static short[] Decode(ReadOnlySpan gsm, int channels)` | Decodes a buffer of GSM 06.10 frames to interleaved 16-bit PCM. | -| `LooksLikeRawFrames` | `static bool LooksLikeRawFrames(ReadOnlySpan gsm)` | Reports whether `gsm` is a whole number of 33-byte frames whose per-frame signature nibbles are all `0xD` — the cheap structural check a headerless `.gsm` reader uses before committing to a decode. | - -### Namespace `Codec.ImaAdpcm` - -[`ImaAdpcmCodec`](#imaadpcmcodec) - -#### `ImaAdpcmCodec` - -IMA ADPCM (Interactive Multimedia Association Adaptive Differential PCM) decoder. Each 4-bit nibble encodes the magnitude + sign of the delta between samples; the step size walks up and down a 89-entry log-spaced table based on the previous nibble. Used by WAV format code 0x0011 with a block layout: Per-channel 4-byte header: int16 predictor, int8 step-index, 1 reserved byte.For mono: remaining `blockAlign - 4` bytes are nibble pairs (LSN first).For stereo: headers are interleaved per channel (4 bytes L, 4 bytes R), then nibbles are interleaved 4 bytes per channel (8 samples each). - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecodeQuickTime` | `static short[][] DecodeQuickTime(ReadOnlySpan data, int channels)` | Decodes the Apple/QuickTime `ima4` packet variant (as carried by AIFC) into one PCM buffer per channel. The data is a sequence of fixed 34-byte packets that round-robin through the channels (ch0, ch1, …, ch0, …). Each packet is: a 2-byte big-endian preamble: the top 9 bits are the signed initial predictor (`(short)(preamble & 0xFF80)`) and the low 7 bits are the initial step index (clamped to ≤ 88);32 data bytes = 64 nibbles, low nibble first within each byte, decoded with the standard IMA step tables. Every packet therefore yields exactly 64 samples for its channel. Unlike the WAV block layout the packet does not emit the predictor itself as a sample. | -| `Decode` | `static short[][] Decode(ReadOnlySpan adpcm, int blockAlign, int channels)` | Decodes IMA ADPCM data to one PCM buffer per channel. Each output buffer holds `((blockAlign/channels - 4) * 2 + 1)` samples per block. | - -### Namespace `Codec.Midi` - -[`MidiCodec`](#midicodec) · [`MidiCodec.FileHeader`](#midicodecfileheader) · [`MidiCodec.MetaEvent`](#midicodecmetaevent) · [`MidiCodec.TrackChunk`](#midicodectrackchunk) - -#### `MidiCodec` - -Standard MIDI File (SMF) parser + per-track re-emitter. The archive descriptor uses this to enumerate tracks and produce format-0 single-track outputs from multi-track inputs. MIDI channel voice messages are not interpreted here — callers that only want meta-events get them via `ParseMetaEvents`; byte-level track slicing via `ExtractTrackBytes` returns the raw `MTrk` chunk data so downstream tools keep note-on/note-off semantics intact. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MidiCodec` | `MidiCodec()` | | -| `BuildSingleTrackFile` | `byte[] BuildSingleTrackFile(byte[] trackBody, int division)` | Wraps a raw MTrk body in a format-0 SMF file using `division` copied from the source. | -| `ExtractTrackBytes` | `byte[] ExtractTrackBytes(ReadOnlySpan data, TrackChunk track)` | Returns the raw `MTrk` payload bytes (minus the 8-byte "MTrk" + length header). | -| `FindTracks` | `IReadOnlyList FindTracks(ReadOnlySpan data)` | | -| `ParseMetaEvents` | `IReadOnlyList ParseMetaEvents(ReadOnlySpan data, TrackChunk track)` | Reads meta-events from a single MTrk chunk. Running-status preservation is handled correctly — every event's delta-time + status is decoded before the meta filter so the stream position stays coherent. | -| `ReadHeader` | `FileHeader ReadHeader(ReadOnlySpan data)` | | - -#### `MidiCodec.FileHeader` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FileHeader` | `FileHeader(int Format, int NumTracks, int Division)` | | -| `Division` | `int Division { get; init; }` | | -| `Format` | `int Format { get; init; }` | | -| `NumTracks` | `int NumTracks { get; init; }` | | - -#### `MidiCodec.MetaEvent` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MetaEvent` | `MetaEvent(int TrackIndex, byte Type, byte[] Data)` | | -| `Data` | `byte[] Data { get; init; }` | | -| `TrackIndex` | `int TrackIndex { get; init; }` | | -| `Type` | `byte Type { get; init; }` | | - -#### `MidiCodec.TrackChunk` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TrackChunk` | `TrackChunk(int Index, int FileOffset, int ByteLength)` | | -| `ByteLength` | `int ByteLength { get; init; }` | | -| `FileOffset` | `int FileOffset { get; init; }` | | -| `Index` | `int Index { get; init; }` | | - -### Namespace `Codec.Mp3` - -[`Mp3Codec`](#mp3codec) · [`Mp3FrameHeader`](#mp3frameheader) · [`Mp3StreamInfo`](#mp3streaminfo) - -#### `Mp3Codec` - -Clean-room MP3 decoder. Ported from `minimp3` (https://github.com/lieff/minimp3, commit 7b590fdcfa5a79c033e76eacc05d0c3e4c79f536, public domain / CC0). Decodes MPEG-1 / MPEG-2 / MPEG-2.5 Layer I, Layer II and Layer III to interleaved little-endian signed 16-bit PCM. Free-format bitrates, ancillary data and CRC verification are not implemented (CRC bytes are skipped if present). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decodes an MP3 stream into raw interleaved little-endian PCM (signed 16-bit per channel) on `output`. The output sample rate / channel count are set by the first decoded frame; readers are expected to track those separately (e.g. via `ReadStreamInfo`). | -| `ReadStreamInfo` | `static Mp3StreamInfo ReadStreamInfo(Stream input)` | Reads stream-level info (sample rate, channels, average bitrate, duration in samples). | - -#### `Mp3FrameHeader` - -Parsed MPEG-1/2/2.5 Layer I/II/III frame header. MP3 frames begin with a 32-bit header: 11 bits sync (0xFFE or 0xFFF), 2 bits version ID, 2 bits layer, 1 bit protection (CRC), 4 bits bitrate index, 2 bits sample-rate index, 1 bit padding, 1 bit private, 2 bits channel mode, 2 bits mode extension, 1 bit copyright, 1 bit original, 2 bits emphasis. Fields are raw; sample rate / bitrate lookups must go through `SampleRateHz` and `BitrateKbps`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp3FrameHeader` | `Mp3FrameHeader(int VersionId, int Layer, bool HasCrc, int BitrateIndex, int SampleRateIndex, bool Padding, bool Private, int ChannelMode, int ModeExtension, bool Copyright, bool Original, int Emphasis)` | Parsed MPEG-1/2/2.5 Layer I/II/III frame header. MP3 frames begin with a 32-bit header: 11 bits sync (0xFFE or 0xFFF), 2 bits version ID, 2 bits layer, 1 bit protection (CRC), 4 bits bitrate index, 2 bits sample-rate index, 1 bit padding, 1 bit private, 2 bits channel mode, 2 bits mode extension, 1 bit copyright, 1 bit original, 2 bits emphasis. Fields are raw; sample rate / bitrate lookups must go through `SampleRateHz` and `BitrateKbps`. | -| `BitrateIndex` | `int BitrateIndex { get; init; }` | | -| `BitrateKbps` | `int BitrateKbps { get; }` | Bitrate in kbps from the MPEG/layer-specific lookup table (0 = free format). | -| `ChannelMode` | `int ChannelMode { get; init; }` | | -| `Channels` | `int Channels { get; }` | Number of channels (1 for mono, 2 for any stereo mode). | -| `Copyright` | `bool Copyright { get; init; }` | | -| `Emphasis` | `int Emphasis { get; init; }` | | -| `FrameLengthBytes` | `int FrameLengthBytes { get; }` | Frame length in bytes (including header). Returns 0 for free-format frames. Formula: samplesPerFrame * bitrate / sampleRate / 8 + padding. | -| `HasCrc` | `bool HasCrc { get; init; }` | | -| `IsIntensityStereo` | `bool IsIntensityStereo { get; }` | True when joint-stereo mode has intensity-stereo enabled. | -| `IsMono` | `bool IsMono { get; }` | True when this frame carries only a single audio channel. | -| `IsMpeg1` | `bool IsMpeg1 { get; }` | True for MPEG-1 (version id = 3). | -| `IsMpeg25` | `bool IsMpeg25 { get; }` | True for MPEG-2.5 (unofficial extension, version id = 0). | -| `IsMsStereo` | `bool IsMsStereo { get; }` | True when joint-stereo mode has MS-stereo enabled. | -| `Layer` | `int Layer { get; init; }` | | -| `ModeExtension` | `int ModeExtension { get; init; }` | | -| `Original` | `bool Original { get; init; }` | | -| `Padding` | `bool Padding { get; init; }` | | -| `Private` | `bool Private { get; init; }` | | -| `SampleRateHz` | `int SampleRateHz { get; }` | Sample rate in Hz after version scaling (MPEG-2 halves, MPEG-2.5 quarters). | -| `SampleRateIndex` | `int SampleRateIndex { get; init; }` | | -| `SamplesPerFrame` | `int SamplesPerFrame { get; }` | Samples produced per decoded frame (1152 for MPEG-1 L2/3, 576 for MPEG-2 L3, 384 for L1). | -| `VersionId` | `int VersionId { get; init; }` | | -| `Parse` | `static Mp3FrameHeader Parse(ReadOnlySpan header4)` | Parses a 4-byte MP3 frame header. Throws `InvalidDataException` if the syncword is absent or reserved bit patterns are present. | - -#### `Mp3StreamInfo` - -Stream-level metadata extracted from an MP3 stream's first valid frame header (and Xing/Info VBR header, if present). `DurationSamples` is estimated from frame count when a VBR header is found, otherwise from byte size / average bitrate; pass -1 when unknown. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp3StreamInfo` | `Mp3StreamInfo(int SampleRate, int Channels, int Bitrate, long DurationSamples)` | Stream-level metadata extracted from an MP3 stream's first valid frame header (and Xing/Info VBR header, if present). `DurationSamples` is estimated from frame count when a VBR header is found, otherwise from byte size / average bitrate; pass -1 when unknown. | -| `Bitrate` | `int Bitrate { get; init; }` | | -| `Channels` | `int Channels { get; init; }` | | -| `DurationSamples` | `long DurationSamples { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | - -### Namespace `Codec.MsAdpcm` - -[`MsAdpcmCodec`](#msadpcmcodec) - -#### `MsAdpcmCodec` - -Microsoft ADPCM decoder (WAV format code 0x0002). Block layout: Per channel: 1-byte predictor selector (index into the 7-entry coefficient table), 2-byte delta (quantization step), 2-byte sample1, 2-byte sample2.Followed by `blockAlign - 7*channels` bytes of ADPCM nibbles, where each byte packs two samples (high nibble first) that alternate channels when stereo. Predictor coefficients are taken from a standard 7-entry table; the new sample is computed as `(s1 * c1 + s2 * c2) >> 8` plus a dequantized delta, with the delta itself adapting based on an error table. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decode` | `static short[][] Decode(ReadOnlySpan adpcm, int blockAlign, int channels)` | Decodes a buffer of MS-ADPCM blocks to per-channel PCM. Each block emits `2 + (blockAlign - 7*channels) * 2 / channels` samples per channel. | - -### Namespace `Codec.MuLaw` - -[`MuLawCodec`](#mulawcodec) - -#### `MuLawCodec` - -G.711 μ-law codec: 8-bit logarithmic samples decoded to 16-bit linear PCM. The μ-law quantisation is symmetric around zero and uses a bias of 0x84 plus a sign/exponent/mantissa encoding. This is the lossless inverse of the ITU-T G.711 reference algorithm. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DecodeSample` | `static short DecodeSample(byte mu)` | Decodes one μ-law byte to a 16-bit signed linear sample. | -| `Decode` | `static short[] Decode(ReadOnlySpan mulaw)` | Decodes a full μ-law byte buffer to 16-bit linear PCM. | -| `EncodeSample` | `static byte EncodeSample(short pcm)` | Encodes one 16-bit signed linear sample to a μ-law byte (used for test round-trip). | -| `Encode` | `static byte[] Encode(ReadOnlySpan pcm)` | Encodes a 16-bit linear PCM buffer to μ-law bytes (used for tests). | - -### Namespace `Codec.Opus` - -[`OggOpusReader`](#oggopusreader) · [`OpusBandwidth`](#opusbandwidth) · [`OpusCelt`](#opuscelt) · [`OpusCodec`](#opuscodec) · [`OpusHeadPacket`](#opusheadpacket) · [`OpusMode`](#opusmode) · [`OpusPacketReader`](#opuspacketreader) · [`OpusRangeDecoder`](#opusrangedecoder) · [`OpusResampler`](#opusresampler) · [`OpusSilk`](#opussilk) · [`OpusStreamInfo`](#opusstreaminfo) · [`OpusTagsPacket`](#opustagspacket) · [`OpusTocInfo`](#opustocinfo) - -#### `OggOpusReader` - -Minimal Ogg page walker specialised for Opus streams (RFC 7845 / RFC 3533). Reassembles logical packets across page boundaries using the segment-table "lacing" mechanism. Does not verify CRCs (we trust the stream here). - -| Member | Signature | Summary | -| --- | --- | --- | -| `OggOpusReader` | `OggOpusReader(Stream stream)` | | -| `ReadHead` | `OpusHeadPacket ReadHead()` | Reads and validates the first logical packet, which must be `OpusHead`. | -| `TryReadPacket` | `bool TryReadPacket(out byte[] packet)` | Pulls the next reassembled logical packet from the Ogg stream. | -| `TryReadTags` | `OpusTagsPacket TryReadTags()` | Reads the second logical packet if it is `OpusTags`, otherwise buffers it back for audio consumption and returns null. | - -#### `OpusBandwidth` - -Opus audio bandwidth (NB/MB/WB/SWB/FB) as signalled by the TOC config field. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Narrowband` | `0` | Narrowband — 4 kHz audio bandwidth, 8 kHz sample rate. | -| `Mediumband` | `1` | Mediumband — 6 kHz audio bandwidth, 12 kHz sample rate. | -| `Wideband` | `2` | Wideband — 8 kHz audio bandwidth, 16 kHz sample rate. | -| `SuperWideband` | `3` | Super-wideband — 12 kHz audio bandwidth, 24 kHz sample rate. | -| `Fullband` | `4` | Fullband — 20 kHz audio bandwidth, 48 kHz sample rate. | - -#### `OpusCelt` - -CELT decoder entry point — transforms quantised MDCT coefficients + pitch prediction back into PCM samples. Status: scaffolding only. The bitstream entry point `DecodeFrame` currently throws `NotSupportedException`; the `Decompress` wrapper bypasses it and emits silence so that Ogg framing + TOC + packet counts round-trip correctly. Subsequent waves land the full pipeline: Silence decision + post-filter stateSpread / tapset / tf changesCoarse + fine energy (coarse delta-coded Laplace, fine uniform)PVQ (vector quantisation of residual) + stereo mid-sideAnti-collapse + denormalisationInverse MDCT with Kaiser-Bessel-Derived window + overlap-add - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusCelt` | `OpusCelt(int channels, int frameSamplesAt48k)` | Creates a new CELT decoder for the given output channels / frame size. | -| `Channels` | `int Channels { get; }` | Number of output channels (1 or 2). | -| `FrameSamples` | `int FrameSamples { get; }` | Frame size in samples at 48 kHz. | -| `DecodeFrame` | `void DecodeFrame(ReadOnlySpan frame, Span pcmOut)` | Decodes one CELT frame from `frame` into `pcmOut` (interleaved float). Not implemented in this pass. | - -#### `OpusCodec` - -Clean-room Opus decoder. Input: an Ogg Opus stream (RFC 7845) whose packets carry Opus-encoded frames (RFC 6716). Output: interleaved little-endian signed 16-bit PCM at the stream's native sample rate (48 kHz for CELT). Ported from: libopus (Xiph) — BSD 3-clause, commit-agnostic clean-room port tracking the RFC 6716 / RFC 7845 / RFC 8251 bitstream specification. Supported surface (first pass):Ogg page walker + `OpusHead` / `OpusTags` metadata parsing.TOC byte parsing + all four frame-packing codes (0/1/2/3) per RFC 6716 §3.2.Range decoder (ec_dec) skeleton — reads tell, bits, and cdf symbols.CELT-only configs (16-31) — framing only. Full spectral inverse MDCT is not landed in this first pass and currently emits silence for the expected number of samples so downstream tooling can round-trip file structure and sample counts. Use `ReadStreamInfo` to introspect stream metadata deterministically.SILK-only configs (0-11) — framing only (same silence fallback).Hybrid configs (12-15) — throws `NotSupportedException`. This is pragmatic scaffolding: `OpusStreamInfo`, TOC parsing, and Ogg framing are production-complete and covered by tests. The CELT/SILK subband decoders are stubbed to silence — the intent is that subsequent waves will flesh out `OpusCelt` and `OpusSilk` without changing the public surface here. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an Ogg Opus stream from `input` into interleaved little-endian signed 16-bit PCM on `output`. | -| `ReadStreamInfo` | `static OpusStreamInfo ReadStreamInfo(Stream input)` | Reads the Ogg Opus identification header and any comment header without decoding audio. | - -#### `OpusHeadPacket` - -`OpusHead` identification-header packet contents per RFC 7845 §5.1. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusHeadPacket` | `OpusHeadPacket(byte Version, byte ChannelCount, ushort PreSkip, uint InputSampleRate, short OutputGainQ8, byte ChannelMappingFamily)` | `OpusHead` identification-header packet contents per RFC 7845 §5.1. | -| `ChannelCount` | `byte ChannelCount { get; init; }` | | -| `ChannelMappingFamily` | `byte ChannelMappingFamily { get; init; }` | | -| `InputSampleRate` | `uint InputSampleRate { get; init; }` | | -| `OutputGainQ8` | `short OutputGainQ8 { get; init; }` | | -| `PreSkip` | `ushort PreSkip { get; init; }` | | -| `Version` | `byte Version { get; init; }` | | - -#### `OpusMode` - -One of the three Opus operating modes, decoded from the TOC byte's config field per RFC 6716 §3.1. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `SilkOnly` | `0` | | -| `Hybrid` | `1` | | -| `CeltOnly` | `2` | | - -#### `OpusPacketReader` - -Parses the TOC byte (RFC 6716 §3.1) and walks the four frame-packing formats (codes 0-3, §3.2). - -| Member | Signature | Summary | -| --- | --- | --- | -| `CountFrames` | `static int CountFrames(ReadOnlySpan packet)` | Counts the number of Opus frames packed into `packet` per RFC 6716 §3.2. Returns 0 if the packet is malformed. | -| `ParseToc` | `static OpusTocInfo ParseToc(byte toc)` | Parses an Opus TOC byte into `OpusTocInfo`. | -| `SplitFrames` | `static List SplitFrames(ReadOnlySpan packet)` | Splits an Opus packet into individual frame byte ranges per RFC 6716 §3.2, respecting codes 0 (1 frame), 1 (2 CBR frames), 2 (2 VBR frames), and 3 (N frames — CBR or VBR, optional padding). | - -#### `OpusRangeDecoder` - -Opus range (entropy) decoder — the shared arithmetic-coder state used by both the CELT and SILK bitstreams, per RFC 6716 §4.1 (entity "`ec_dec`"). This is a clean-room port of libopus's `entdec.c`/`entcode.c`. The range coder reads forward from the start of the packet and also reads raw/unstructured bits backward from the end of the packet. `ReadBitsRaw` exposes the backward stream used for quantised pulse signs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusRangeDecoder` | `OpusRangeDecoder(ReadOnlySpan buffer)` | Creates a new range decoder over `buffer`. | -| `Tell` | `int Tell { get; }` | Total bits consumed so far (used for termination checks). | -| `DecodeUniform` | `uint DecodeUniform(uint ft)` | Decodes a symbol modelled by a cumulative-frequency table with total probability `ft`. Returns the scaled frequency value (0 ≤ fs < ft) which the caller must map through its CDF to find the symbol. | -| `ReadBitsRaw` | `uint ReadBitsRaw(int bits)` | Decodes `bits` raw (uncompressed) bits from the backward stream — used by CELT's pulse-coding stage for sign and fine-energy bits. | -| `Update` | `void Update(uint fl, uint fh, uint ft)` | Narrows the range after the symbol with cumulative frequency bounds `fl`..`fh` (out of `ft`) was decoded. | - -#### `OpusResampler` - -Rational-rate resampler used to bring SILK's 8 / 12 / 16 / 24 kHz output up to CELT's native 48 kHz so hybrid / SILK-only configs can emit to the unified output rate. Status: simple linear interpolation stub — replace with libopus's Kaiser-windowed sinc ("speex_resampler") in a follow-up wave when SILK is wired up. Kept as a separate class so the API surface is stable while the internals are upgraded. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusResampler` | `OpusResampler(int inputRate, int outputRate, int channels)` | Creates a resampler converting `inputRate` → `outputRate`. | -| `Channels` | `int Channels { get; }` | | -| `InputRate` | `int InputRate { get; }` | | -| `OutputRate` | `int OutputRate { get; }` | | -| `Resample` | `int Resample(ReadOnlySpan input, Span output)` | Resamples `input` (interleaved float) into `output`. | - -#### `OpusSilk` - -SILK decoder entry point — linear-predictive speech codec path used for narrowband / medium-band / wideband Opus configs (0-11). Status: scaffolding only. `DecodeFrame` throws `NotSupportedException`; `Decompress` emits silence for the correct sample count. Full pipeline (LTP + LSF → LPC synthesis + excitation decoding + stereo unmixing + `OpusResampler` up-conversion to 48 kHz) is a follow-up wave. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusSilk` | `OpusSilk(int channels, int internalSampleRate)` | Creates a SILK decoder for the given output channels + sample rate. | -| `Channels` | `int Channels { get; }` | Output channel count (1 or 2). | -| `InternalSampleRate` | `int InternalSampleRate { get; }` | SILK's internal sample rate (8 / 12 / 16 kHz). | -| `DecodeFrame` | `void DecodeFrame(ReadOnlySpan frame, Span pcmOut)` | Decodes one SILK frame. Not implemented in this pass. | - -#### `OpusStreamInfo` - -Opus stream identification info extracted from the `OpusHead` + optional `OpusTags` packets of an Ogg Opus stream. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusStreamInfo` | `OpusStreamInfo(int SampleRate, int Channels, int PreSkip, int InputSampleRate, string Vendor)` | Opus stream identification info extracted from the `OpusHead` + optional `OpusTags` packets of an Ogg Opus stream. | -| `Channels` | `int Channels { get; init; }` | | -| `InputSampleRate` | `int InputSampleRate { get; init; }` | | -| `PreSkip` | `int PreSkip { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | -| `Vendor` | `string Vendor { get; init; }` | | - -#### `OpusTagsPacket` - -`OpusTags` comment-header packet contents per RFC 7845 §5.2. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusTagsPacket` | `OpusTagsPacket(string Vendor, IReadOnlyList Comments)` | `OpusTags` comment-header packet contents per RFC 7845 §5.2. | -| `Comments` | `IReadOnlyList Comments { get; init; }` | | -| `Vendor` | `string Vendor { get; init; }` | | - -#### `OpusTocInfo` - -Decoded TOC-byte configuration for an Opus packet (RFC 6716 Table 2). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OpusTocInfo` | `OpusTocInfo(int Config, OpusMode Mode, OpusBandwidth Bandwidth, int FrameDurationMicros, bool IsStereo, int FrameCountCode)` | Decoded TOC-byte configuration for an Opus packet (RFC 6716 Table 2). | -| `Bandwidth` | `OpusBandwidth Bandwidth { get; init; }` | Signalled audio bandwidth. | -| `Config` | `int Config { get; init; }` | Raw config field (0-31). | -| `FrameCountCode` | `int FrameCountCode { get; init; }` | Frame-packing code c (bits 0-1 of the TOC byte). | -| `FrameDurationMicros` | `int FrameDurationMicros { get; init; }` | Frame duration in microseconds (2500 / 5000 / 10000 / 20000 / 40000 / 60000). | -| `FrameSamplesAt48k` | `int FrameSamplesAt48k { get; }` | Samples per frame at the 48 kHz native CELT output rate. | -| `IsStereo` | `bool IsStereo { get; init; }` | Stereo flag (bit 2 of the TOC byte, mislabeled "s" in the RFC). | -| `Mode` | `OpusMode Mode { get; init; }` | SILK-only / Hybrid / CELT-only. | - -### Namespace `Codec.Pcm` - -[`ChannelLayout`](#channellayout) · [`PcmCodec`](#pcmcodec) - -#### `ChannelLayout` - -Speaker-channel model for multi-channel audio, mirroring FFmpeg's `libavutil/channel_layout`. Channel identities are bit positions shared by `WAVE_FORMAT_EXTENSIBLE.dwChannelMask`, CAF's channel bitmap and FFmpeg's `AVChannel` (bits 0–17 are the WAVE speakers, 29+ are FFmpeg extensions up to the 22.2 bottom speakers). For streams that don't carry an explicit speaker mask, `DefaultNames` applies FFmpeg's `av_channel_layout_default` rule — the first entry of its layout map with a matching channel count (mono, stereo, 2.1, 4.0, 5.0, 5.1, 6.1, 7.1, 5.1.4, 7.1.4, 9.1.4, 9.1.6, 22.2) — and any unmapped count degrades to indexed `CH_n` names so arbitrary channel counts stay decodable. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DefaultNames` | `static IReadOnlyList DefaultNames(int channels)` | Per-channel pseudo-file names for a stream WITHOUT an explicit speaker mask: FFmpeg's default layout for the count, or `CH_n` for unmapped counts. Mono keeps `MONO` and plain stereo keeps `LEFT`/`RIGHT`. | -| `NamesFromMask` | `static IReadOnlyList NamesFromMask(ulong mask, int channels)` | Per-channel names from an explicit speaker mask (WAVE_FORMAT_EXTENSIBLE `dwChannelMask`, CAF channel bitmap). The mask wins only when its population count matches the actual channel count; otherwise the count defaults apply. Plain stereo (FL\|FR) keeps the legacy LEFT/RIGHT names. | -| `OrderIndex` | `static int OrderIndex(string name)` | Canonical interleave position of a named channel — the inverse of the naming above, used to sort per-channel inputs back into file order when assembling a multi-channel file. `CH_n` maps to `n`; unknown names sort last. | - -#### `PcmCodec` - -PCM codec: integer/float sample packing, channel interleave/deinterleave, and canonical RIFF/WAVE header framing. Used by audio-container descriptors (WAV, FLAC-archive, future Opus/Vorbis) that surface per-channel mono WAVs as archive entries. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Interleave` | `static byte[] Interleave(IReadOnlyList monoChannels, int bitsPerSample)` | Weaves per-channel mono PCM blobs back into one interleaved buffer — the inverse of `SplitInterleavedPcm`. All channels must share the same byte length (i.e. the same frame count at the given `bitsPerSample`). Channels are interleaved in the order supplied. A single channel is returned unchanged. | -| `LayoutNames` | `static IReadOnlyList LayoutNames(int channels)` | Conventional channel names per layout (FFmpeg default layouts, mono → 22.2); unmapped counts fall back to CH_0..CH_N. See `ChannelLayout`. | -| `SplitInterleavedFloat` | `static IReadOnlyList> SplitInterleavedFloat(byte[] interleaved, int channels, int sampleRate, int bitsPerSample, ulong? channelMask = null)` | Splits interleaved little-endian IEEE-float PCM into per-channel mono WAV blobs (RIFF format code 3). Mirrors `SplitInterleavedPcm`'s frame walk but emits float WAVs; `bitsPerSample` must be 32 or 64. As with the integer split, an explicit `channelMask` (WAVE_FORMAT_EXTENSIBLE `dwChannelMask`, CAF channel bitmap) names each mono WAV for its real speaker; otherwise the FFmpeg default layout for the channel count applies. | -| `SplitInterleavedPcm` | `static IReadOnlyList> SplitInterleavedPcm(byte[] interleaved, int channels, int sampleRate, int bitsPerSample, ulong? channelMask = null)` | Splits interleaved little-endian signed-integer PCM into per-channel mono WAV blobs. Channels are returned in the order they occur in `interleaved`. When the container carries an explicit speaker bitmap (WAVE_FORMAT_EXTENSIBLE `dwChannelMask`, CAF channel bitmap), pass it via `channelMask` so each mono WAV is named for its real speaker; otherwise the FFmpeg default layout for the channel count applies. | -| `SplitPerChannelIntSamples` | `static IReadOnlyList> SplitPerChannelIntSamples(int[][] perChannel, int sampleRate, int bitsPerSample)` | Splits per-channel integer samples into per-channel mono WAV blobs. Widths wider than `bitsPerSample` are truncated via two's-complement masking. | -| `ToWavBlob` | `static byte[] ToWavBlob(byte[] pcm, int channels, int sampleRate, int bitsPerSample, int formatCode = 1)` | Wraps raw little-endian PCM bytes in a minimal RIFF/WAVE header. `formatCode`: 1 = PCM integer, 3 = IEEE float. | - -### Namespace `Codec.Vorbis` - -[`VorbisCodec`](#vorbiscodec) · [`VorbisStreamInfo`](#vorbisstreaminfo) - -#### `VorbisCodec` - -Ogg Vorbis I decoder. Reads an Ogg-wrapped Vorbis bitstream and produces interleaved little-endian 16-bit PCM. Clean-room port — uses the public Vorbis I specification (xiph.org) and stb_vorbis.c v1.22 (public domain, Sean Barrett, 2007–2021) as a structural reference. Supported: Ogg page reassembly, identification + comment + setup packets, codebook lookup types 0/1/2, floor 0 (LSP) and floor 1, residue types 0/1/2, single-step channel coupling (stereo and beyond), short/long-block IMDCT with the Vorbis sine window and overlap-add, output clipping to int16. Deferred / not implemented: chained logical bitstreams beyond the first one, low-latency seeking, 24-bit output. The IMDCT uses an O(N²) direct form rather than a butterfly factorisation — correct but slow for long blocks. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | Decompresses an Ogg-Vorbis stream to interleaved little-endian 16-bit PCM on `output`. | -| `ReadStreamInfo` | `static VorbisStreamInfo ReadStreamInfo(Stream input)` | Reads the identification + comment packets and returns metadata without decoding any audio frames. | - -#### `VorbisStreamInfo` - -Vorbis-stream metadata returned by `ReadStreamInfo`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VorbisStreamInfo` | `VorbisStreamInfo(int SampleRate, int Channels, int NominalBitrate, string Vendor, long? DurationSamples)` | Vorbis-stream metadata returned by `ReadStreamInfo`. | -| `Channels` | `int Channels { get; init; }` | Channel count. | -| `DurationSamples` | `long? DurationSamples { get; init; }` | Total duration in samples, or `null` if not derivable. | -| `NominalBitrate` | `int NominalBitrate { get; init; }` | Nominal bitrate in bits/second (0 if absent). | -| `SampleRate` | `int SampleRate { get; init; }` | Sample rate in Hz, from the identification packet. | -| `Vendor` | `string Vendor { get; init; }` | Encoder vendor string (from the comment packet). | - -### Namespace `FileFormat.Aiff` - -[`AiffFormatDescriptor`](#aiffformatdescriptor) · [`AiffReader`](#aiffreader) · [`AiffReader.ParsedAiff`](#aiffreaderparsedaiff) · [`AiffWriter`](#aiffwriter) - -#### `AiffFormatDescriptor` - -Exposes an AIFF / AIFC file as an archive of `FULL.aif`, one `LEFT.wav`/ `RIGHT.wav`/… per channel, plus `metadata/annotations.txt` and `metadata/markers.bin`. Compressed AIFC payloads are decoded to linear PCM before being split per channel (μ-law, A-law, `fl32`/`fl64` IEEE float, and `ima4` Apple/QuickTime IMA ADPCM are decoded to per-channel PCM; `GSM` is recognised but passed through as raw bytes in the `FULL.aif` entry only). - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveWriteConstraints`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AiffFormatDescriptor` | `AiffFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AiffReader` - -IFF/AIFF + AIFC container parser. Walks the FORM chunk chain and surfaces the COMM/SSND/ANNO/MARK/INST/ID3 chunks. All integers in AIFF are big-endian; the sample rate is stored as a 10-byte IEEE 754 extended-precision float. Compression IDs recognised for AIFC: `NONE`/`twos` (big-endian PCM), `sowt` (little-endian PCM), `ulaw`/`ULAW` (G.711 μ-law), `alaw`/`ALAW` (G.711 A-law), `ima4` (Apple/QuickTime IMA ADPCM variant), `fl32`/`fl64` (IEEE float big-endian), and `GSM `. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AiffReader` | `AiffReader()` | | -| `Decode80BitFloatToInt` | `static int Decode80BitFloatToInt(ReadOnlySpan b)` | Decodes the 80-bit IEEE 754 extended-precision float that AIFF uses for the sample rate field. Returns the value truncated to int; non-finite/negative inputs return 0. | -| `Read` | `ParsedAiff Read(ReadOnlySpan data)` | | - -#### `AiffReader.ParsedAiff` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ParsedAiff` | `ParsedAiff(int NumChannels, int SampleRate, int BitsPerSample, int SampleFrames, string CompressionId, string CompressionName, bool IsAifc, byte[] SoundData, byte[] Annotations, byte[] Markers, byte[] Instrument, byte[] Id3, IReadOnlyList> OtherChunks)` | | -| `Annotations` | `byte[] Annotations { get; init; }` | | -| `BitsPerSample` | `int BitsPerSample { get; init; }` | | -| `CompressionId` | `string CompressionId { get; init; }` | | -| `CompressionName` | `string CompressionName { get; init; }` | | -| `Id3` | `byte[] Id3 { get; init; }` | | -| `Instrument` | `byte[] Instrument { get; init; }` | | -| `IsAifc` | `bool IsAifc { get; init; }` | | -| `Markers` | `byte[] Markers { get; init; }` | | -| `NumChannels` | `int NumChannels { get; init; }` | | -| `OtherChunks` | `IReadOnlyList> OtherChunks { get; init; }` | | -| `SampleFrames` | `int SampleFrames { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | -| `SoundData` | `byte[] SoundData { get; init; }` | | - -#### `AiffWriter` - -Minimal uncompressed AIFF (FORM/AIFF) writer: a COMM chunk describing the big-endian linear PCM plus an SSND chunk carrying the samples. Used by `AiffFormatDescriptor` to assemble a multi-channel AIFF from per-channel mono inputs. The sample rate is stored in the 80-bit IEEE 754 extended-precision form AIFF mandates — the inverse of `Decode80BitFloatToInt`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AiffWriter` | `AiffWriter()` | | -| `Encode80BitFloat` | `static byte[] Encode80BitFloat(int value)` | Encodes a non-negative integer sample rate as a 10-byte 80-bit IEEE 754 extended-precision float (sign + 15-bit biased exponent + 64-bit mantissa with an explicit integer bit). | -| `Write` | `byte[] Write(byte[] bigEndianInterleaved, int channels, int sampleRate, int bitsPerSample)` | Builds an uncompressed AIFF from already big-endian interleaved PCM. | - -### Namespace `FileFormat.Akb` - -[`AkbEntry`](#akbentry) · [`AkbFormatDescriptor`](#akbformatdescriptor) · [`AkbReader`](#akbreader) · [`AkbWriter`](#akbwriter) - -#### `AkbEntry` - -Represents a single audio entry within a Square Enix AKB audio bank. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AkbEntry` | `AkbEntry()` | | -| `Flags` | `uint Flags { get; init; }` | Gets the per-entry flags word; bit 0 indicates a looping sample. | -| `Name` | `string Name { get; init; }` | Gets the synthetic display name (e.g. `entry_000.bin`). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute byte offset of the entry's audio data within the AKB stream. | -| `SampleCount` | `uint SampleCount { get; init; }` | Gets the duration of the entry in samples (codec-dependent interpretation). | -| `Size` | `long Size { get; init; }` | Gets the byte length of the entry's audio data. | - -#### `AkbFormatDescriptor` - -Square Enix AKB audio bank descriptor — surfaces per-entry raw audio payloads plus a synthetic `metadata.ini` entry containing bank-wide header fields (sample rate, channel mode, loop points). References: `https://github.com/vgmstream/vgmstream` — vgmstream — implements AKB parsing; the de-facto referenceSquare Enix never published the AKB layout; header fields were recovered by the VGM ripping community - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AkbFormatDescriptor` | `AkbFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The synthetic `metadata.ini` entry is materialised on the fly; all other entries delegate to the reader's per-entry extract and are wrapped in a `BoundedEntryStream` sized to their logical length. | - -#### `AkbReader` - -Reads entries from a Square Enix AKB audio bank (Final Fantasy / Kingdom Hearts era). Surfaces raw per-entry payload bytes; the per-entry codec (HCA, MSADPCM, IMA-ADPCM, raw PCM) is intentionally not decoded — game-specific dispatch belongs to the caller. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AkbReader` | `AkbReader(Stream stream, bool leaveOpen = false)` | Initializes a new `AkbReader` from a stream positioned at the start of an AKB file. | -| `ChannelMode` | `byte ChannelMode { get; }` | Gets the channel-mode byte (1 = mono, 2 = stereo). Informational only. | -| `ContentOffset` | `uint ContentOffset { get; }` | Gets the absolute offset where entry payload data begins. | -| `ContentSize` | `uint ContentSize { get; }` | Gets the total byte length of the content region. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all audio entries declared in the bank. | -| `LoopEnd` | `uint LoopEnd { get; }` | Gets the loop end position in samples; 0 if the bank declares no loop. | -| `LoopStart` | `uint LoopStart { get; }` | Gets the loop start position in samples; 0 if the bank declares no loop. | -| `SampleRate` | `uint SampleRate { get; }` | Gets the sample rate in Hz declared by the bank header. | -| `VersionByte` | `byte VersionByte { get; }` | Gets the AKB subformat version byte (1 = single-stream v1, 2 = multi-entry v2). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AkbEntry entry)` | Reads the raw payload bytes for a given entry. The codec is not decoded — these are the raw on-disk bytes between `Offset` and `Offset` + `Size`. | - -#### `AkbWriter` - -Creates a Square Enix AKB v2 audio bank from caller-supplied raw audio payloads. The codec is not encoded — supplied bytes are stored verbatim into the content region. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AkbWriter` | `AkbWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `AkbWriter` that will write AKB v2 to `stream`. | -| `ChannelMode` | `byte ChannelMode { get; set; }` | Gets or sets the channel-mode byte (1 = mono, 2 = stereo). Defaults to mono. | -| `LoopEnd` | `uint LoopEnd { get; set; }` | Gets or sets the loop end position (samples). 0 means no loop. | -| `LoopStart` | `uint LoopStart { get; set; }` | Gets or sets the loop start position (samples). 0 means no loop. | -| `SampleRate` | `uint SampleRate { get; set; }` | Gets or sets the bank-wide sample rate written to the header. Defaults to 44100 Hz. | -| `AddEntry` | `void AddEntry(string name, byte[] data, uint sampleCount = 0, uint flags = 0)` | Adds an entry to the bank. The supplied bytes are stored verbatim — caller is responsible for any codec encoding (HCA, MSADPCM, etc.). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Serializes the bank to the underlying stream. Called automatically on Dispose. | - -### Namespace `FileFormat.Alac` - -[`AlacFormatDescriptor`](#alacformatdescriptor) - -#### `AlacFormatDescriptor` - -Surfaces an ALAC (Apple Lossless) audio file — usually wrapped in an M4A (ISOBMFF) container — as a read-only archive of the container passthrough, the ALAC codec-specific "magic cookie", the raw ALAC frame bytes extracted via stsz/stsc/stco, a metadata.ini describing the cookie fields, and — when the stream decodes — one playable mono WAV per speaker (Kind `Channel`, method `pcm`), named per `ChannelLayout`. The decode is best-effort: any unsupported cookie or truncated stream leaves the FULL/Track/metadata view intact. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AlacFormatDescriptor` | `AlacFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Ape` - -[`ApeFormatDescriptor`](#apeformatdescriptor) - -#### `ApeFormatDescriptor` - -Surfaces a Monkey's Audio (.ape) file as a read-only archive of the container passthrough, the raw APE descriptor header, the preserved WAV header bytes, the concatenated frame data, the seek table, and a metadata.ini describing the stream parameters. When the stream is a compression-level-1000 ("fast") Monkey's Audio file the decoder can handle, the listing also gains one playable mono WAV per speaker (`LEFT.wav`/`RIGHT.wav`/`MONO.wav`/…, Kind `Channel`, method `pcm`), named per `ChannelLayout`. The decode is best-effort: higher compression levels, unsupported bit depths/channel counts or malformed input leave the container/metadata view intact rather than failing. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApeFormatDescriptor` | `ApeFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Au` - -[`AuFormatDescriptor`](#auformatdescriptor) · [`AuReader`](#aureader) · [`AuReader.ParsedAu`](#aureaderparsedau) · [`AuWriter`](#auwriter) - -#### `AuFormatDescriptor` - -Exposes a Sun/NeXT `.au` / `.snd` file as an archive of `FULL.au`, one WAV per channel (after decoding μ-law/A-law/PCM, G.721 (G.726 @ 32 kbit/s), G.723 3-bit (G.726 @ 24 kbit/s) and 5-bit (G.726 @ 40 kbit/s) ADPCM, and G.722 sub-band ADPCM), and a `metadata.ini` carrying the encoding type, sample rate and any annotation string. - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveWriteConstraints`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AuFormatDescriptor` | `AuFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `AuReader` - -Sun / NeXT `.au` (`.snd`) header parser. The first 24 bytes are all big-endian: 4-byte magic `.snd` (0x2E 0x73 0x6E 0x64).uint32 data offset (≥ 24 — annotation bytes after byte 24 padded to this).uint32 data size (`0xFFFFFFFF` means "until EOF" in streaming).uint32 encoding (1=μ-law, 2=8-bit PCM, 3=16-bit BE PCM, 4=24-bit BE, 5=32-bit BE, 6/7=float, 23=G.721 ADPCM, 27=A-law).uint32 sample rate.uint32 channels. Bytes between header end (24) and `data offset` are an optional ASCII annotation string. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AuReader` | `AuReader()` | | -| `Read` | `ParsedAu Read(ReadOnlySpan data)` | | - -#### `AuReader.ParsedAu` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ParsedAu` | `ParsedAu(uint Encoding, int SampleRate, int NumChannels, byte[] SoundData, string Annotation)` | | -| `Annotation` | `string Annotation { get; init; }` | | -| `Encoding` | `uint Encoding { get; init; }` | | -| `NumChannels` | `int NumChannels { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | -| `SoundData` | `byte[] SoundData { get; init; }` | | - -#### `AuWriter` - -Sun / NeXT `.au` writer: the 24-byte big-endian header followed by big-endian linear PCM. Used by `AuFormatDescriptor` to assemble a multi-channel `.au` from per-channel mono inputs. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AuWriter` | `AuWriter()` | | -| `Write` | `byte[] Write(byte[] bigEndianInterleaved, int channels, int sampleRate, int bitsPerSample)` | Builds a linear-PCM `.au` from already big-endian interleaved samples. The encoding field is derived from `bitsPerSample` (8→2, 16→3, 24→4, 32→5). | - -### Namespace `FileFormat.Awb` - -[`AwbEntry`](#awbentry) · [`AwbFormatDescriptor`](#awbformatdescriptor) · [`AwbReader`](#awbreader) · [`AwbWriter`](#awbwriter) - -#### `AwbEntry` - -Represents a single audio entry inside a CRI Audio Wave Bank (AFS2). The wave bank stores raw codec payload (HCA, ADX, etc.) — payload bytes are surfaced verbatim. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AwbEntry` | `AwbEntry()` | | -| `CueId` | `uint CueId { get; init; }` | Game-specific cue identifier (lookup key into the paired ACB cue sheet). | -| `Name` | `string Name { get; init; }` | Synthetic name in the form `cue_NNNNN.bin` where NNNNN is the zero-padded cue ID. | -| `Offset` | `long Offset { get; init; }` | Absolute byte offset of this entry's data inside the AWB file (already alignment-resolved). | -| `Size` | `long Size { get; init; }` | Length of this entry's payload in bytes. | - -#### `AwbFormatDescriptor` - -CRI Audio Wave Bank (AFS2) — used by Capcom (Resident Evil, Monster Hunter), Sega (Yakuza, Persona 5), and other CRI Middleware titles. Contains raw codec payloads (HCA, ADX, etc.) which are surfaced verbatim — we do not decode the inner audio. References: `https://github.com/vgmstream/vgmstream` — vgmstream — implements AFS2/AWB parsing; the de-facto referenceCRI Middleware never published the AFS2 layout; it was recovered by the VGM ripping community - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AwbFormatDescriptor` | `AwbFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The underlying reader produces the entry's bytes (decoded if the format compresses per-entry); the returned stream is a `BoundedEntryStream` sized to the entry's logical length so adjacent entries and any trailing padding are physically unreachable through this view. | - -#### `AwbReader` - -Reads entries from a CRI Audio Wave Bank (AFS2). Audio payloads are surfaced as raw bytes — the inner codec (HCA, ADX, etc.) is the caller's concern. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AwbReader` | `AwbReader(Stream stream, bool leaveOpen = false)` | Initializes a new `AwbReader`, parsing the header, cue-ID table, and offset table. | -| `Alignment` | `uint Alignment { get; }` | Audio-data alignment in bytes (typically 0x20). Each entry's payload starts at the next multiple of this value. | -| `Entries` | `IReadOnlyList Entries { get; }` | All audio entries in the wave bank, in storage order. | -| `IdSize` | `byte IdSize { get; }` | Width in bytes of each cue-ID-table entry (typically 2). | -| `OffsetSize` | `byte OffsetSize { get; }` | Width in bytes of each offset-table entry (2 or 4). | -| `SubKey` | `uint SubKey { get; }` | Sub-key used by HCA decryption derivation. Preserved verbatim — we do not decrypt. | -| `Version` | `byte Version { get; }` | Container version byte from the header (1, 2, or 4 are observed in the wild). | -| `BuildMetadataIni` | `byte[] BuildMetadataIni()` | Returns a UTF-8 INI document describing the wave bank's header values for analyst tooling. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AwbEntry entry)` | Reads the raw payload bytes for a single entry. | - -#### `AwbWriter` - -Builds a CRI Audio Wave Bank (AFS2) container from in-memory payloads. Writes `DefaultVersion` with 4-byte offsets and 2-byte cue IDs for maximum compatibility. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AwbWriter` | `AwbWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `AwbWriter`. | -| `Alignment` | `uint Alignment { get; set; }` | Audio-data alignment in bytes. Must be a non-zero power of two. Defaults to 0x20. | -| `AddEntry` | `void AddEntry(byte[] data)` | Adds an entry with an auto-assigned sequential cue ID (next available, starting from 0 if empty). | -| `AddEntry` | `void AddEntry(uint cueId, byte[] data)` | Adds an entry with an explicit cue ID. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the AFS2 container and finalizes the stream. | - -### Namespace `FileFormat.Flac` - -[`FlacArchiveDescriptor`](#flacarchivedescriptor) · [`FlacFormatDescriptor`](#flacformatdescriptor) · [`FlacLayoutMap`](#flaclayoutmap) · [`FlacReader`](#flacreader) · [`FlacReader.AudioProperties`](#flacreaderaudioproperties) · [`FlacWriter`](#flacwriter) - -#### `FlacArchiveDescriptor` - -Archive-shaped view of a FLAC file: full blob + decoded per-channel WAVs. The existing `FlacFormatDescriptor` keeps its stream-decompressor contract for back-compat; this descriptor provides the recursive-descent path so users can pull out `LEFT.wav`/`RIGHT.wav` from a FLAC directly. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FlacArchiveDescriptor` | `FlacArchiveDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `FlacFormatDescriptor` - -Format descriptor and stream operations for the FLAC (Free Lossless Audio Codec) format. Also surfaces an archive view: `FULL.flac` plus one mono WAV per channel (`LEFT.wav`/`RIGHT.wav`/...) so multi-channel FLAC files can be decomposed in the archive browser. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveLayoutMap`, `IFormatDescriptor`, `IStreamFormatOperations`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FlacFormatDescriptor` | `FlacFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Compress` | `void Compress(Stream input, Stream output)` | | -| `Decompress` | `void Decompress(Stream input, Stream output)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `FlacLayoutMap` - -Walks a FLAC file and emits the byte-level layout: fLaC magic, STREAMINFO, other metadata blocks (PADDING, VORBIS_COMMENT, PICTURE, SEEKTABLE, etc.), and audio frames as `DefragBlockInfo` tiles. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream archive)` | | - -#### `FlacReader` - -Thin back-compat shim over `FlacCodec`. New code should call the codec class directly; this wrapper stays for one release cycle so existing callers don't break. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Decompress` | `static void Decompress(Stream input, Stream output)` | | -| `ReadAudioProperties` | `static AudioProperties ReadAudioProperties(ReadOnlySpan flacBytes)` | | - -#### `FlacReader.AudioProperties` - -Back-compat mirror of `AudioProperties`. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AudioProperties` | `AudioProperties(int SampleRate, int Channels, int BitsPerSample, long TotalSamples)` | Back-compat mirror of `AudioProperties`. | -| `BitsPerSample` | `int BitsPerSample { get; init; }` | | -| `Channels` | `int Channels { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | -| `TotalSamples` | `long TotalSamples { get; init; }` | | - -#### `FlacWriter` - -Writes a FLAC stream from raw interleaved little-endian PCM data. Assumes 16-bit stereo 44100 Hz input by default. Uses FIXED prediction (orders 0-4) and LPC prediction (orders 1-8) with Rice-coded residuals, choosing whichever produces smaller output. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compress` | `static void Compress(Stream input, Stream output)` | Compresses raw PCM data to FLAC format. Input is expected to be interleaved little-endian 16-bit signed PCM (stereo 44100 Hz). | - -### Namespace `FileFormat.Fmod` - -[`FmodFormatDescriptor`](#fmodformatdescriptor) - -#### `FmodFormatDescriptor` - -FMOD Sample Bank (.fsb, version 5) surfaced as an archive. Enumerates the individual sample blobs plus the header / name-table raw sections and summary metadata. Audio payloads are kept in their native encoded form (Vorbis/XMA/ADPCM/etc.) — no decoding. References: `https://www.fmod.com` — vendor — the FSB5 container is not publicly documented`https://github.com/HearthSim/python-fsb5` — python-fsb5 — open-source FSB5 parser, a de-facto format reference`https://github.com/vgmstream/vgmstream` — vgmstream — maintained FSB5 support - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FmodFormatDescriptor` | `FmodFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single FSB entry as a bounded read-only stream. The `BuildEntries` parser produces decoded byte buffers per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so adjacent samples cannot leak. | - -### Namespace `FileFormat.It` - -[`ItFormatDescriptor`](#itformatdescriptor) - -#### `ItFormatDescriptor` - -Exposes an Impulse Tracker (IT) module as an archive of `FULL.it`, `metadata.ini`, a rendered `SONG.wav` (Kind `Track`; 44100 Hz stereo 16-bit), the packed `patterns/pattern_NN.bin` data, `instruments/NN_{name}.bin` instrument blocks, and each sample decoded to a playable mono WAV (`samples/NN_{name}.wav`) at its C5 speed. IT214/IT215-compressed samples are decompressed via `ItSampleDecompressor`. The song is rendered by `ItPlayer` (NNA/virtual channels, envelopes, resonant filter, effects A..Z); rendering failures degrade gracefully to the non-rendered entries. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ItFormatDescriptor` | `ItFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Midi` - -[`MidiFormatDescriptor`](#midiformatdescriptor) - -#### `MidiFormatDescriptor` - -Surfaces a Standard MIDI File as an archive: one `FULL.mid`, one `track_NN_.mid` per `MTrk` chunk (re-wrapped as a format-0 single-track file), one `metadata.ini` carrying song title / copyright / tempo / time signature, and `lyrics.txt` if lyric meta-events are present. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveWriteConstraints`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MidiFormatDescriptor` | `MidiFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Mod` - -[`ModFormatDescriptor`](#modformatdescriptor) - -#### `ModFormatDescriptor` - -Exposes a ProTracker / SoundTracker / NoiseTracker MOD file as an archive of `FULL.mod`, a `metadata.ini` summary, a rendered `SONG.wav` (44100 Hz stereo 16-bit, played from order 0 through the shared tracker mixer), `patterns/pattern_NN.bin` (raw N×channels×64×4 pattern blocks) and `samples/NN_{name}.wav` per non-empty sample (each instrument decoded to a mono 16-bit WAV at the finetune-correct PAL replay rate). Rendering degrades gracefully: any failure leaves the previous surface (full file + patterns + samples) intact, with samples falling back to their raw 8-bit blobs. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ModFormatDescriptor` | `ModFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Mp3` - -[`Id3v1Reader`](#id3v1reader) · [`Id3v1Reader.Tag`](#id3v1readertag) · [`Id3v2Reader`](#id3v2reader) · [`Id3v2Reader.Frame`](#id3v2readerframe) · [`Id3v2Writer`](#id3v2writer) · [`Mp3FormatDescriptor`](#mp3formatdescriptor) · [`Mp3LayoutMap`](#mp3layoutmap) · [`Mp3Optimizer`](#mp3optimizer) - -#### `Id3v1Reader` - -Parses an ID3v1 (/v1.1) tag — the fixed 128-byte trailer at the end of many older MP3 files. The tag starts with ASCII `"TAG"`; fields are ISO-8859-1, space-padded, typically NUL-terminated. ID3v1.1 cannibalises the last two bytes of the comment field (28 bytes of text + 0x00 + 1-byte track number) which this parser detects via the v1.1 sentinel. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Id3v1Reader` | `Id3v1Reader()` | | -| `Read` | `Tag Read(ReadOnlySpan file)` | | - -#### `Id3v1Reader.Tag` - -Parsed fields, or `null` if the file doesn't carry an ID3v1 tag. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Tag` | `Tag(string Title, string Artist, string Album, string Year, string Comment, int? Track, byte GenreByte)` | Parsed fields, or `null` if the file doesn't carry an ID3v1 tag. | -| `Album` | `string Album { get; init; }` | | -| `Artist` | `string Artist { get; init; }` | | -| `Comment` | `string Comment { get; init; }` | | -| `GenreByte` | `byte GenreByte { get; init; }` | | -| `Title` | `string Title { get; init; }` | | -| `Track` | `int? Track { get; init; }` | | -| `Year` | `string Year { get; init; }` | | - -#### `Id3v2Reader` - -Parses ID3v2 tag frames prepended to an MP3. Extracts common text frames (TIT2/TPE1/TALB/TDRC/…), attached picture frames (APIC), URL frames (WOAS/WOAF/…), and comment frames (COMM). Sync-safe integer handling and de-unsynchronisation are implemented per ID3v2.4; the older v2.3 tags follow the same layout and read correctly against this parser. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Id3v2Reader` | `Id3v2Reader()` | | -| `Read` | `ValueTuple> Read(ReadOnlySpan data)` | Returns extracted frames, or an empty list if no ID3v2 tag is present. | - -#### `Id3v2Reader.Frame` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Frame` | `Frame(string Id, string MimeType, string Description, byte[] Payload)` | | -| `Description` | `string Description { get; init; }` | | -| `Id` | `string Id { get; init; }` | | -| `MimeType` | `string MimeType { get; init; }` | | -| `Payload` | `byte[] Payload { get; init; }` | | - -#### `Id3v2Writer` - -Emits an ID3v2.4 tag. Supports text frames (TIT2, TPE1, TALB, TDRC, TCON, TRCK, TCOM, TPUB, COMM), URL frames (WOAF, WORS, WOAS, …), APIC picture frames with MIME auto-detection (JPEG / PNG), and USLT lyric frames. Format: the archive-view of an MP3 reads cover.jpg / metadata.ini; this writer takes the same convention and produces an ID3v2 tag blob that the Mp3FormatDescriptor prepends to the audio stream on Create. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Id3v2Writer` | `Id3v2Writer()` | | -| `AddLyrics` | `void AddLyrics(string lyrics, string language = "eng", string description = "")` | Adds an unsynchronised lyric/text transcription (USLT) frame. | -| `AddPicture` | `void AddPicture(byte[] pictureBytes, string description = "Cover", byte pictureType = 3)` | Adds an APIC picture frame. MIME type is auto-detected from the first bytes of `pictureBytes` (JPEG `FF D8 FF`; PNG `89 50 4E 47`; GIF `47 49 46 38`). `description` is a human-readable label. | -| `AddText` | `void AddText(string frameId, string text)` | Adds a text frame (TIT2, TPE1, TALB, …). Text is written as UTF-8. | -| `AddUrl` | `void AddUrl(string frameId, string url)` | Adds a URL frame (WOAF, WORS, …). Per the spec URL frames have no encoding byte. | -| `Build` | `byte[] Build()` | Emits the complete ID3v2.4 tag bytes, ready to be prepended to the audio frames of an MP3 file. | - -#### `Mp3FormatDescriptor` - -Surfaces an MP3 file as an archive whose layout is shaped for human/tool use: one `FULL.mp3`, one `metadata.ini` carrying all text/URL/comment fields as `key=value`, one `cover.` per APIC picture, and `lyrics.txt` for USLT. When both ID3v1 and ID3v2 are present the archive surfaces `id3v1/metadata.ini` + `id3v2/metadata.ini` so callers can see which fields come from which tag version. When the MPEG audio decodes (Layer III via `Codec.Mp3`), the archive also surfaces one mono `.wav` per channel; the `FULL.mp3` entry always carries the original frames unchanged. Inputs the decoder can't handle (e.g. Layer I/II) fall back to `FULL.mp3` + metadata only. - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveWriteConstraints`, `IFileInternalChunkMover`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Mp3FormatDescriptor` | `Mp3FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `Mp3LayoutMap` - -Walks an MP3 file and emits `DefragBlockInfo` tiles for the ID3v2 header, tag frames, padding, audio data region, APEv2 tag, and ID3v1 trailer. Audio frames are not individually decoded -- just the overall region boundaries are located. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream file)` | | - -#### `Mp3Optimizer` - -Compacts oversized ID3v2 padding in an MP3 file. If the ID3v2 tag has more than 256 bytes of trailing padding, the audio data is shifted forward and the tag is rewritten with exactly 256 bytes of padding (standard convention to allow future in-place edits without a full file rewrite). - -| Member | Signature | Summary | -| --- | --- | --- | -| `TargetPadding` | `const int TargetPadding` | The target padding size after optimization. 256 bytes is the conventional allowance for future in-place ID3v2 edits. | -| `Optimize` | `static void Optimize(Stream file)` | Optimizes the MP3 file in `file` by compacting ID3v2 padding. The stream must be readable, writable, and seekable. If no ID3v2 tag exists or padding is already <= 256 bytes, this is a no-op. | -| `Optimize` | `static void Optimize(Stream file, MetadataPlacementProfile profile)` | Optimizes the MP3 file with an optional metadata placement profile. The MP3 format requires ID3v2 at the start per spec, so the profile does not affect ID3v2 tag position — only the padding compaction is performed. | - -### Namespace `FileFormat.Ogg` - -[`OggFormatDescriptor`](#oggformatdescriptor) · [`OggLayoutMap`](#ogglayoutmap) · [`OggPageParser`](#oggpageparser) · [`OggPageParser.Page`](#oggpageparserpage) · [`VorbisCommentReader`](#vorbiscommentreader) · [`VorbisCommentReader.Parsed`](#vorbiscommentreaderparsed) - -#### `OggFormatDescriptor` - -Surfaces an OGG container as an archive of the full file + per-logical-stream raw packet blobs + the Vorbis/Opus comment block. When the primary audio stream decodes (Vorbis via `Codec.Vorbis`, Opus via `Codec.Opus`) the archive also surfaces one mono `.wav` per channel; streams the decoder can't handle fall back to the raw packet blobs only. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OggFormatDescriptor` | `OggFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `OggLayoutMap` - -Walks an OGG bitstream at the page level and emits `DefragBlockInfo` tiles for block-chart visualization. Codec header pages (first page of each logical stream) are classified as MetadataReserved; subsequent audio data pages are classified as Used. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream file)` | | - -#### `OggPageParser` - -Walks an Ogg bitstream at the page level (RFC 3533). Each page begins with the magic `OggS`, carries a header of at least 27 bytes, a segment table, and the concatenated packet segments. This parser does not reassemble continuing packets across pages — consumers that need whole packets call `StreamPackets`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `OggPageParser` | `OggPageParser()` | | -| `Pages` | `List Pages(ReadOnlySpan data)` | | -| `StreamPackets` | `IEnumerable StreamPackets(ReadOnlySpan data, uint serial)` | Yields reassembled packet blobs for a single logical bitstream (filtered by `serial`). | - -#### `OggPageParser.Page` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Page` | `Page(uint Serial, byte Flags, byte[][] Segments)` | | -| `Flags` | `byte Flags { get; init; }` | | -| `Segments` | `byte[][] Segments { get; init; }` | | -| `Serial` | `uint Serial { get; init; }` | | - -#### `VorbisCommentReader` - -Parses a Vorbis / Opus comment block. Layout: vendor length + vendor string + comment count + N × (comment length + UTF-8 string). Used by both Vorbis and Opus streams identically — Vorbis prefixes the block with the packet-type byte `0x03` + `"vorbis"`; Opus prefixes it with `"OpusTags"`. Callers pass the block *after* stripping those prefixes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VorbisCommentReader` | `VorbisCommentReader()` | | -| `Read` | `Parsed Read(ReadOnlySpan body)` | | - -#### `VorbisCommentReader.Parsed` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Parsed` | `Parsed(string Vendor, IReadOnlyList> Comments)` | | -| `Comments` | `IReadOnlyList> Comments { get; init; }` | | -| `Vendor` | `string Vendor { get; init; }` | | - -### Namespace `FileFormat.Psf` - -[`PsfConstants`](#psfconstants) · [`PsfCrc32`](#psfcrc32) · [`PsfEntry`](#psfentry) · [`PsfFormatDescriptor`](#psfformatdescriptor) · [`PsfReader`](#psfreader) · [`PsfWriter`](#psfwriter) - -#### `PsfConstants` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Crc32Polynomial` | `const uint Crc32Polynomial` | | -| `EntryHeader` | `const string EntryHeader` | | -| `EntryProgram` | `const string EntryProgram` | | -| `EntryReserved` | `const string EntryReserved` | | -| `EntryTags` | `const string EntryTags` | | -| `HeaderSize` | `const int HeaderSize` | | -| `Magic` | `static readonly byte[] Magic` | | -| `TagPrefix` | `const string TagPrefix` | | -| `VersionPs1` | `const byte VersionPs1` | | - -#### `PsfCrc32` - -Standard CRC-32 (IEEE 802.3 / zlib polynomial 0xEDB88320). Inlined here because FileFormat.* projects only reference `Compression.Registry`, not `Compression.Core` where the shared (and hardware-accelerated) `Crc32` lives. PSF stores this CRC over the compressed program bytes inside its 16-byte header, so a tiny dependency-free table-driven implementation is sufficient. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compute` | `static uint Compute(ReadOnlySpan data)` | Computes the standard CRC-32 of the given bytes. | - -#### `PsfEntry` - -A synthetic entry exposed by `PsfReader` for the flat-archive view of a PSF. PSFs aren't true archives — these entries surface the container's logical components (header, reserved blob, decompressed program, parsed tags) so the standard archive browse/extract UX works against them. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsfEntry` | `PsfEntry()` | | -| `Data` | `byte[] Data { get; init; }` | Raw bytes of the entry. For `program.bin` these are post-zlib decompression. | -| `Name` | `string Name { get; init; }` | Synthetic entry name (e.g. `header.bin`, `program.bin`, `tags.txt`). | - -#### `PsfFormatDescriptor` - -Portable Sound Format (PSF) — game-music archival container wrapping a compressed program plus tags. References: Neill Corlett, "PSF — Portable Sound Format" specification (psf_format.txt) — the defining document`https://en.wikipedia.org/wiki/Portable_Sound_Format` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsfFormatDescriptor` | `PsfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `PsfReader` - -Reads a Portable Sound Format (PSF) container: 16-byte header, optional reserved blob, zlib-compressed program section, and an optional `[TAG]` key/value block. Magic and CRC mismatches surface as `IsCorrupt` rather than throwing (except for outright bad magic, which is unrecoverable). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsfReader` | `PsfReader(Stream stream, bool leaveOpen = false)` | Opens a PSF container from the given stream. | -| `ActualProgramCrc32` | `uint ActualProgramCrc32 { get; }` | The CRC-32 actually computed by the reader over the raw compressed program bytes. | -| `Entries` | `IReadOnlyList Entries { get; }` | The flat synthetic-entry view: header.bin, [reserved.bin], program.bin, [tags.txt]. | -| `HeaderBytes` | `byte[] HeaderBytes { get; }` | The raw 16-byte header bytes (kept so the synthetic header.bin entry can round-trip exactly). | -| `IsCorrupt` | `bool IsCorrupt { get; }` | True when `ProgramCrc32` doesn't match `ActualProgramCrc32`. Reader does not throw on mismatch. | -| `ProgramCrc32` | `uint ProgramCrc32 { get; }` | The CRC-32 value as stored in the header (computed by the producer over the COMPRESSED program bytes). | -| `ProgramData` | `byte[] ProgramData { get; }` | The decompressed program payload. Always non-null; empty if the program section was empty. | -| `ReservedData` | `byte[] ReservedData { get; }` | The reserved-area blob (length determined by the header field). May be empty. | -| `Tags` | `IReadOnlyDictionary Tags { get; }` | Parsed tag block (UTF-8 / Latin-1, one `key=value` per line). Empty if the file had no `[TAG]` sentinel. | -| `VersionByte` | `byte VersionByte { get; }` | Platform/version byte from offset 3 of the header (e.g. 0x01 = PS1, 0x02 = PS2). | -| `Dispose` | `void Dispose()` | | - -#### `PsfWriter` - -Writes a Portable Sound Format (PSF) container. The CRC stored in the header is over the COMPRESSED program bytes (per spec) — common bug source if mistakenly computed over the uncompressed payload, which the round-trip test guards against. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `PsfWriter` | `PsfWriter(Stream stream, bool leaveOpen = false)` | Initializes a new `PsfWriter` bound to `stream`. | -| `ProgramData` | `byte[] ProgramData { get; set; }` | Uncompressed program payload. Will be zlib-compressed at `CompressionLevel.Optimal`. | -| `ReservedData` | `byte[] ReservedData { get; set; }` | Reserved-area blob written verbatim between header and compressed program. | -| `Tags` | `Dictionary Tags { get; }` | Tag key/value pairs serialized as a UTF-8 `[TAG]` block. Empty -> no tag block. | -| `VersionByte` | `byte VersionByte { get; set; }` | The platform/version byte (default 0x01 = PS1). | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Serializes all fields to the underlying stream. Idempotent. | - -### Namespace `FileFormat.S3m` - -[`S3mFormatDescriptor`](#s3mformatdescriptor) - -#### `S3mFormatDescriptor` - -Exposes a Scream Tracker 3 (S3M) module as an archive of `FULL.s3m`, `metadata.ini`, a rendered `SONG.wav` (44100 Hz stereo 16-bit, played from order 0 through the shared tracker mixer), `patterns/pattern_NN.bin` (raw packed pattern blocks with their 2-byte length prefix stripped), and `samples/NN_{name}.wav` per PCM instrument (decoded to a mono 16-bit WAV at the instrument's C2SPD). Rendering degrades gracefully: any failure leaves the previous surface intact, with samples falling back to their raw blobs. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `S3mFormatDescriptor` | `S3mFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.Wav` - -[`WavChannelMux`](#wavchannelmux) · [`WavFormatDescriptor`](#wavformatdescriptor) · [`WavLayoutMap`](#wavlayoutmap) · [`WavOptimizer`](#wavoptimizer) · [`WavReader`](#wavreader) · [`WavReader.ParsedWav`](#wavreaderparsedwav) - -#### `WavChannelMux` - -Shared helper for PCM-container writers (WAV / CAF / W64 / RF64): collects per-channel mono WAV inputs (LEFT/RIGHT/CENTER/… or CH_N), validates they agree on sample rate + bit depth, and interleaves them into a single little-endian integer PCM buffer. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GatherChannels` | `static List> GatherChannels(IReadOnlyList> fileList)` | Picks the per-channel mono WAV inputs from a flat list of (name, data) pairs, ordered by the conventional channel layout. Inputs whose names are not `FULL.*` and end in `.wav` are treated as channels. | -| `Interleave` | `static ValueTuple Interleave(IReadOnlyList> channelBlobs)` | Reads each mono channel WAV, verifies they share sample rate and bit depth and have equal frame counts, then interleaves into one PCM buffer. | - -#### `WavFormatDescriptor` - -Exposes a WAV/RIFF file as an archive of `FULL.wav` plus one mono WAV per channel plus any ancillary RIFF metadata chunks (INFO/LIST/bext). - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IArchiveWriteConstraints`, `IFileInternalChunkMover`, `IFileInternalLayoutMap`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WavFormatDescriptor` | `WavFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateChunks` | `IEnumerable EnumerateChunks(Stream file)` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `WavLayoutMap` - -Walks a WAV (RIFF/WAVE) file's chunk structure and emits `DefragBlockInfo` tiles. The RIFF header and fmt chunk are MetadataReserved, the data chunk is Used, and metadata chunks (LIST/INFO, bext, iXML, etc.) are Used with Cold classification. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream file)` | | - -#### `WavOptimizer` - -WAV optimizer that ensures the data chunk comes immediately after fmt (data-first layout for streaming). Metadata chunks (LIST, bext, iXML, etc.) are moved after the data chunk. - -Implements `IFileInternalChunkMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WavOptimizer` | `WavOptimizer()` | | -| `Optimize` | `void Optimize(Stream file)` | | -| `Optimize` | `void Optimize(Stream file, MetadataPlacementProfile profile)` | | - -#### `WavReader` - -RIFF/WAVE header + per-channel PCM extraction. Supports format codes: 1 — linear PCM (8/16/24/32-bit).3 — IEEE float (32-bit / 64-bit).6 — G.711 A-law (decoded to 16-bit LE PCM via `Codec.ALaw`).7 — G.711 μ-law (decoded to 16-bit LE PCM via `Codec.MuLaw`).0x0002 — Microsoft ADPCM (decoded via `Codec.MsAdpcm`).0x0011 — IMA ADPCM (decoded via `Codec.ImaAdpcm`).0x0022 — DSP Group TrueSpeech (decoded to mono 16-bit PCM via `Codec.TrueSpeech`).0x0031 — GSM 06.10 full-rate (decoded via `Codec.Gsm610`).0xFFFE — WAVEFORMAT_EXTENSIBLE, real sub-format at +24 in `fmt` body. After decoding, `InterleavedPcm` always holds little-endian integer samples and `BitsPerSample` reflects the decoded width, so downstream callers (e.g. `WavFormatDescriptor`) see PCM regardless of the on-wire compression. `FormatCode` also reflects the post-decode code (always 1 when we decoded). Reads only the `fmt` and `data` chunks; skips metadata chunks but leaves them addressable via `MetadataChunks`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WavReader` | `WavReader()` | | -| `Read` | `ParsedWav Read(ReadOnlySpan data)` | | - -#### `WavReader.ParsedWav` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ParsedWav` | `ParsedWav(int NumChannels, int SampleRate, int BitsPerSample, int FormatCode, byte[] InterleavedPcm, IReadOnlyList> MetadataChunks, uint? ChannelMask = null)` | | -| `BitsPerSample` | `int BitsPerSample { get; init; }` | | -| `ChannelMask` | `uint? ChannelMask { get; init; }` | | -| `FormatCode` | `int FormatCode { get; init; }` | | -| `InterleavedPcm` | `byte[] InterleavedPcm { get; init; }` | | -| `MetadataChunks` | `IReadOnlyList> MetadataChunks { get; init; }` | | -| `NumChannels` | `int NumChannels { get; init; }` | | -| `SampleRate` | `int SampleRate { get; init; }` | | - -### Namespace `FileFormat.WavPack` - -[`WavPackFormatDescriptor`](#wavpackformatdescriptor) - -#### `WavPackFormatDescriptor` - -Surfaces a WavPack stream (`.wv`/`.wvc`) as a read-only archive of its constituent blocks. Each 32-byte `wvpk` block header plus its body is extracted verbatim as `block_NNNN.wv`; a `metadata.ini` lists the top-level stream parameters (sample count, rate, channels, bit depth). When the stream is a lossless WavPack v4/v5 file the decoder can handle, the listing also gains one playable mono WAV per speaker (`LEFT.wav`/ `RIGHT.wav`/`MONO.wav`/…, Kind `Channel`, method `pcm`), named per `ChannelLayout`. The decode is best-effort: hybrid/lossy, float, DSD or otherwise unsupported streams leave the block/metadata view intact rather than failing. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WavPackFormatDescriptor` | `WavPackFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileFormat.WwiseBnk` - -[`HircObject`](#hircobject) · [`WemEntry`](#wementry) · [`WwiseBnkFormatDescriptor`](#wwisebnkformatdescriptor) · [`WwiseBnkReader`](#wwisebnkreader) - -#### `HircObject` - -| Member | Signature | Summary | -| --- | --- | --- | -| `HircObject` | `HircObject()` | | -| `Id` | `uint Id { get; init; }` | | -| `Size` | `uint Size { get; init; }` | | -| `Type` | `byte Type { get; init; }` | | - -#### `WemEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `WemEntry` | `WemEntry()` | | -| `Offset` | `uint Offset { get; init; }` | | -| `Size` | `uint Size { get; init; }` | | -| `WemId` | `uint WemId { get; init; }` | | - -#### `WwiseBnkFormatDescriptor` - -Audiokinetic Wwise SoundBank (.bnk) — BKHD/DIDX/DATA/HIRC chunked container. References: `https://github.com/bnnm/wwiser` — wwiser — most complete open .bnk parser (community reverse engineering)`https://github.com/eXpl0it3r/bnkextr` — bnkextr — minimal BKHD/DIDX/DATA extractor`https://www.audiokinetic.com/` — Audiokinetic — vendor; the bank format itself is not publicly documented - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `WwiseBnkFormatDescriptor` | `WwiseBnkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single bank entry as a bounded read-only stream. Handles the synthetic `FULL.bnk` passthrough, the `metadata.ini` summary, `hirc_objects.txt`, and per-WEM positional slices. All returns are wrapped in `BoundedEntryStream` sized to their logical length so adjacent regions can't leak. | - -#### `WwiseBnkReader` - -Parses a Wwise SoundBank (.bnk) file as a sequence of RIFF-style 4CC+uint32-size chunks. Known chunks: BKHD (header), DIDX (data index), DATA (embedded WEM blob pool), HIRC (hierarchy of sound/event objects), STID (soundbank id→name table), INIT (init data), STMG (state manager). - -| Member | Signature | Summary | -| --- | --- | --- | -| `WwiseBnkReader` | `WwiseBnkReader(Stream stream)` | | -| `BankId` | `uint BankId { get; }` | | -| `BankVersion` | `uint BankVersion { get; }` | | -| `ChunkSpans` | `Dictionary> ChunkSpans { get; }` | Maps each top-level chunk tag to its (body offset, body length) so callers can surface a raw per-section blob (BKHD.bin, HIRC.bin, …). | -| `Chunks` | `Dictionary Chunks { get; }` | | -| `DataChunkOffset` | `long DataChunkOffset { get; }` | | -| `DataChunkSize` | `long DataChunkSize { get; }` | | -| `HircObjects` | `List HircObjects { get; }` | | -| `Wems` | `List Wems { get; }` | | -| `ExtractChunk` | `byte[] ExtractChunk(string tag)` | Reads a top-level chunk's raw body bytes by its 4CC tag. | -| `ExtractWem` | `byte[] ExtractWem(WemEntry e)` | | - -### Namespace `FileFormat.Xm` - -[`XmFormatDescriptor`](#xmformatdescriptor) - -#### `XmFormatDescriptor` - -Exposes a FastTracker II XM module as an archive of `FULL.xm`, `metadata.ini`, a rendered `SONG.wav` (Kind `Track`; 44100 Hz stereo 16-bit), the packed `patterns/pattern_NN.bin` data, and per-instrument samples decoded to playable mono WAVs (`instruments/NN_{name}/MM_{sample}.wav`) at each sample's relative-note/finetune rate. The song is rendered by `XmPlayer` (linear/Amiga frequency tables, envelopes, auto-vibrato, fadeout, volume column and effects 0..X); rendering failures degrade gracefully to the non-rendered entries. - -Implements `IArchiveFormatOperations`, `IArchiveInMemoryExtract`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `XmFormatDescriptor` | `XmFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `ExtractEntry` | `void ExtractEntry(Stream input, string entryName, Stream output, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | +Every public and protected member of all 100 types, generated from the built assembly and its XML documentation, is in [REFERENCE.md](https://github.com/Hawkynt/CompressionWorkbench/blob/main/Hawkynt.FileFormats.Audio/REFERENCE.md). diff --git a/Hawkynt.FileFormats.FileSystems/README.md b/Hawkynt.FileFormats.FileSystems/README.md index b2bf80568..7f7117165 100644 --- a/Hawkynt.FileFormats.FileSystems/README.md +++ b/Hawkynt.FileFormats.FileSystems/README.md @@ -366,10071 +366,7 @@ The filesystem package is built against the repository's shared Core version. Re -### Namespace `FileFormat.BinCue` - -[`BinCueEntry`](#bincueentry) · [`BinCueFormatDescriptor`](#bincueformatdescriptor) · [`BinCueInPlaceModifier`](#bincueinplacemodifier) · [`BinCueInPlaceModifier.SectorGeometry`](#bincueinplacemodifiersectorgeometry) · [`BinCueLayoutMap`](#bincuelayoutmap) · [`BinCueReader`](#bincuereader) - -#### `BinCueEntry` - -Represents a file or directory entry in a BIN/CUE disc image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinCueEntry` | `BinCueEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path within the disc image, using forward slashes. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the filename or directory name of this entry. | -| `Size` | `long Size { get; init; }` | Gets the file size in bytes (0 for directories). | -| `StartLba` | `int StartLba { get; init; }` | Gets the starting LBA (Logical Block Address) of this entry's data. | - -#### `BinCueFormatDescriptor` - -BIN/CUE CD-ROM image — raw 2352-byte sector dump (.bin) described by a CDRWIN cue sheet (.cue). References: Golden Hawk Technology CDRWIN user manual — the defining cue-sheet documentation`https://en.wikipedia.org/wiki/Cue_sheet_(computing)` — cue-sheet syntax overviewECMA-130 — CD-ROM sector layout (mode 1 / mode 2 framing) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinCueFormatDescriptor` | `BinCueFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Rewrites raw CD sectors in place. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed byte offset `lba * sectorSize + dataOffset`; everything outside the touched 2 048-byte user-data region stays byte-identical. Inputs not matching the synthetic sector schema are skipped — inner-ISO 9660 directory mutation is delegated to `FileSystem.Iso` and is out of scope for the sector-rewrite modifier. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Zeros the 2 048-byte user-data region of each named sector. The sector framing bytes (sync / address / mode / EDC) on raw geometries are preserved so the LBA-to-offset map and the rest of the image remain byte-identical. | - -#### `BinCueInPlaceModifier` - -In-place sector-rewrite modifier for a BIN/CUE CD-ROM disc image. Operates at the raw 2 048-byte user-data region of each CD sector at the fixed byte offset `lba * sectorSize + dataOffset`, where `sectorSize` and `dataOffset` are the geometry detected from the image (raw 2 352 Mode 1, raw 2 352 Mode 2 Form 1, 2 336-byte sectors, or flat 2 048-byte cooked sectors). Scope. This rewrites the user-data bytes inside an existing sector or appends a brand-new sector at the end of the image. It does not understand the inner ISO 9660 directory structure — that is the job of `IsoWriter` / its reader. Synthetic entry names of the form `sector-NNNN.bin` address a single sector LBA; the modifier neither parses nor mutates ISO 9660 directory records. Sync pattern (12 B), 3-byte address, 1-byte mode, and the EDC/ECC tail of raw sectors are preserved when an existing sector is rewritten and synthesised (sync + zero address + mode byte + zero EDC) when a brand-new sector is appended.True in-place. Writes touch only the 2 048-byte user-data region of the targeted sector. Bytes outside that region — header bytes of the same sector, every untouched sector, the system area (LBA 0-15), the PVD at LBA 16, and the ISO root directory — stay byte-identical at their original byte offsets. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddOrReplaceSectors` | `static void AddOrReplaceSectors(Stream image, IEnumerable> inputs)` | Routes each input through the sector-rewrite path. Inputs whose `ArchiveName` matches `sector-NNNN.bin` are written at the fixed LBA byte offset (existing sector → in-place rewrite, EOF-past sector → append). Inputs whose `ArchiveName` doesn't match the schema are refused — they would belong to an inner ISO 9660 directory entry, and ISO 9660 directory mutation is delegated to `FileSystem.Iso`. | -| `AppendSector` | `static void AppendSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Extends the image so that sector `lba` exists, writing `userData` as its 2 048-byte payload. Intermediate sectors (between the previous EOF sector and `lba`) are appended with the format-correct sync + zero address + mode byte + zero EDC framing for raw geometries, or plain zeros for cooked. | -| `DetectGeometry` | `static SectorGeometry DetectGeometry(Stream image)` | Detects the sector geometry of `image` the same way `BinCueReader` does — by probing for the `CD001` PVD signature at LBA 16. Falls back to raw Mode 1 (2 352 / 16) when no probe succeeds, matching the reader's behaviour. | -| `FormatSectorEntryName` | `static string FormatSectorEntryName(int lba)` | Formats a sector LBA into the synthetic entry name used by the in-place modifier. Six-digit zero-padded LBA so 0..999 999 sort lexicographically the same as numerically. | -| `RemoveSectors` | `static void RemoveSectors(Stream image, IEnumerable entryNames)` | Zeros each named `sector-NNNN.bin`. Names that don't match the schema are refused; sectors past EOF are still skipped (there's nothing to remove). The framing bytes of an existing sector — sync/address/mode/EDC — are preserved. | -| `TryParseSectorEntryName` | `static bool TryParseSectorEntryName(string entryName, out int lba)` | Parses a synthetic `sector-NNNN.bin` entry name and returns the embedded sector LBA. Names that don't match the schema return `false`. The callers refuse such a name rather than passing over it: an entry that cannot be placed is not an entry to discard quietly. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData)` | Rewrites the 2 048-byte user-data region of sector `lba` in place. Other bytes — sync/header/EDC for raw sectors, every other sector, every other region of the image — are untouched. If `lba` points past current EOF, the image is grown sector-by-sector with appended-sector framing (`AppendSector`). | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Variant of `WriteSector` that reuses a previously-probed geometry, avoiding a redundant PVD probe per call when a caller is rewriting several sectors back-to-back. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba)` | Zeros the 2 048-byte user-data region of sector `lba` in place. The sector framing bytes are preserved; only the user data is wiped. Returns `true` if the sector existed (and was zeroed), `false` if `lba` is past EOF. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba, SectorGeometry geom)` | Variant of `ZeroSector` reusing a previously-probed geometry. | - -#### `BinCueInPlaceModifier.SectorGeometry` - -Detected on-disk sector geometry for a BIN/CUE image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SectorGeometry` | `SectorGeometry(int SectorSize, int DataOffset)` | Detected on-disk sector geometry for a BIN/CUE image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `SectorSize` | `int SectorSize { get; init; }` | | - -#### `BinCueLayoutMap` - -Walks a BIN/CUE disc image and emits the byte-level layout showing the track/sector structure: system area, volume descriptors, directory records, and file data regions based on the detected sector geometry. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream stream)` | | - -#### `BinCueReader` - -Reads the ISO 9660 file system embedded in a BIN/CUE CD-ROM disc image. Supports raw 2352-byte sectors (Mode 1 and Mode 2 Form 1), 2336-byte sectors, and plain 2048-byte ISO sector streams. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BinCueReader` | `BinCueReader(Stream stream, bool leaveOpen = false)` | Initializes a new `BinCueReader` from a BIN stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries found in the ISO 9660 file system. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(BinCueEntry entry)` | Extracts the raw data for a file entry. | - -### Namespace `FileFormat.Cdi` - -[`CdiEntry`](#cdientry) · [`CdiFormatDescriptor`](#cdiformatdescriptor) · [`CdiInPlaceModifier`](#cdiinplacemodifier) · [`CdiInPlaceModifier.SectorGeometry`](#cdiinplacemodifiersectorgeometry) · [`CdiReader`](#cdireader) - -#### `CdiEntry` - -Represents a file or directory entry in a DiscJuggler CDI disc image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CdiEntry` | `CdiEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path within the disc image, using forward slashes. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the filename or directory name of this entry. | -| `Size` | `long Size { get; init; }` | Gets the file size in bytes (0 for directories). | -| `StartLba` | `int StartLba { get; init; }` | Gets the starting LBA (Logical Block Address) of this entry's data. | - -#### `CdiFormatDescriptor` - -DiscJuggler CDI disc image (Padus) — track data plus trailing session/track descriptor blocks. References: `https://en.wikipedia.org/wiki/DiscJuggler` — background on the creating toolCDIrip source — the DiscJuggler layout was reverse-engineered by the disc-preservation community; Padus never published a spec - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CdiFormatDescriptor` | `CdiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Rewrites raw CD sectors in place. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed byte offset `lba * sectorSize + dataOffset`; everything outside the touched 2 048-byte user-data region — including the 8-byte CDI footer — stays byte-identical (the footer migrates with the new EOF when the data area grows past the previous end). Inputs not matching the synthetic sector schema are skipped — inner-ISO 9660 directory mutation is delegated to `FileSystem.Iso` and is out of scope for the sector-rewrite modifier. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Zeros the 2 048-byte user-data region of each named sector. Sector framing bytes (sync / address / mode / EDC) on raw geometries and the trailing CDI footer are preserved so the LBA-to-offset map and the rest of the image remain byte-identical. | - -#### `CdiInPlaceModifier` - -In-place sector-rewrite modifier for a DiscJuggler CDI disc image. Operates at the raw 2 048-byte user-data region of each CD sector at the fixed byte offset `lba * sectorSize + dataOffset`, where `sectorSize` and `dataOffset` are the geometry detected from the data area (raw 2 352 Mode 1, raw 2 352 Mode 2 Form 1, 2 336-byte sectors, or flat 2 048-byte cooked sectors). CDI framing. A CDI image is a stream of CD sectors followed by an 8-byte footer at EOF: 4 bytes LE version identifier (one of 0x80000004 / 0x80000005 / 0x80000006), then 4 bytes LE offset-from-EOF to the session descriptor (typically 0 in clean-room CDIs). The footer is kept byte-identical across in-place rewrites and is relocated past the new EOF whenever the data area grows (Append / past-EOF Write).Scope. Rewrites only the user-data bytes inside an existing sector or appends a brand-new sector at the end of the data area. It does not understand the inner ISO 9660 directory structure — that is the job of `IsoWriter` / its reader. Synthetic entry names of the form `sector-NNNNNN.bin` address a single sector LBA. Sync pattern (12 B), 3-byte address, 1-byte mode, and the EDC/ECC tail of raw sectors are preserved when an existing sector is rewritten and synthesised (sync + zero address + mode byte + zero EDC) when a brand-new sector is appended.True in-place. Writes touch only the 2 048-byte user-data region of the targeted sector. Bytes outside that region — header bytes of the same sector, every untouched sector, the system area (LBA 0-15), the PVD at LBA 16, the ISO root directory, and the trailing 8-byte CDI footer — stay byte-identical at their original byte offsets (the footer migrates to follow the new EOF when the data area grows). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddOrReplaceSectors` | `static void AddOrReplaceSectors(Stream image, IEnumerable> inputs)` | Routes each input through the sector-rewrite path. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed LBA byte offset. Inputs whose `ArchiveName` doesn't match the schema are refused — inner ISO 9660 directory mutation is delegated to `FileSystem.Iso`. | -| `AppendSector` | `static void AppendSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Extends the data area so that sector `lba` exists, writing `userData` as its 2 048-byte payload. Intermediate sectors (between the previous EOF sector and `lba`) are appended with the format-correct sync + zero address + mode byte + zero EDC framing for raw geometries, or plain zeros for cooked. The trailing 8-byte CDI footer, if present, is preserved verbatim and rewritten at the new EOF. | -| `DetectGeometry` | `static SectorGeometry DetectGeometry(Stream image)` | Detects the sector geometry of `image` the same way `CdiReader` does — by probing for the `CD001` PVD signature at LBA 16 inside the data area. Falls back to raw Mode 1 (2 352 / 16) when no probe succeeds. Trailing 8-byte CDI footer is excluded from the data area when its version identifier matches a known CDI release. | -| `FormatSectorEntryName` | `static string FormatSectorEntryName(int lba)` | Formats a sector LBA into the synthetic entry name used by the in-place modifier. | -| `RemoveSectors` | `static void RemoveSectors(Stream image, IEnumerable entryNames)` | Zeros each named `sector-NNNNNN.bin`. Names that don't match the schema are refused; sectors past the data-area EOF are still skipped. The framing bytes of an existing sector — sync/address/mode/EDC — and the trailing CDI footer are preserved. | -| `TryParseSectorEntryName` | `static bool TryParseSectorEntryName(string entryName, out int lba)` | Parses a synthetic `sector-NNNNNN.bin` entry name and returns the embedded sector LBA. Names that don't match the schema return `false`. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData)` | Rewrites the 2 048-byte user-data region of sector `lba` in place. Other bytes — sync/header/EDC for raw sectors, every other sector, every other region of the image, and the trailing 8-byte CDI footer — are untouched. If `lba` points past the current data-area EOF, the image is grown sector-by-sector with appended-sector framing (`AppendSector`) and the footer is relocated to the new EOF. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Variant of `WriteSector` that reuses a previously-probed geometry, avoiding a redundant PVD probe per call when a caller is rewriting several sectors back-to-back. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba)` | Zeros the 2 048-byte user-data region of sector `lba` in place. The sector framing bytes and the trailing CDI footer are preserved; only the user data is wiped. Returns `true` if the sector existed (and was zeroed), `false` if `lba` is past the data-area EOF. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba, SectorGeometry geom)` | Variant of `ZeroSector` reusing a previously-probed geometry. | - -#### `CdiInPlaceModifier.SectorGeometry` - -Detected on-disk sector geometry for a CDI image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. `DataAreaLength` is the byte length of the sector-bearing region (everything up to the 8-byte footer when present, otherwise the whole stream). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SectorGeometry` | `SectorGeometry(int SectorSize, int DataOffset, long DataAreaLength)` | Detected on-disk sector geometry for a CDI image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. `DataAreaLength` is the byte length of the sector-bearing region (everything up to the 8-byte footer when present, otherwise the whole stream). | -| `DataAreaLength` | `long DataAreaLength { get; init; }` | | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `SectorSize` | `int SectorSize { get; init; }` | | - -#### `CdiReader` - -Reads the ISO 9660 file system embedded in a DiscJuggler CDI disc image. CDI files store raw CD sector data followed by a session descriptor block at the end of the file. The footer begins with a 4-byte signature field identifying the CDI version, followed by a 4-byte offset (from EOF) to the start of the session descriptor. Known CDI footer signatures (last 4 bytes before the offset field): 0x80000004 — CDI v20x80000005 — CDI v30x80000006 — CDI v3.5 This reader probes the footer, then heuristically detects the sector geometry and parses the embedded ISO 9660 file system from the data area. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CdiReader` | `CdiReader(Stream stream, bool leaveOpen = false)` | Initializes a new `CdiReader` from a CDI stream. | -| `CdiVersion` | `uint CdiVersion { get; }` | Gets the CDI version identifier read from the footer, or 0 if no valid CDI footer was found. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries found in the ISO 9660 file system. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(CdiEntry entry)` | Extracts the raw data for a file entry. | - -### Namespace `FileFormat.Cso` - -[`CsoFormatDescriptor`](#csoformatdescriptor) · [`CsoInPlaceModifier`](#csoinplacemodifier) · [`CsoWriter`](#csowriter) - -#### `CsoFormatDescriptor` - -PSP CSO / ZSO compressed ISO image. Layout after the 4-byte magic (`CISO` for CSO, `ZISO` for LZ4-compressed ZSO): uint32 header_size, uint64 uncompressed_size, uint32 block_size, uint8 version, uint8 align, uint16 reserved, then an index table of `N = uncompressed_size / block_size + 1` uint32 entries (high bit = stored/uncompressed, low 31 bits = file offset). This descriptor surfaces each compressed block as a raw blob — it does NOT decompress the blocks (consumers can further process with zlib for CSO or LZ4 for ZSO). References: `https://github.com/unknownbrackets/maxcso` — maxcso — maintained CSO/ZSO tool; its docs describe the CSO v1/v2 and ZSO layoutsThe format originates in PSP homebrew (ciso); there is no official Sony documentation - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CsoFormatDescriptor` | `CsoFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Replaces blocks named `blocks/block_NNNNN.bin` (5-digit zero-padded index) with the supplied payloads. Each input must be exactly the container's block_size bytes. Other input names are ignored. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a fresh CSO v1 stream. Inputs are concatenated in supplied order to form the uncompressed payload (the caller is responsible for ensuring the result is a valid PSP ISO if PSP semantics matter). | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | "Removes" blocks by writing block_size zero bytes through `WriteBlock`, which compresses the zero slab to its minimum DEFLATE encoding and zero-pads the on-disk slack. | - -#### `CsoInPlaceModifier` - -In-place block-level mutator for PSP CSO v1 images. Lets callers replace individual decompressed blocks without rewriting the whole container. Semantics for `WriteBlock`: If the new compressed payload fits inside the old block's on-disk slot, the payload is written at the same offset and trailing slack is zero-padded — the index table and every other block's bytes are unchanged.Otherwise the payload is appended at the current end of stream and the block's index entry is updated to point at the new location. The old in-place bytes become orphaned (defrag-recoverable).CSO v2 / ZSO (LZ4) are out of scope; only the v1 header layout with align=0 is supported. The modifier refuses to operate on streams whose header reports a different version or a non-zero align (because the offset-shift semantics would silently misplace the new block). - -| Member | Signature | Summary | -| --- | --- | --- | -| `WriteBlock` | `static void WriteBlock(Stream image, int blockIndex, ReadOnlySpan newUncompressedData)` | Replaces block `blockIndex`'s content with `newUncompressedData` (which must be exactly `block_size` bytes long, matching the container's geometry). The payload is DEFLATE-compressed; if the result is smaller than the slab it's written compressed, otherwise stored uncompressed (with the index entry's high bit set). | - -#### `CsoWriter` - -Writes a PSP CSO v1 ("CISO") compressed-ISO container from scratch (WORM). Layout (24-byte header + (N+1)·uint32 index + N compressed blocks): $00..$03: magic "CISO"$04..$07: uint32 LE header_size = 24$08..$0F: uint64 LE uncompressed_size$10..$13: uint32 LE block_size (this writer uses 2048 = ISO 9660 sector)$14: uint8 version = 1$15: uint8 align (left-shift applied to index offsets; this writer uses 0)$16..$17: uint16 reserved = 0$18..(header+4·(N+1)): index table. bit 31 set = stored uncompressed.Each block: raw DEFLATE bytes (no zlib header) of one block_size-aligned slab, OR the slab verbatim when the compressed output is not smaller than the slab.ZSO (LZ4) and CSO v2 are out of scope; see `CsoFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CsoWriter` | `CsoWriter()` | | -| `DefaultBlockSize` | `const int DefaultBlockSize` | Default block size — 2048 = one ISO 9660 cooked sector. | -| `Build` | `static byte[] Build(ReadOnlySpan uncompressedData, int blockSize = 2048)` | Builds a CSO v1 stream that, when fully decompressed, yields `uncompressedData`. Blocks of `blockSize` bytes are each DEFLATE-compressed; if the compressed output is not smaller than the original slab, the slab is stored verbatim and its index entry gets the `IndexUncompressedFlag` bit set. | - -### Namespace `FileFormat.Dmg` - -[`DmgEntry`](#dmgentry) · [`DmgFormatDescriptor`](#dmgformatdescriptor) · [`DmgReader`](#dmgreader) · [`DmgWriter`](#dmgwriter) - -#### `DmgEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmgEntry` | `DmgEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `DmgFormatDescriptor` - -Apple disk image (DMG/UDIF) — "koly" trailer + XML plist block map (blkx) with zlib/bzip2/ADC-compressed chunks. References: `http://newosxbook.com/DMG.html` — Jonathan Levin's UDIF format write-up — the standard unofficial reference (Apple never published a spec)`https://github.com/darlinghq/darling-dmg` — darling-dmg — open-source DMG/UDIF implementation`https://en.wikipedia.org/wiki/Apple_Disk_Image` — format overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmgFormatDescriptor` | `DmgFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single DMG partition as a bounded read-only `Stream`. The reader's per-entry extractor reconstructs the partition's raw sectors; they are wrapped in a `BoundedEntryStream` sized to the entry's size. | - -#### `DmgReader` - -Read-only reader for Apple Disk Image (DMG) files. Parses the koly trailer, XML plist, and mish block tables to expose each partition as an extractable entry. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmgReader` | `DmgReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | All partitions found in the DMG, each exposed as a named entry. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DmgEntry entry)` | Reassembles and returns the raw sector data for `entry`. | - -#### `DmgWriter` - -Writes Apple Disk Image (DMG) files in WORM mode. Each input file becomes one partition with a single raw (uncompressed) mish block. The output roundtrips through `DmgReader`: Layout: [partition data sectors] [XML plist] [512-byte koly trailer].Each partition has a mish table with one `BlockTypeRaw` entry covering all its sectors plus a terminator.No compression -- DMG's zlib/bz2/lzfse encoders aren't paired here, and raw is fully spec-valid.No checksums -- mish/koly checksum-type fields set to 0 ("none"), which the reader accepts. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DmgWriter` | `DmgWriter()` | | -| `AddPartition` | `void AddPartition(string name, byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.Dtb` - -[`DtbFormatDescriptor`](#dtbformatdescriptor) · [`DtbReader`](#dtbreader) · [`DtbReader.Fdt`](#dtbreaderfdt) · [`DtbReader.Header`](#dtbreaderheader) · [`DtbReader.Property`](#dtbreaderproperty) · [`DtbReader.Reservation`](#dtbreaderreservation) · [`DtbWriter`](#dtbwriter) - -#### `DtbFormatDescriptor` - -Pseudo-archive descriptor for Flattened Device Tree Blobs (DTB/DTBO). Walks the structure block and emits one entry per leaf property. Property data that parses cleanly as a UTF-8 string list is written as a `.txt` file; anything else is written as raw bytes. A `metadata.ini` summarises the FDT header + memory reservation map. References: `https://github.com/devicetree-org/devicetree-specification` — Devicetree Specification — defines the flattened (FDT/DTB) encoding`https://www.devicetree.org` — devicetree.org portal`https://en.wikipedia.org/wiki/Device_tree` — background - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DtbFormatDescriptor` | `DtbFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM creation: emits a minimal valid FDT v17 blob whose root node carries each input as a leaf property. The synthetic `metadata.ini` + any reader-emitted `.txt`/`.bin` suffixes are stripped from the archive name before sanitisation so a list-then-create round-trip lands at the same property name. Property names are sanitised to the devicetree-spec character set; collisions in the input list are preserved as repeated FDT_PROP records. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `DtbReader` - -Reader for the Flattened Device Tree Blob (FDT/DTB) format used by the Linux kernel and U-Boot to describe hardware. Walks the structure block and yields every leaf property as a `Property` with its slash-delimited node path, property name, and raw bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DtbReader` | `DtbReader()` | | -| `FDT_BEGIN_NODE` | `const uint FDT_BEGIN_NODE` | Structure-block tokens. | -| `FDT_END_NODE` | `const uint FDT_END_NODE` | | -| `FDT_END` | `const uint FDT_END` | | -| `FDT_NOP` | `const uint FDT_NOP` | | -| `FDT_PROP` | `const uint FDT_PROP` | | -| `Magic` | `const uint Magic` | FDT magic `0xD00DFEED` (BE u32 at offset 0). | -| `Read` | `static Fdt Read(ReadOnlySpan data)` | Parses a full DTB byte span into a `Fdt` record. | - -#### `DtbReader.Fdt` - -Parsed FDT blob. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Fdt` | `Fdt(Header Header, IReadOnlyList Reservations, IReadOnlyList Properties)` | Parsed FDT blob. | -| `Header` | `Header Header { get; init; }` | | -| `Properties` | `IReadOnlyList Properties { get; init; }` | | -| `Reservations` | `IReadOnlyList Reservations { get; init; }` | | - -#### `DtbReader.Header` - -Parsed FDT header (v17 fields; older versions leave trailing fields at 0). - -Implements `IEquatable
`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Header` | `Header(uint Magic, uint TotalSize, uint OffsetDtStruct, uint OffsetDtStrings, uint OffsetMemRsvmap, uint Version, uint LastCompVersion, uint BootCpuidPhys, uint SizeDtStrings, uint SizeDtStruct)` | Parsed FDT header (v17 fields; older versions leave trailing fields at 0). | -| `BootCpuidPhys` | `uint BootCpuidPhys { get; init; }` | | -| `LastCompVersion` | `uint LastCompVersion { get; init; }` | | -| `Magic` | `uint Magic { get; init; }` | | -| `OffsetDtStrings` | `uint OffsetDtStrings { get; init; }` | | -| `OffsetDtStruct` | `uint OffsetDtStruct { get; init; }` | | -| `OffsetMemRsvmap` | `uint OffsetMemRsvmap { get; init; }` | | -| `SizeDtStrings` | `uint SizeDtStrings { get; init; }` | | -| `SizeDtStruct` | `uint SizeDtStruct { get; init; }` | | -| `TotalSize` | `uint TotalSize { get; init; }` | | -| `Version` | `uint Version { get; init; }` | | - -#### `DtbReader.Property` - -A leaf property in the device tree. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Property` | `Property(string NodePath, string Name, byte[] Data)` | A leaf property in the device tree. | -| `Data` | `byte[] Data { get; init; }` | Raw property bytes (BE-ordered cells, NUL-separated strings, etc.). | -| `Name` | `string Name { get; init; }` | Property name (e.g. `compatible`). | -| `NodePath` | `string NodePath { get; init; }` | Slash-delimited path, e.g. `/chosen`. Root is `""`. | - -#### `DtbReader.Reservation` - -A reserved memory range declared in the header's memory-reservation map. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Reservation` | `Reservation(ulong Address, ulong Size)` | A reserved memory range declared in the header's memory-reservation map. | -| `Address` | `ulong Address { get; init; }` | | -| `Size` | `ulong Size { get; init; }` | | - -#### `DtbWriter` - -WORM writer for the Flattened Device Tree Blob (FDT v17) format. Produces a minimal valid DTB where every input becomes a leaf property on the root node. The root node carries spec-required `#address-cells = <2>` and `#size-cells = <2>` properties so the blob round-trips through `fdtdump` / `dtc` consumers without warnings. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DtbWriter` | `DtbWriter()` | | -| `SanitisePropertyName` | `static string SanitisePropertyName(string archiveName)` | Coerces an input archive name into a property name valid per devicetree-specification §2.2.4 (ASCII subset of property-name chars). Reserved chars are replaced with `_`; the leaf of any path is used. | -| `Write` | `static void Write(Stream output, IReadOnlyList> inputs)` | Writes a minimal FDT blob to `output` whose root node contains one property per input. Each input's archive-name leaf is used as the property name; the raw bytes become the property value. Names are deduplicated in the strings block, but each occurrence still gets its own FDT_PROP record (multiple identical property names on one node are technically nonconforming, but matching the input list verbatim is the honest WORM behaviour). | - -### Namespace `FileFormat.Ewf` - -[`EwfFormatDescriptor`](#ewfformatdescriptor) · [`EwfReader`](#ewfreader) · [`EwfReader.EwfImage`](#ewfreaderewfimage) · [`EwfReader.Section`](#ewfreadersection) · [`EwfWriter`](#ewfwriter) - -#### `EwfFormatDescriptor` - -Pseudo-archive descriptor for EnCase Expert Witness Format (EWF) forensic images (.e01/.ewf/.l01). Surfaces each parsed section as a separate entry along with a `metadata.ini` summarising acquisition parameters pulled from the `header`/`header2`/`hash`/`digest` sections. Full sector decompression + segment chaining across multi-file sets is deferred to a later phase — forensic tooling (libewf, EnCase) can decode the per-section data directly. References: `https://github.com/libyal/libewf` — libewf — canonical open-source implementation; its documentation folder carries Joachim Metz's EWF/EWF2 format specsASR Data "Expert Witness Compression Format" — the original format the EnCase .E01 family derives from - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EwfFormatDescriptor` | `EwfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates a single-segment .E01 image wrapping the supplied input(s) as raw media. EWF is a media-wrapper format, so file inputs are concatenated into one contiguous raw image (the common case is a single disk-image input). The produced image is accepted by libewf's `ewfverify`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `EwfReader` - -Reader for EnCase Expert Witness Format (EWF) forensic images — the .e01/.ewf/.l01 family used by EnCase and libewf. Walks the section chain starting at offset 13 (just past the 8-byte signature + 1-byte fields_start + 2-byte segment + 2-byte fields_end) and surfaces each section's raw bytes along with parsed metadata. Full sector decompression is deferred. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EwfReader` | `EwfReader()` | | -| `EvfSignature` | `static readonly byte[] EvfSignature` | | -| `FileHeaderSize` | `const int FileHeaderSize` | | -| `LvfSignature` | `static readonly byte[] LvfSignature` | | -| `SectionDescriptorSize` | `const int SectionDescriptorSize` | | -| `Read` | `static EwfImage Read(ReadOnlySpan data)` | | - -#### `EwfReader.EwfImage` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EwfImage` | `EwfImage(bool IsLogical, ushort SegmentNumber, List
Sections, long TotalFileSize)` | | -| `IsLogical` | `bool IsLogical { get; init; }` | | -| `Sections` | `List
Sections { get; init; }` | | -| `SegmentNumber` | `ushort SegmentNumber { get; init; }` | | -| `TotalFileSize` | `long TotalFileSize { get; init; }` | | - -#### `EwfReader.Section` - -Implements `IEquatable
`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Section` | `Section(string Type, long DescriptorOffset, ulong NextSectionOffset, ulong SectionSize, uint Checksum, byte[] Payload)` | | -| `Checksum` | `uint Checksum { get; init; }` | | -| `DescriptorOffset` | `long DescriptorOffset { get; init; }` | | -| `NextSectionOffset` | `ulong NextSectionOffset { get; init; }` | | -| `Payload` | `byte[] Payload { get; init; }` | | -| `SectionSize` | `ulong SectionSize { get; init; }` | | -| `Type` | `string Type { get; init; }` | | - -#### `EwfWriter` - -Writer for EnCase Expert Witness Format (EWF / .E01) forensic images. Produces a single-segment EVF image that the reference `libewf` tools (`ewfverify`, `ewfinfo`, `ewfexport`) accept and reconstruct byte-for-byte. - -| Member | Signature | Summary | -| --- | --- | --- | -| `EwfWriter` | `EwfWriter()` | | -| `BytesPerSector` | `const int BytesPerSector` | Bytes per sector (libewf default). | -| `ChunkSize` | `const int ChunkSize` | Chunk size in bytes (64 * 512 = 32768). | -| `SectorsPerChunk` | `const int SectorsPerChunk` | Sectors per chunk (libewf default). | -| `CaseNumber` | `string CaseNumber { get; init; }` | Case number recorded in the acquisition header. | -| `CompressChunks` | `bool CompressChunks { get; init; }` | When true, each chunk is zlib-compressed (stored uncompressed if it does not shrink). | -| `Description` | `string Description { get; init; }` | Free-form description recorded in the acquisition header. | -| `EvidenceNumber` | `string EvidenceNumber { get; init; }` | Evidence number recorded in the acquisition header. | -| `ExaminerName` | `string ExaminerName { get; init; }` | Examiner name recorded in the acquisition header. | -| `Notes` | `string Notes { get; init; }` | Notes recorded in the acquisition header. | -| `Build` | `byte[] Build(ReadOnlySpan media)` | Builds a single-segment E01 image from the supplied raw media bytes. | - -### Namespace `FileFormat.FirmwareHex` - -[`FirmwareImage`](#firmwareimage) · [`IntelHexFormatDescriptor`](#intelhexformatdescriptor) · [`IntelHexReader`](#intelhexreader) · [`SRecordReader`](#srecordreader) · [`TiTxtFormatDescriptor`](#titxtformatdescriptor) · [`TiTxtReader`](#titxtreader) - -#### `FirmwareImage` - -A decoded firmware image: an ordered collection of address/byte-run segments plus a declared start address (when the source format supplies one — Intel HEX type 03/05, S-Record S7/S8/S9). Segments are sorted by address and never overlap; gaps between segments are filled with `0xFF` (flash erase default) when the image is flattened to a single binary. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FirmwareImage` | `FirmwareImage(IReadOnlyList> Segments, uint? StartAddress, int RecordCount, int GapCount, int TotalDataBytes, string SourceFormat)` | A decoded firmware image: an ordered collection of address/byte-run segments plus a declared start address (when the source format supplies one — Intel HEX type 03/05, S-Record S7/S8/S9). Segments are sorted by address and never overlap; gaps between segments are filled with `0xFF` (flash erase default) when the image is flattened to a single binary. | -| `BaseAddress` | `uint BaseAddress { get; }` | Returns the lowest address across all segments, or 0 when empty. | -| `GapCount` | `int GapCount { get; init; }` | | -| `RecordCount` | `int RecordCount { get; init; }` | | -| `Segments` | `IReadOnlyList> Segments { get; init; }` | | -| `SourceFormat` | `string SourceFormat { get; init; }` | | -| `StartAddress` | `uint? StartAddress { get; init; }` | | -| `TotalDataBytes` | `int TotalDataBytes { get; init; }` | | -| `ToFlatBinary` | `byte[] ToFlatBinary(byte fill = 255)` | Flattens all segments into a single contiguous binary spanning from the lowest address to the end of the highest segment. Gaps are filled with `fill` (default `0xFF` to match flash erase state). | - -#### `IntelHexFormatDescriptor` - -Pseudo-archive descriptor for Intel HEX firmware files. Decodes the ASCII records into a flat binary (`firmware.bin`) and surfaces a `metadata.ini` with record count, declared start address, and gap count. References: Intel "Hexadecimal Object File Format Specification", Rev. A (1988) — the defining document`https://en.wikipedia.org/wiki/Intel_HEX` — record types and checksum rules - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IntelHexFormatDescriptor` | `IntelHexFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `IntelHexReader` - -Reader for Intel HEX records (`:LLAAAATT[DD…]CC`), the long-standing flash-programmer text format. Supports record types 00 (data), 01 (EOF), 02 (extended-segment address), 03 (start-segment address), 04 (extended-linear address) and 05 (start-linear address). Maps all 16-bit addresses through the active extended base into a flat 32-bit address space. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IntelHexReader` | `IntelHexReader()` | | -| `Read` | `static FirmwareImage Read(string text)` | Parses an Intel HEX text document into a `FirmwareImage`. | - -#### `SRecordReader` - -Reader for Motorola S-Record files (`Stnn[aaaa|aaaaaa|aaaaaaaa]dd…cc`). Recognised types: S0 header, S1/S2/S3 data (16/24/32-bit address), S5/S6 record counts (informational), S7/S8/S9 termination (32/24/16-bit start addr). - -| Member | Signature | Summary | -| --- | --- | --- | -| `SRecordReader` | `SRecordReader()` | | -| `Read` | `static FirmwareImage Read(string text)` | Parses an S-Record text document into a `FirmwareImage`. | - -#### `TiTxtFormatDescriptor` - -Pseudo-archive descriptor for the TI-TXT firmware text format used by MSP430. Address lines (`@HHHH`) introduce contiguous byte runs; a single `q` terminates the file. Extension is intentionally empty — `.txt` is far too ambiguous — so detection relies on the first non-whitespace byte being `@`. References: Texas Instruments MSP430 programming/bootloader guides — define the TI-TXT format (@addr / data / q)`https://srecord.sourceforge.net` — SRecord tool suite — documents and converts TI-TXT (srec_ti_txt) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TiTxtFormatDescriptor` | `TiTxtFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `TiTxtReader` - -Reader for TI-TXT MSP430 text firmware files. Addresses are introduced by `@HHHH` lines; data lines follow as space-separated hex bytes (typically 16 per line); a single `q` token terminates the file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TiTxtReader` | `TiTxtReader()` | | -| `Read` | `static FirmwareImage Read(string text)` | Parses a TI-TXT document into a `FirmwareImage`. | - -### Namespace `FileFormat.Ipsw` - -[`IpswFormatDescriptor`](#ipswformatdescriptor) · [`IpswInPlaceModifier`](#ipswinplacemodifier) - -#### `IpswFormatDescriptor` - -Apple IPSW / OTA firmware package. An IPSW is just a ZIP file (with an Apple-specific layout). Rather than surfacing entries as a flat generic ZIP, this descriptor lifts the well-known Apple artifacts (`BuildManifest.plist`, `Firmware/` subtree, `LLB.*`, `iBSS.*`, `iBEC.*`, `iBoot.*`, root-filesystem `*.dmg`) into first-class canonical entries. Everything else is exposed under `other/`. This is a compound-extension descriptor (`.ipsw`, `.otazip`): magic is empty so it does not steal generic ZIPs. Read-only; the plist and DMG payloads are emitted as raw bytes — no plist parsing or DMG mounting. References: `https://theapplewiki.com` — The Apple Wiki (formerly The iPhone Wiki) — community IPSW documentation`https://github.com/blacktop/ipsw` — ipsw — maintained IPSW research and extraction tool`https://en.wikipedia.org/wiki/IPSW` — Wikipedia - -Implements `IArchiveCreatable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `IpswFormatDescriptor` | `IpswFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by ZIP path) entries inside an existing IPSW. Routes through `IpswInPlaceModifier` — only the central directory, EOCD, and the appended LFH + payload are touched. Synthetic canonical entries are silently dropped. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Emits a fresh IPSW (ZIP) container from the supplied inputs. Synthetic canonical entries the descriptor surfaces on read (`FULL.ipsw`, `metadata.ini`) are silently dropped — they aren't real ZIP entries. All other inputs are stored under their `ArchiveName`. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named ZIP entries from an existing IPSW. Routes through `IpswInPlaceModifier` — the LFH + compressed payload of the dropped entry are zero-wiped and the central directory is rewritten. | - -#### `IpswInPlaceModifier` - -In-place modifier for Apple IPSW packages. An IPSW is just a ZIP file with an Apple-specific entry layout, so every mutation routes straight through `ZipModifier` — the central directory and EOCD record are the only structural bytes the operation touches. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddEntry` | `static void AddEntry(Stream ipsw, string zipPath, byte[] data)` | Adds (or replaces by ZIP path) a single entry inside the IPSW. The previous entry's bytes are wiped via `RemoveFile` before the new entry is appended. | -| `RemoveEntry` | `static bool RemoveEntry(Stream ipsw, string zipPath)` | Removes a single entry by ZIP path. Returns true if removed. | - -### Namespace `FileFormat.Mdf` - -[`MdfEntry`](#mdfentry) · [`MdfFormatDescriptor`](#mdfformatdescriptor) · [`MdfInPlaceModifier`](#mdfinplacemodifier) · [`MdfInPlaceModifier.SectorGeometry`](#mdfinplacemodifiersectorgeometry) · [`MdfReader`](#mdfreader) - -#### `MdfEntry` - -Represents a file or directory entry in an MDF disc image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MdfEntry` | `MdfEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path within the disc image, using forward slashes. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the filename or directory name of this entry. | -| `Size` | `long Size { get; init; }` | Gets the file size in bytes (0 for directories). | -| `StartLba` | `int StartLba { get; init; }` | Gets the starting LBA (Logical Block Address) of this entry's data. | - -#### `MdfFormatDescriptor` - -Alcohol 120% MDF/MDS disc image pair — raw sector data (.mdf) plus a session/track descriptor (.mds). References: `https://cdemu.sourceforge.io` — CDEmu / libMirage — its MDS/MDF parser is the de-facto format documentationNo official specification — proprietary Alcohol Soft format, reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MdfFormatDescriptor` | `MdfFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Rewrites raw CD sectors in place. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed byte offset `lba * sectorSize + dataOffset`; everything outside the touched 2 048-byte user-data region stays byte-identical. Inputs not matching the synthetic sector schema are skipped — inner-ISO 9660 directory mutation is delegated to `FileSystem.Iso` and is out of scope for the sector-rewrite modifier. The accompanying `.mds` sidecar (if any) is not touched; the modifier only mutates the MDF byte stream. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Zeros the 2 048-byte user-data region of each named sector. Sector framing bytes (sync / address / mode / EDC) on raw geometries are preserved so the LBA-to-offset map and the rest of the image remain byte-identical. | - -#### `MdfInPlaceModifier` - -In-place sector-rewrite modifier for an Alcohol 120% MDF disc image. Operates at the raw 2 048-byte user-data region of each CD sector at the fixed byte offset `lba * sectorSize + dataOffset`, where `sectorSize` and `dataOffset` are the geometry detected from the stream (raw 2 352 Mode 1, raw 2 352 Mode 2 Form 1, 2 336-byte sectors, or flat 2 048-byte cooked sectors). MDF framing. Alcohol 120% pairs an `.mdf` sector-stream with an `.mds` metadata sidecar that describes the track layout. The MDF itself has no internal header or footer — it is a flat byte stream of sectors at LBA × sectorSize. The MDS sidecar is not touched by this modifier (the in-place surface only mutates the MDF data); the reader's geometry detection survives any sector rewrite.Scope. Rewrites only the user-data bytes inside an existing sector or appends a brand-new sector at the end of the stream. It does not understand the inner ISO 9660 directory structure — that is the job of `IsoWriter` / its reader. Synthetic entry names of the form `sector-NNNNNN.bin` address a single sector LBA. Multi-track layouts (described in the companion `.mds`) are not parsed — the modifier treats the stream as a single track of sectors at flat LBA offsets. Sync pattern (12 B), 3-byte address, 1-byte mode, and the EDC/ECC tail of raw sectors are preserved on rewrite and synthesised on append.True in-place. Writes touch only the 2 048-byte user-data region of the targeted sector. Bytes outside that region — header bytes of the same sector, every untouched sector, the system area (LBA 0-15), the PVD at LBA 16, and the ISO root directory — stay byte-identical at their original byte offsets. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddOrReplaceSectors` | `static void AddOrReplaceSectors(Stream image, IEnumerable> inputs)` | Routes each input through the sector-rewrite path. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed LBA byte offset. Inputs whose `ArchiveName` doesn't match the schema are refused — inner ISO 9660 directory mutation is delegated to `FileSystem.Iso`. | -| `AppendSector` | `static void AppendSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Extends the image so that sector `lba` exists, writing `userData` as its 2 048-byte payload. Intermediate sectors are appended with format-correct framing. | -| `DetectGeometry` | `static SectorGeometry DetectGeometry(Stream image)` | Detects the sector geometry of `image` the same way `MdfReader` does — by probing for the `CD001` PVD signature at LBA 16. Falls back to raw Mode 1 (2 352 / 16) when no probe succeeds. | -| `FormatSectorEntryName` | `static string FormatSectorEntryName(int lba)` | Formats a sector LBA into the synthetic entry name used by the in-place modifier. | -| `RemoveSectors` | `static void RemoveSectors(Stream image, IEnumerable entryNames)` | Zeros each named `sector-NNNNNN.bin`. Names that don't match the schema are refused; sectors past EOF are still skipped. The framing bytes of an existing sector are preserved. | -| `TryParseSectorEntryName` | `static bool TryParseSectorEntryName(string entryName, out int lba)` | Parses a synthetic `sector-NNNNNN.bin` entry name and returns the embedded sector LBA. Names that don't match the schema return `false`. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData)` | Rewrites the 2 048-byte user-data region of sector `lba` in place. Other bytes — sync/header/EDC for raw sectors, every other sector — are untouched. If `lba` points past current EOF, the image is grown sector-by-sector with appended-sector framing (`AppendSector`). | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Variant of `WriteSector` that reuses a previously-probed geometry, avoiding a redundant PVD probe per call when a caller is rewriting several sectors back-to-back. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba)` | Zeros the 2 048-byte user-data region of sector `lba` in place. The sector framing bytes are preserved; only the user data is wiped. Returns `true` if the sector existed (and was zeroed), `false` if `lba` is past EOF. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba, SectorGeometry geom)` | Variant of `ZeroSector` reusing a previously-probed geometry. | - -#### `MdfInPlaceModifier.SectorGeometry` - -Detected on-disk sector geometry for an MDF image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SectorGeometry` | `SectorGeometry(int SectorSize, int DataOffset)` | Detected on-disk sector geometry for an MDF image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `SectorSize` | `int SectorSize { get; init; }` | | - -#### `MdfReader` - -Reads the ISO 9660 file system embedded in an Alcohol 120% MDF disc image. MDF files contain raw CD/DVD sector data, typically in 2352-byte raw sectors (Mode 1 with user data at offset 16) or plain 2048-byte ISO sectors. The accompanying MDS file describes track layout; this reader detects the sector geometry heuristically by probing for the ISO 9660 PVD signature. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `MdfReader` | `MdfReader(Stream stream, bool leaveOpen = false)` | Initializes a new `MdfReader` from an MDF stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries found in the ISO 9660 file system. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(MdfEntry entry)` | Extracts the raw data for a file entry. | - -### Namespace `FileFormat.Nrg` - -[`NrgEntry`](#nrgentry) · [`NrgFormatDescriptor`](#nrgformatdescriptor) · [`NrgInPlaceModifier`](#nrginplacemodifier) · [`NrgInPlaceModifier.SectorGeometry`](#nrginplacemodifiersectorgeometry) · [`NrgReader`](#nrgreader) - -#### `NrgEntry` - -Represents a file or directory entry in a Nero NRG disc image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NrgEntry` | `NrgEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | Gets the full path within the disc image, using forward slashes. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Gets whether this entry is a directory. | -| `Name` | `string Name { get; init; }` | Gets the filename or directory name of this entry. | -| `Size` | `long Size { get; init; }` | Gets the file size in bytes (0 for directories). | -| `StartLba` | `int StartLba { get; init; }` | Gets the starting LBA (Logical Block Address) of this entry's data. | - -#### `NrgFormatDescriptor` - -Nero Burning ROM NRG disc image — trailing NER5/NERO footer pointing at a chunked session/track descriptor area. References: `https://cdemu.sourceforge.io` — CDEmu / libMirage — its NRG parser is the de-facto format documentation`https://en.wikipedia.org/wiki/NRG_(file_format)` — WikipediaNo official specification — proprietary Nero format, reverse-engineered - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NrgFormatDescriptor` | `NrgFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Rewrites raw CD sectors in place. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed byte offset `lba * sectorSize + dataOffset`; everything outside the touched 2 048-byte user-data region — including the trailing NRG footer — stays byte-identical (the footer migrates with the new EOF when the data area grows past the previous end). Inputs not matching the synthetic sector schema are skipped — inner-ISO 9660 directory mutation is delegated to `FileSystem.Iso` and is out of scope for the sector-rewrite modifier. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Zeros the 2 048-byte user-data region of each named sector. Sector framing bytes (sync / address / mode / EDC) on raw geometries and the trailing NRG footer are preserved so the LBA-to-offset map and the rest of the image remain byte-identical. | - -#### `NrgInPlaceModifier` - -In-place sector-rewrite modifier for a Nero Burning ROM NRG disc image. Operates at the raw 2 048-byte user-data region of each CD sector at the fixed byte offset `lba * sectorSize + dataOffset`, where `sectorSize` and `dataOffset` are the geometry detected from the data area (raw 2 352 Mode 1, raw 2 352 Mode 2 Form 1, 2 336-byte sectors, or flat 2 048-byte cooked sectors). NRG framing. An NRG image is a stream of CD sectors followed by a footer at EOF identifying the format version: NRG v2: last 12 bytes — "NER5" + uint64 BE chunk-table offset.NRG v1: last 8 bytes — "NERO" + uint32 BE chunk-table offset. The footer is preserved byte-identical across in-place rewrites and is relocated past the new EOF whenever the data area grows.Scope. Rewrites only the user-data bytes inside an existing sector or appends a brand-new sector at the end of the data area. It does not understand the inner ISO 9660 directory structure — that is the job of `IsoWriter` / its reader. Synthetic entry names of the form `sector-NNNNNN.bin` address a single sector LBA. Multi-track DAOI/CUEX layouts are not parsed — the modifier treats the stream as a single track of sectors at flat LBA offsets. Sync pattern (12 B), 3-byte address, 1-byte mode, and the EDC/ECC tail of raw sectors are preserved on rewrite and synthesised on append.True in-place. Writes touch only the 2 048-byte user-data region of the targeted sector. Bytes outside that region — header bytes of the same sector, every untouched sector, the system area (LBA 0-15), the PVD at LBA 16, the ISO root directory, and the trailing NRG footer — stay byte-identical at their original byte offsets (the footer migrates to follow the new EOF when the data area grows). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddOrReplaceSectors` | `static void AddOrReplaceSectors(Stream image, IEnumerable> inputs)` | Routes each input through the sector-rewrite path. Inputs whose `ArchiveName` matches `sector-NNNNNN.bin` are written at the fixed LBA byte offset. Inputs whose `ArchiveName` doesn't match the schema are refused — inner ISO 9660 directory mutation is delegated to `FileSystem.Iso`. | -| `AppendSector` | `static void AppendSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Extends the data area so that sector `lba` exists, writing `userData` as its 2 048-byte payload. Intermediate sectors are appended with format-correct framing. The trailing NRG footer is preserved verbatim and rewritten at the new EOF. | -| `DetectGeometry` | `static SectorGeometry DetectGeometry(Stream image)` | Detects the sector geometry of `image` the same way `NrgReader` does — by probing for the `CD001` PVD signature at LBA 16 inside the data area. Falls back to raw Mode 1 (2 352 / 16) when no probe succeeds. NRG v2 ("NER5") and v1 ("NERO") footers are excluded from the data area. | -| `FormatSectorEntryName` | `static string FormatSectorEntryName(int lba)` | Formats a sector LBA into the synthetic entry name used by the in-place modifier. | -| `RemoveSectors` | `static void RemoveSectors(Stream image, IEnumerable entryNames)` | Zeros each named `sector-NNNNNN.bin`. Names that don't match the schema are refused; sectors past the data-area EOF are still skipped. The framing bytes of an existing sector and the trailing NRG footer are preserved. | -| `TryParseSectorEntryName` | `static bool TryParseSectorEntryName(string entryName, out int lba)` | Parses a synthetic `sector-NNNNNN.bin` entry name and returns the embedded sector LBA. Names that don't match the schema return `false`. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData)` | Rewrites the 2 048-byte user-data region of sector `lba` in place. Other bytes — sync/header/EDC for raw sectors, every other sector, every other region of the image, and the trailing NRG footer — are untouched. If `lba` points past the current data-area EOF, the image is grown sector-by-sector with appended-sector framing (`AppendSector`) and the footer is relocated to the new EOF. | -| `WriteSector` | `static void WriteSector(Stream image, int lba, ReadOnlySpan userData, SectorGeometry geom)` | Variant of `WriteSector` that reuses a previously-probed geometry, avoiding a redundant PVD probe per call when a caller is rewriting several sectors back-to-back. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba)` | Zeros the 2 048-byte user-data region of sector `lba` in place. The sector framing bytes and the trailing NRG footer are preserved; only the user data is wiped. Returns `true` if the sector existed (and was zeroed), `false` if `lba` is past the data-area EOF. | -| `ZeroSector` | `static bool ZeroSector(Stream image, int lba, SectorGeometry geom)` | Variant of `ZeroSector` reusing a previously-probed geometry. | - -#### `NrgInPlaceModifier.SectorGeometry` - -Detected on-disk sector geometry for an NRG image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. `DataAreaLength` excludes the trailing NRG footer (12 bytes for v2, 8 bytes for v1) when present. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `SectorGeometry` | `SectorGeometry(int SectorSize, int DataOffset, long DataAreaLength)` | Detected on-disk sector geometry for an NRG image. `DataOffset` is the byte offset within a sector where the 2 048 B of ISO user data begins. `DataAreaLength` excludes the trailing NRG footer (12 bytes for v2, 8 bytes for v1) when present. | -| `DataAreaLength` | `long DataAreaLength { get; init; }` | | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `SectorSize` | `int SectorSize { get; init; }` | | - -#### `NrgReader` - -Reads the ISO 9660 file system embedded in a Nero Burning ROM NRG disc image. NRG images carry a footer at the end of the file identifying the format version and providing a chunk table that describes the track layout. Footer layout: NRG v2: last 12 bytes — "NER5" (4 bytes) + uint64 BE offset to chunk table.NRG v1: last 8 bytes — "NERO" (4 bytes) + uint32 BE offset to chunk table. This reader parses the footer to locate the data area, then heuristically detects the sector geometry and parses the ISO 9660 file system. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NrgReader` | `NrgReader(Stream stream, bool leaveOpen = false)` | Initializes a new `NrgReader` from an NRG stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries found in the ISO 9660 file system. | -| `Version` | `int Version { get; }` | Gets the NRG format version detected from the footer (1 or 2), or 0 if no valid footer was found. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(NrgEntry entry)` | Extracts the raw data for a file entry. | - -### Namespace `FileFormat.Pfs0` - -[`Pfs0Entry`](#pfs0entry) · [`Pfs0FormatDescriptor`](#pfs0formatdescriptor) · [`Pfs0InPlaceModifier`](#pfs0inplacemodifier) · [`Pfs0Reader`](#pfs0reader) · [`Pfs0Writer`](#pfs0writer) - -#### `Pfs0Entry` - -Represents a single entry in a Nintendo Switch PartitionFS (PFS0) archive. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pfs0Entry` | `Pfs0Entry()` | | -| `Name` | `string Name { get; init; }` | Gets the entry name (UTF-8, decoded from the string table). | -| `Offset` | `long Offset { get; init; }` | Gets the absolute stream offset where the entry data begins (translated from the on-disk relative offset). | -| `Size` | `long Size { get; init; }` | Gets the entry data size in bytes. | - -#### `Pfs0FormatDescriptor` - -Nintendo Switch PartitionFS (PFS0) archive — the flat file table inside NSP packages. References: `https://switchbrew.org/` — Switchbrew wiki — community reverse-engineered Switch format documentation (PFS0/NSP)`https://github.com/SciresM/hactool` — hactool — reference extraction tool implementing PFS0 - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pfs0FormatDescriptor` | `Pfs0FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Appends or replaces files inside an existing PFS0 archive. PFS0 has a flat header + entry table + string table + data region layout that is rewritten in place via `Pfs0InPlaceModifier` — the existing entries are preserved verbatim, the new file is inserted (or replaces one with the same name), the entry table is re-sorted alphabetically per the Switch SDK convention, and the data region is re-laid out so payloads stay contiguous. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | Rebuild-based defrag: extracts then re-creates the PFS0 archive in listing order. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rebuild-based defrag: extracts then re-creates the PFS0 archive per the requested mode. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single entry as a bounded read-only stream. The reader produces the decoded bytes per entry; the matched bytes are wrapped in a `BoundedEntryStream` sized to their logical length. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing PFS0 archive. The data region is re-laid out so the removed payloads are physically dropped — no forensic trace of the removed bytes remains in the resulting archive. | - -#### `Pfs0InPlaceModifier` - -In-place modifier for Nintendo Switch PartitionFS (PFS0) archives. PFS0 has a flat layout — header + entry table + string table + data region — that lends itself to shift-in-place mutation. On `AddFiles` the existing header / entry table / string table / data region are read into RAM, the new file is appended, the in-memory layout is rewritten with the new alphabetically-sorted entry table + string table + data region, and finally the buffer is written back to the underlying stream. The stream's length is set to the new length. On `RemoveFiles` the chosen entries are dropped from the entry table, the string table is rebuilt without their names, and the data region is re-laid-out so the remaining payloads stay contiguous. Removed payload bytes never appear in the new buffer — no forensic trace of the deleted entry remains. Layout (little-endian): 0x00 char[4] "PFS0" 0x04 u32 file_count 0x08 u32 string_table_size 0x0C u32 reserved 0x10.. file_count × 24-byte entries (data_offset, data_size, name_offset, reserved) then string_table_size bytes of NUL-terminated UTF-8 names then the data region (concatenated payloads). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFiles` | `static void AddFiles(Stream archive, IReadOnlyList> inputs)` | Adds — or replaces by name — files in an existing PFS0 archive. The archive is rewritten in place at the underlying stream. | -| `RemoveFiles` | `static int RemoveFiles(Stream archive, IReadOnlyList names)` | Removes the named entries from an existing PFS0 archive. Names that don't exist are silently ignored. Returns the number of entries actually removed. | - -#### `Pfs0Reader` - -Reads entries from a Nintendo Switch PartitionFS (PFS0) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pfs0Reader` | `Pfs0Reader(Stream stream, bool leaveOpen = false)` | Initializes a new `Pfs0Reader` from a stream. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all entries in the PFS0 archive. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(Pfs0Entry entry)` | Extracts the raw data for a given entry. | - -#### `Pfs0Writer` - -Creates a Nintendo Switch PartitionFS (PFS0) archive. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Pfs0Writer` | `Pfs0Writer(Stream stream, bool leaveOpen = false)` | Initializes a new `Pfs0Writer`. | -| `AddEntry` | `void AddEntry(string name, byte[] data)` | Adds an entry to the archive. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the PFS0 archive to the stream and finishes writing. | - -### Namespace `FileFormat.Qcow2` - -[`Qcow2Entry`](#qcow2entry) · [`Qcow2FormatDescriptor`](#qcow2formatdescriptor) · [`Qcow2LayoutMap`](#qcow2layoutmap) · [`Qcow2Reader`](#qcow2reader) · [`Qcow2Stream`](#qcow2stream) · [`Qcow2Writer`](#qcow2writer) - -#### `Qcow2Entry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `Qcow2Entry` | `Qcow2Entry()` | | -| `Name` | `string Name { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `Qcow2FormatDescriptor` - -QEMU Copy-On-Write v2/v3 (qcow2) disk image — two-level L1/L2 cluster-mapped sparse virtual disk. References: `docs/interop/qcow2.rst` in the QEMU source tree — the authoritative on-disk specification`https://gitlab.com/qemu-project/qemu` — canonical QEMU repository`https://en.wikipedia.org/wiki/Qcow` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IPartitionEditable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Qcow2FormatDescriptor` | `Qcow2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | - -#### `Qcow2LayoutMap` - -Walks a QCOW2 image and emits the byte-level layout: header, L1 table, L2 tables, refcount table, refcount blocks, and data clusters. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream stream)` | | - -#### `Qcow2Reader` - -Reads QCOW2 (QEMU Copy-On-Write v2/v3) disk images. Supports uncompressed, zlib-compressed, and zero clusters. Magic: 0x514649FB ("QFI\xFB") at offset 0, big-endian header. Streams reads via `SectorCache` so opening a multi-TB image does not load the whole file into RAM — only the header, L1/L2 tables and (during `ExtractDisk`) the requested cluster bytes are fetched on demand. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Qcow2Reader` | `Qcow2Reader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `VirtualSize` | `long VirtualSize { get; }` | Virtual disk size in bytes. | -| `Dispose` | `void Dispose()` | | -| `ExtractDisk` | `byte[] ExtractDisk()` | Extracts the full virtual disk image, resolving all L1/L2 table entries. Zero L2 entries yield zero-filled clusters; compressed entries are inflated via raw deflate. | - -#### `Qcow2Stream` - -Provides seekable read/write access to the virtual disk content of an uncompressed QCOW2 v2/v3 image. Translates virtual offsets through the L1 and L2 tables. Reads from unallocated clusters return zeros. Writes to unallocated clusters allocate new clusters at EOF and update L2 entries and refcounts. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `TryOpen` | `static Qcow2Stream TryOpen(Stream stream)` | Tries to open a `Qcow2Stream` for an uncompressed QCOW2 image. Returns `null` if the stream is not a valid QCOW2 or uses unsupported features. | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `Qcow2Writer` - -Writes QCOW2 v2 disk images in WORM mode. Takes a single raw disk image and wraps it in a QCOW2 container with uncompressed clusters. Layout: header (cluster 0) → L1 table (cluster 1) → L2 tables → refcount table → refcount block → data clusters. Each cluster has a refcount of 1, and every L1/L2 entry that points at such a single-refcount cluster carries the `QCOW_OFLAG_COPIED` flag (bit 63). This matches the arrangement `qemu-img create` produces, so `qemu-img check` reports no errors. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Qcow2Writer` | `Qcow2Writer()` | | -| `SetDiskImage` | `void SetDiskImage(byte[] data)` | | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileFormat.T64` - -[`T64BlockMover`](#t64blockmover) · [`T64Entry`](#t64entry) · [`T64FormatDescriptor`](#t64formatdescriptor) · [`T64InPlaceModifier`](#t64inplacemodifier) · [`T64Modifier`](#t64modifier) · [`T64Reader`](#t64reader) · [`T64Writer`](#t64writer) - -#### `T64BlockMover` - -In-place T64 block mover. Moves data extents within a T64 tape image and patches the directory entry's data-offset field so the file remains reachable. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `T64BlockMover` | `T64BlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `T64Entry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `T64Entry` | `T64Entry()` | | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `EndAddress` | `ushort EndAddress { get; init; }` | | -| `EntryType` | `byte EntryType { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | -| `StartAddress` | `ushort StartAddress { get; init; }` | | - -#### `T64FormatDescriptor` - -Commodore 64 T64 tape container — directory of memory-load records. References: Peter Schepers, "C64 File Formats: T64" — the classic reference document`https://vice-emu.sourceforge.io/` — VICE emulator — reference implementation reading/writing T64 - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemBlockMover`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `T64FormatDescriptor` | `T64FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing T64 tape image via `T64InPlaceModifier`. If a directory slot is free the entry drops in directly and the new payload is appended at EOF. If the directory is full the directory grows by one 32-byte slot — the payload region shifts forward by 32 bytes and every existing slot's absolute dataOffset field is patched. No full image rebuild. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Defragments a T64 image. Falls back to rebuild since T64 data offsets are stored in directory entries and recompaction is simplest via rebuild. | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | Enumerates the byte layout of a T64 tape image: 64-byte header as MetadataReserved, N×32-byte directory entries as MetadataReserved, and each file's data region as Used. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing T64 tape image via `T64InPlaceModifier`. Later directory slots shift up by 32 bytes, the removed payload bytes are wiped, the remaining payload region shifts to close the gap (each affected slot's absolute dataOffset is patched), and the stream is truncated. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `T64InPlaceModifier` - -True in-place R/W modifier for Commodore 64 `.t64` tape images. Performs O(touched bytes) byte-level region shifts against the raw stream instead of read-extract-rebuild. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, ushort startAddress = 2049)` | Adds (or replaces by name, case-insensitive) a single file inside an existing T64 stream. The image is mutated in-place — no full rebuild. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name)` | Removes a named entry from the T64 stream. Returns true if found and removed. | - -#### `T64Modifier` - -In-place T64 modifier — performs O(touched bytes) random-access I/O against a T64 tape image. T64 has a 64-byte header followed by a fixed-size directory table of N×32-byte slots, then concatenated file data. AddFile: finds an empty slot (entryType=0) in the directory, appends file data at EOF, and fills in the slot.RemoveFile: sets the slot's entryType to 0 (marks it free). Data is left in place (no compaction). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, ushort startAddress = 2049)` | Adds a file to an existing T64 tape image. Finds the first free slot (entryType=0) in the directory, appends the file data at the end of the image, and writes the directory entry. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name)` | Removes a named file from the T64 image by zeroing its directory entry type. Returns false if not found. | - -#### `T64Reader` - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `T64Reader` | `T64Reader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `TapeName` | `string TapeName { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(T64Entry entry)` | | - -#### `T64Writer` - -| Member | Signature | Summary | -| --- | --- | --- | -| `T64Writer` | `T64Writer()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `AddFile` | `void AddFile(string name, ushort startAddress, byte[] data)` | | -| `Build` | `byte[] Build(string tapeName = "TAPE")` | | - -### Namespace `FileFormat.Tap` - -[`TapBlockMover`](#tapblockmover) · [`TapEntry`](#tapentry) · [`TapFormatDescriptor`](#tapformatdescriptor) · [`TapModifier`](#tapmodifier) · [`TapReader`](#tapreader) · [`TapWriter`](#tapwriter) - -#### `TapBlockMover` - -In-place TAP block mover. TAP is a purely sequential format with no directory pointing into data, so "moving" an extent means physically relocating block bytes and updating the stream. The rebuild fallback is preferred for defragmentation. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TapBlockMover` | `TapBlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `TapEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `TapEntry` | `TapEntry()` | | -| `DataOffset` | `long DataOffset { get; init; }` | | -| `FileType` | `byte FileType { get; init; }` | 0=Program, 1=NumArray, 2=CharArray, 3=Code | -| `Name` | `string Name { get; init; }` | | -| `Size` | `int Size { get; init; }` | | - -#### `TapFormatDescriptor` - -ZX Spectrum TAP tape image — length-prefixed blocks as written by the ROM SAVE routine. References: `https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format` — Sinclair wiki — TAP format descriptionWorld of Spectrum "File format reference" — long-standing community documentation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemBlockMover`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TapFormatDescriptor` | `TapFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing TAP tape image. Uses `TapModifier` for in-place append at EOF (Add) and byte-shift removal (Remove) — O(touched bytes) for Add, O(tail size) for Remove. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Defragments a TAP image via rebuild (TAP is sequential with no directory). | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | Enumerates the byte layout of a TAP tape image. Each file occupies two blocks: a 19-byte header block (flag + type + name + params + checksum, preceded by a 2-byte length word) and a variable-size data block (flag + payload + checksum, preceded by a 2-byte length word). Header blocks are reported as MetadataReserved; data blocks as Used. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from an existing TAP tape image using `TapModifier` — walks the block chain, shifts trailing bytes. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `TapModifier` - -In-place TAP modifier — performs O(touched bytes) random-access I/O against a ZX Spectrum TAP tape image. AddFile: appends a header block + data block pair at EOF.RemoveFile: walks the block chain to find the target, then shifts all trailing bytes forward to fill the gap and truncates the stream. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte fileType = 3)` | Appends a file (header block + data block pair) at the end of an existing TAP image. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name)` | Removes the first file matching `name` from the TAP image. Walks the block chain to find the header+data pair, shifts trailing bytes forward, and truncates. Returns false if not found. | - -#### `TapReader` - -Reads ZX Spectrum TAP tape image files. TAP has no magic bytes — detection is by file extension only. Structure: sequence of blocks, each preceded by a uint16 LE block length. First byte of each block is a flag: 0x00 = header block, 0xFF = data block. Header blocks are 19 bytes: flag + fileType + 10-byte name + dataLength(u16) + param1(u16) + param2(u16) + checksum. Data blocks carry the actual file payload: flag + data + checksum. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TapReader` | `TapReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Extract` | `byte[] Extract(TapEntry entry)` | Extracts the payload of an entry (excluding flag and checksum bytes). | - -#### `TapWriter` - -Writes ZX Spectrum TAP tape image files. Each file is stored as a paired header block + data block. Checksum = XOR of all bytes in the block (including the flag byte). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `TapWriter` | `TapWriter(Stream output, bool leaveOpen = false)` | | -| `AddFile` | `void AddFile(string name, byte[] data, byte fileType = 3)` | Queues a file to be written as a header+data block pair. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes all queued files to the output stream as sequential block pairs. | - -### Namespace `FileFormat.UImage` - -[`UImageFormatDescriptor`](#uimageformatdescriptor) · [`UImageReader`](#uimagereader) · [`UImageReader.UImage`](#uimagereaderuimage) - -#### `UImageFormatDescriptor` - -Pseudo-archive descriptor for U-Boot legacy uImage containers (`mkimage` output). Exposes `metadata.ini`, `header.bin` (the 64-byte legacy header) and `payload.bin` (the compressed body verbatim). When the body compression is `none` an additional `payload_decompressed.bin` is emitted; for gzip/bzip2/lzma/lzo/lz4/zstd the body is left compressed and the `metadata.ini` notes which scheme the caller needs to apply. References: `https://docs.u-boot.org/` — U-Boot documentation`https://github.com/u-boot/u-boot` — U-Boot sources — `include/image.h` defines the 64-byte legacy header - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UImageFormatDescriptor` | `UImageFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `UImageReader` - -Reader for the legacy U-Boot uImage container (`mkimage` output). The fixed 64-byte big-endian header is followed by a body whose length is declared in the header and whose compression is selected by the `ih_comp` byte. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UImageReader` | `UImageReader()` | | -| `HeaderSize` | `const int HeaderSize` | Length of the fixed-size legacy header. | -| `Magic` | `const uint Magic` | Legacy uImage magic `0x27051956` (BE u32 at offset 0). | -| `NameLength` | `const int NameLength` | Length of the image-name field. | -| `ArchName` | `static string ArchName(byte arch)` | Decodes the `ih_arch` byte to a readable name. | -| `CompressionName` | `static string CompressionName(byte comp)` | Decodes the `ih_comp` byte to a readable name. | -| `OsName` | `static string OsName(byte os)` | Decodes the `ih_os` byte to a readable name. | -| `Read` | `static UImage Read(ReadOnlySpan data)` | Parses a uImage from a full-file byte span. | -| `TypeName` | `static string TypeName(byte type)` | Decodes the `ih_type` byte to a readable name. | - -#### `UImageReader.UImage` - -Parsed uImage container. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UImage` | `UImage(uint Magic, uint HeaderCrc, uint Timestamp, uint DataSize, uint LoadAddress, uint EntryPoint, uint DataCrc, byte Os, byte Architecture, byte Type, byte Compression, string Name, byte[] Header, byte[] Body, uint ComputedHeaderCrc, uint ComputedDataCrc)` | Parsed uImage container. | -| `Architecture` | `byte Architecture { get; init; }` | | -| `Body` | `byte[] Body { get; init; }` | | -| `Compression` | `byte Compression { get; init; }` | | -| `ComputedDataCrc` | `uint ComputedDataCrc { get; init; }` | | -| `ComputedHeaderCrc` | `uint ComputedHeaderCrc { get; init; }` | | -| `DataCrc` | `uint DataCrc { get; init; }` | | -| `DataSize` | `uint DataSize { get; init; }` | | -| `EntryPoint` | `uint EntryPoint { get; init; }` | | -| `HeaderCrc` | `uint HeaderCrc { get; init; }` | | -| `Header` | `byte[] Header { get; init; }` | | -| `LoadAddress` | `uint LoadAddress { get; init; }` | | -| `Magic` | `uint Magic { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Os` | `byte Os { get; init; }` | | -| `Timestamp` | `uint Timestamp { get; init; }` | | -| `Type` | `byte Type { get; init; }` | | - -### Namespace `FileFormat.UefiFv` - -[`UefiFvFormatDescriptor`](#uefifvformatdescriptor) · [`UefiFvReader`](#uefifvreader) · [`UefiFvReader.FfsFile`](#uefifvreaderffsfile) · [`UefiFvReader.FirmwareVolume`](#uefifvreaderfirmwarevolume) · [`UefiFvReader.FvHeader`](#uefifvreaderfvheader) - -#### `UefiFvFormatDescriptor` - -Pseudo-archive descriptor for UEFI PI Firmware Volumes (`.fv`/`.fd`). Locates the FV by scanning for the `_FVH` signature at offset 40 and emits one entry per FFS file, named `{GUID}_{TYPE_TAG}.bin`. References: `https://uefi.org/specifications` — UEFI Platform Initialization (PI) Specification — Volume 3 defines Firmware Volumes and FFS`https://github.com/LongSoft/UEFITool` — UEFITool — canonical firmware-volume parser/editor - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UefiFvFormatDescriptor` | `UefiFvFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `UefiFvReader` - -Reader for UEFI Platform Initialization (PI) Firmware Volumes. Locates the FV header by scanning for the `_FVH` signature at offset 40 from the start of each 16-byte-aligned candidate (UEFI PI Volume 3). Walks the FFS file list and returns one `FfsFile` record per file. - -| Member | Signature | Summary | -| --- | --- | --- | -| `UefiFvReader` | `UefiFvReader()` | | -| `SignatureOffset` | `const int SignatureOffset` | Signature offset from FV start. | -| `Signature` | `static readonly byte[] Signature` | FV signature bytes (`_FVH`) at FV offset 40. | -| `FileTypeName` | `static string FileTypeName(byte t)` | Decodes the FFS type byte to the UEFI PI spec name. | -| `FindFirst` | `static int? FindFirst(ReadOnlySpan data)` | Scans `data` for the first `_FVH` signature and returns the FV start. | -| `Read` | `static FirmwareVolume Read(ReadOnlySpan data, int fvStart = 0)` | Parses a firmware volume located at the given file offset. | -| `ShortTypeTag` | `static string ShortTypeTag(byte t)` | Returns a short type tag for use in entry names (e.g. `RAW`, `DRIVER`). | - -#### `UefiFvReader.FfsFile` - -A single FFS (Firmware File System) file inside the FV. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FfsFile` | `FfsFile(Guid Name, byte Type, byte Attributes, byte State, uint Size, byte[] Contents)` | A single FFS (Firmware File System) file inside the FV. | -| `Attributes` | `byte Attributes { get; init; }` | FFS file attributes byte. | -| `Contents` | `byte[] Contents { get; init; }` | File contents (size minus the 24-byte header). | -| `Name` | `Guid Name { get; init; }` | File GUID (`EFI_FFS_FILE_HEADER.Name`). | -| `Size` | `uint Size { get; init; }` | Declared file size including the 24-byte header. | -| `State` | `byte State { get; init; }` | FFS file state byte. | -| `Type` | `byte Type { get; init; }` | Raw FFS type byte (see `FileTypeName`). | - -#### `UefiFvReader.FirmwareVolume` - -Parsed firmware volume. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FirmwareVolume` | `FirmwareVolume(int StartOffset, FvHeader Header, IReadOnlyList Files)` | Parsed firmware volume. | -| `Files` | `IReadOnlyList Files { get; init; }` | | -| `Header` | `FvHeader Header { get; init; }` | | -| `StartOffset` | `int StartOffset { get; init; }` | | - -#### `UefiFvReader.FvHeader` - -FV header (excluding block map + extended header body). - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FvHeader` | `FvHeader(Guid FileSystemGuid, ulong FvLength, uint Attributes, ushort HeaderLength, ushort Checksum, ushort ExtHeaderOffset, byte Revision, IReadOnlyList> BlockMap)` | FV header (excluding block map + extended header body). | -| `Attributes` | `uint Attributes { get; init; }` | | -| `BlockMap` | `IReadOnlyList> BlockMap { get; init; }` | | -| `Checksum` | `ushort Checksum { get; init; }` | | -| `ExtHeaderOffset` | `ushort ExtHeaderOffset { get; init; }` | | -| `FileSystemGuid` | `Guid FileSystemGuid { get; init; }` | | -| `FvLength` | `ulong FvLength { get; init; }` | | -| `HeaderLength` | `ushort HeaderLength { get; init; }` | | -| `Revision` | `byte Revision { get; init; }` | | - -### Namespace `FileFormat.Vdi` - -[`VdiEntry`](#vdientry) · [`VdiFormatDescriptor`](#vdiformatdescriptor) · [`VdiLayoutMap`](#vdilayoutmap) · [`VdiReader`](#vdireader) · [`VdiStream`](#vdistream) · [`VdiWriter`](#vdiwriter) - -#### `VdiEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `VdiEntry` | `VdiEntry()` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `VdiFormatDescriptor` - -VirtualBox VDI virtual disk image — block-mapped sparse/fixed disk container. References: `https://www.virtualbox.org/` — VirtualBox — the VDI layout is defined by its open-source Storage/VDI code`https://en.wikipedia.org/wiki/VDI_(file_format)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IPartitionEditable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VdiFormatDescriptor` | `VdiFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | - -#### `VdiLayoutMap` - -Walks a VDI image and emits the byte-level layout: pre-header, header, block allocation map, and data blocks (allocated vs unallocated). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream stream)` | | - -#### `VdiReader` - -Reads VirtualBox Disk Image (VDI) files. Layout: Offset 0: 64 bytes pre-header text (null-padded) Offset 64: uint32 LE signature = 0xBEDA107F Offset 68: uint32 version Offset 72: uint32 cbHeader (size of header, usually 400) Offset 76: uint32 uImageType (1=dynamic, 2=fixed) Offset 80: uint32 fFlags Offset 84: 256 bytes description (null-terminated) Offset 340: uint32 offsetBlocks Offset 344: uint32 offsetData Offset 348: uint32 cCylinders Offset 352: uint32 cHeads Offset 356: uint32 cSectors Offset 360: uint32 cbSector (512) Offset 364: uint32 unused Offset 368: uint64 cbDisk (virtual disk size in bytes) Offset 376: uint32 cbBlock (block size, typically 1MB) Offset 380: uint32 cbBlockExtra (usually 0) Offset 384: uint32 cBlocks (total number of blocks) Offset 388: uint32 cBlocksAllocated Offset 392: 16 bytes UUID image Offset 408: 16 bytes UUID last snapshot Offset 424: 16 bytes UUID link Offset 440: 16 bytes UUID parent Streams reads via `SectorCache` so opening a multi-TB image does not load the whole file into RAM — only the header, block map and (during `ExtractDisk`) the requested block bytes are fetched on demand. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VdiReader` | `VdiReader(Stream stream, bool leaveOpen = false)` | | -| `VdiSignature` | `const uint VdiSignature` | | -| `AllocatedBlockCount` | `uint AllocatedBlockCount { get; }` | Number of allocated blocks. | -| `BlockCount` | `uint BlockCount { get; }` | Total number of blocks (including unallocated). | -| `BlockSize` | `uint BlockSize { get; }` | Block size in bytes. | -| `ImageType` | `uint ImageType { get; }` | Image type: 1 = dynamic, 2 = fixed. | -| `OffsetBlocks` | `uint OffsetBlocks { get; }` | Offset of the block allocation map. | -| `OffsetData` | `uint OffsetData { get; }` | Offset of the first data block. | -| `VirtualSize` | `long VirtualSize { get; }` | Virtual disk size in bytes. | -| `Dispose` | `void Dispose()` | | -| `ExtractDisk` | `byte[] ExtractDisk()` | Reconstructs the full disk image by reading all blocks sequentially. Unallocated blocks (map entry = 0xFFFFFFFF) are returned as zeros. | - -#### `VdiStream` - -Provides seekable read/write access to the virtual disk content of a VDI image. Translates virtual block offsets through the block allocation map (BAM). Reads from unallocated blocks (BAM entry = 0xFFFFFFFF) return zeros. Writes to unallocated blocks allocate new data blocks at EOF and update the BAM entry and allocated block count. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `TryOpen` | `static VdiStream TryOpen(Stream stream)` | Tries to open a `VdiStream` for a VDI image (dynamic or fixed). Returns `null` if the stream is not a valid VDI. | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `VdiWriter` - -Writes a dynamic VirtualBox Disk Image (VDI) file. Dynamic VDIs only allocate blocks for non-zero data; all-zero blocks are represented by the sentinel value 0xFFFFFFFF in the block map. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VdiWriter` | `VdiWriter(Stream output, bool leaveOpen = false, long virtualSize = 0, uint blockSize = 1048576)` | | -| `Dispose` | `void Dispose()` | | -| `Write` | `void Write(byte[] diskData)` | Writes a complete dynamic VDI image from the supplied raw disk data. | - -### Namespace `FileFormat.Vhd` - -[`VhdCompactor`](#vhdcompactor) · [`VhdCompactor.CompactResult`](#vhdcompactorcompactresult) · [`VhdEntry`](#vhdentry) · [`VhdFormatDescriptor`](#vhdformatdescriptor) · [`VhdLayoutMap`](#vhdlayoutmap) · [`VhdReader`](#vhdreader) · [`VhdStream`](#vhdstream) · [`VhdWriter`](#vhdwriter) - -#### `VhdCompactor` - -Compacts a dynamic VHD image by scanning the BAT for blocks whose data is all-zero, marking them as unallocated (BAT entry = 0xFFFFFFFF), and then rebuilding the physical file to remove the unused blocks. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Compact` | `static CompactResult Compact(Stream image)` | Compacts a dynamic VHD by identifying all-zero allocated blocks, marking them as sparse in the BAT, and rebuilding the file to eliminate the freed physical blocks. Fixed VHDs are converted to dynamic to enable sparse blocks, then compacted. | - -#### `VhdCompactor.CompactResult` - -Result of a VHD compaction: original and new file sizes, plus the number of blocks that were freed. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompactResult` | `CompactResult(long OriginalSize, long NewSize, int BlocksFreed, bool WasReduced)` | Result of a VHD compaction: original and new file sizes, plus the number of blocks that were freed. | -| `BlocksFreed` | `int BlocksFreed { get; init; }` | | -| `NewSize` | `long NewSize { get; init; }` | | -| `OriginalSize` | `long OriginalSize { get; init; }` | | -| `WasReduced` | `bool WasReduced { get; init; }` | | - -#### `VhdEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdEntry` | `VhdEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `VhdFormatDescriptor` - -Microsoft VHD virtual hard disk (fixed/dynamic/differencing; 512-byte footer). References: Microsoft, "Virtual Hard Disk Image Format Specification" v1.0 (2006, published under the Open Specification Promise)`https://github.com/libyal/libvhdi` — libvhdi — open implementation with format documentation`https://en.wikipedia.org/wiki/VHD_(file_format)` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IPartitionEditable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdFormatDescriptor` | `VhdFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | - -#### `VhdLayoutMap` - -Walks a VHD image and emits the byte-level layout of the container's own structure: footer (copy), dynamic header, BAT, sector bitmaps, data blocks, and trailing footer. For fixed VHDs: raw data + trailing footer. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream stream)` | | - -#### `VhdReader` - -Reader for Microsoft VHD images (fixed, dynamic and differencing). Streams reads via `SectorCache` so opening a multi-TB image does not load the whole file into RAM — only the footer, dynamic header, BAT and (during `Extract`) the requested block bytes are fetched on demand. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdReader` | `VhdReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(VhdEntry entry)` | | - -#### `VhdStream` - -Provides seekable read/write access to the virtual disk content of a VHD (both Fixed and Dynamic). For a fixed VHD the raw disk data occupies bytes [0 .. fileLength-512) and the trailing 512-byte footer is hidden. For a dynamic VHD the BAT (Block Allocation Table) maps virtual 2 MB blocks to physical file offsets; unallocated blocks read as zeros and are allocated at EOF on write. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdStream` | `VhdStream(Stream backing, bool leaveOpen = false)` | Creates a `VhdStream` over an existing VHD file stream. Auto-detects fixed vs dynamic from the footer's disk_type field. | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `VhdWriter` - -Creates fixed or dynamic VHD images. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdWriter` | `VhdWriter()` | | -| `BuildDynamic` | `byte[] BuildDynamic(int blockSize = 2097152)` | Builds a dynamic (sparse) VHD image with a BAT. Non-zero blocks are written; all-zero blocks are stored as sparse (BAT entry = 0xFFFFFFFF). | -| `Build` | `byte[] Build()` | Builds a fixed VHD image: raw data followed by a 512-byte footer. | -| `SetDiskData` | `void SetDiskData(byte[] data)` | Sets the raw disk data to embed in the VHD. | - -### Namespace `FileFormat.Vhdx` - -[`VhdxFormatDescriptor`](#vhdxformatdescriptor) · [`VhdxReader`](#vhdxreader) · [`VhdxReader.HeaderInfo`](#vhdxreaderheaderinfo) · [`VhdxReader.VhdxImage`](#vhdxreadervhdximage) · [`VhdxStream`](#vhdxstream) · [`VhdxWriter`](#vhdxwriter) - -#### `VhdxFormatDescriptor` - -Descriptor for Hyper-V VHDX virtual hard-disk images (MS-VHDX v1). For fixed-payload VHDX images the descriptor delegates List, Extract, Add, Remove, and Defragment operations to the detected inner filesystem via `VhdxStream`. Falls back to structural metadata listing when the inner FS is not detected or the image uses dynamic/differencing layout. References: [MS-VHDX]: Virtual Hard Disk v2 (VHDX) File Format (Microsoft Open Specifications, learn.microsoft.com)`https://github.com/libyal/libvhdi` — libvhdi — open VHD/VHDX implementation with format documentation`https://en.wikipedia.org/wiki/VHD_(file_format)` — Wikipedia overview (covers VHDX) - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IPartitionEditable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdxFormatDescriptor` | `VhdxFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Wraps the supplied input files into a fixed-payload VHDX container. | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | - -#### `VhdxReader` - -Reader for Hyper-V VHDX virtual hard-disk images (MS-VHDX v1). Splits the file into the 64KB File Type Identifier region, the two 64KB header copies, and the two 64KB region tables. Full block-level decompression is out of scope; this first pass surfaces enough structural state for identification and comparison against reference parsers like qemu-img. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdxReader` | `VhdxReader()` | | -| `FileSignature` | `static readonly byte[] FileSignature` | | -| `FileTypeIdentifierOffset` | `const int FileTypeIdentifierOffset` | | -| `Header1Offset` | `const int Header1Offset` | | -| `Header2Offset` | `const int Header2Offset` | | -| `HeaderSignature` | `static readonly byte[] HeaderSignature` | | -| `RegionSize` | `const int RegionSize` | | -| `RegionTable1Offset` | `const int RegionTable1Offset` | | -| `RegionTable2Offset` | `const int RegionTable2Offset` | | -| `RegionTableSignature` | `static readonly byte[] RegionTableSignature` | | -| `Read` | `static VhdxImage Read(ReadOnlySpan data)` | | -| `Read` | `static VhdxImage Read(ReadOnlySpan data, long totalFileSize)` | Parses VHDX header bytes. `data` only needs to span the header region (~0x50000 bytes); `totalFileSize` is the length of the underlying physical file used solely for reporting. | - -#### `VhdxReader.HeaderInfo` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HeaderInfo` | `HeaderInfo(uint Checksum, ulong SequenceNumber, Guid FileWriteGuid, Guid DataWriteGuid, Guid LogGuid, ushort LogVersion, ushort Version, uint LogLength, ulong LogOffset)` | | -| `Checksum` | `uint Checksum { get; init; }` | | -| `DataWriteGuid` | `Guid DataWriteGuid { get; init; }` | | -| `FileWriteGuid` | `Guid FileWriteGuid { get; init; }` | | -| `LogGuid` | `Guid LogGuid { get; init; }` | | -| `LogLength` | `uint LogLength { get; init; }` | | -| `LogOffset` | `ulong LogOffset { get; init; }` | | -| `LogVersion` | `ushort LogVersion { get; init; }` | | -| `SequenceNumber` | `ulong SequenceNumber { get; init; }` | | -| `Version` | `ushort Version { get; init; }` | | - -#### `VhdxReader.VhdxImage` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdxImage` | `VhdxImage(string Creator, byte[] FileTypeIdentifier, byte[] HeaderPrimary, byte[] HeaderBackup, byte[] RegionTablePrimary, byte[] RegionTableBackup, HeaderInfo PrimaryHeaderInfo, HeaderInfo BackupHeaderInfo, long TotalFileSize)` | | -| `BackupHeaderInfo` | `HeaderInfo BackupHeaderInfo { get; init; }` | | -| `Creator` | `string Creator { get; init; }` | | -| `FileTypeIdentifier` | `byte[] FileTypeIdentifier { get; init; }` | | -| `HeaderBackup` | `byte[] HeaderBackup { get; init; }` | | -| `HeaderPrimary` | `byte[] HeaderPrimary { get; init; }` | | -| `PrimaryHeaderInfo` | `HeaderInfo PrimaryHeaderInfo { get; init; }` | | -| `RegionTableBackup` | `byte[] RegionTableBackup { get; init; }` | | -| `RegionTablePrimary` | `byte[] RegionTablePrimary { get; init; }` | | -| `TotalFileSize` | `long TotalFileSize { get; init; }` | | - -#### `VhdxStream` - -Provides seekable read/write access to the virtual disk content of a VHDX (both fixed and dynamic). For a fixed VHDX (all BAT entries FULLY_PRESENT), the data blocks are mapped through the BAT. For a dynamic VHDX, blocks with state PAYLOAD_BLOCK_NOT_PRESENT return zeros on read and are allocated at EOF on write. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `TryOpen` | `static VhdxStream TryOpen(Stream stream)` | Tries to open a `VhdxStream` for a VHDX image (fixed or dynamic). Returns `null` if the stream is not a valid VHDX (too small, bad signature, has parent locator, etc.). The caller owns the returned stream and must dispose it. | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `VhdxWriter` - -Writes spec-compliant Microsoft VHDX (MS-VHDX v2) virtual hard-disk images from a raw disk byte buffer. Produces a fixed-payload (non-differencing, no-log) container — every block is marked PAYLOAD_BLOCK_FULLY_PRESENT. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VhdxWriter` | `VhdxWriter()` | | -| `Build` | `byte[] Build()` | Builds the VHDX container as a single byte array. | -| `SetCreator` | `void SetCreator(string creator)` | Sets the Creator string written into the File Type Identifier (max 256 UTF-16LE chars). | -| `SetDiskData` | `void SetDiskData(byte[] data)` | Sets the raw disk data to embed. Will be padded to the next 16 MiB boundary. | - -### Namespace `FileFormat.Vmdk` - -[`VmdkEntry`](#vmdkentry) · [`VmdkFormatDescriptor`](#vmdkformatdescriptor) · [`VmdkLayoutMap`](#vmdklayoutmap) · [`VmdkReader`](#vmdkreader) · [`VmdkStream`](#vmdkstream) · [`VmdkWriter`](#vmdkwriter) - -#### `VmdkEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `VmdkEntry` | `VmdkEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `VmdkFormatDescriptor` - -VMware VMDK virtual disk (sparse extents with grain directories/tables). References: VMware, "Virtual Disk Format 5.0" technical note — the vendor VMDK specification`https://github.com/libyal/libvmdk` — libvmdk — open implementation with format documentation`https://en.wikipedia.org/wiki/VMDK` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveLayoutMap`, `IArchiveModifiable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IPartitionEditable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VmdkFormatDescriptor` | `VmdkFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `EnumerateLayout` | `IEnumerable EnumerateLayout(Stream archive)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenGuestDiskStream` | `Stream OpenGuestDiskStream(Stream image)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | - -#### `VmdkLayoutMap` - -Walks a sparse VMDK image and emits the byte-level layout: sparse header, embedded descriptor, grain directory, grain tables, and data grains. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream stream)` | | - -#### `VmdkReader` - -Reader for VMware VMDK images (sparse and flat/descriptor). Streams reads via `SectorCache` so opening a multi-TB image does not load the whole file into RAM — only the header, grain directory and (during `Extract`) the requested grain bytes are fetched on demand. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `VmdkReader` | `VmdkReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(VmdkEntry entry)` | | - -#### `VmdkStream` - -Provides seekable read/write access to the virtual disk content of a monolithic sparse VMDK. Translates virtual disk offsets through the grain directory and grain tables. Reads from unallocated grains return zeros. Writes to unallocated grains lazily allocate a fresh grain (and grain table, when needed) at the end of the backing file and update the grain directory + grain table on disk so the new contents are visible on the next read. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `TryOpen` | `static VmdkStream TryOpen(Stream stream)` | Tries to open a `VmdkStream` for a sparse VMDK. Returns `null` if the stream is not a valid sparse VMDK. | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `VmdkWriter` - -| Member | Signature | Summary | -| --- | --- | --- | -| `VmdkWriter` | `VmdkWriter()` | | -| `Build` | `byte[] Build()` | Builds a monolithic sparse VMDK with a proper two-level grain directory/table structure, including the redundant grain directory that VMware/qemu emit by default. | -| `SetDiskData` | `void SetDiskData(byte[] data)` | | - -### Namespace `FileSystem.Adf` - -[`AdfBlockMover`](#adfblockmover) · [`AdfEntry`](#adfentry) · [`AdfExtentMap`](#adfextentmap) · [`AdfFormatDescriptor`](#adfformatdescriptor) · [`AdfModifier`](#adfmodifier) · [`AdfReader`](#adfreader) · [`AdfWriter`](#adfwriter) - -#### `AdfBlockMover` - -In-place Amiga FFS block mover. Moves sector-aligned extents within an ADF image and patches the file header block's data-block pointer table, the root hash table (if the header block itself moved), and the bitmap. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdfBlockMover` | `AdfBlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `AdfEntry` - -Represents a single file or directory entry found within an ADF disk image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdfEntry` | `AdfEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | The full slash-separated path from the disk root (e.g. "dir/subdir/file.txt"). | -| `HeaderBlock` | `int HeaderBlock { get; init; }` | The sector number of the file or directory header block on the disk. | -| `IsDirectory` | `bool IsDirectory { get; init; }` | Whether this entry is a directory rather than a file. | -| `Name` | `string Name { get; init; }` | The filename as stored in the AmigaDOS directory block. | -| `Size` | `int Size { get; init; }` | The uncompressed file size in bytes (0 for directories). | - -#### `AdfExtentMap` - -Walks an Amiga ADF image (901,120 bytes, 1760 × 512-byte sectors) and yields the actual on-disk byte layout — root block + bitmap + boot blocks as metadata, every file's header / extension / data blocks as contiguous-run extents (per-file), and unallocated sectors as Free. Supports both OFS and FFS layouts. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `AdfFormatDescriptor` - -References: `http://lclevy.free.fr/adflib/adf_info.html` — Laurent Clévy's ADF / AmigaDOS (OFS/FFS) on-disk format reference, the de-facto ADF specADFlib — the reference open-source ADF implementation built on that document`https://en.wikipedia.org/wiki/Amiga_Disk_File` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdfFormatDescriptor` | `AdfFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for ADF creation: AmigaDOS file-system flavour (OFS vs FFS) in the boot block and the AmigaDOS volume label written into the root block. The image geometry is fixed at the standard DD floppy size (880 KB, 1760 × 512-byte sectors) — Amiga DD ADF is the canonical emulator/preservation image and is the only size this writer emits. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Adf image (FFS). Uses `AdfModifier` for true O(touched bytes) random-access I/O — only the root block, the bitmap, the optional hash-chain neighbour, and the new file's header + data blocks are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware ADF defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the boot blocks + root block + bitmap blocks + per-file header/extension/data block chains, yielding the actual on-disk layout. Boot/root/bitmap and directory headers become `MetadataReserved`; file header + extension blocks + data blocks attribute to their owning file (coalesced into contiguous runs). | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing Adf image (FFS). Uses `AdfModifier` for O(touched bytes) random-access I/O. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in an Amiga ADF image: every 512-byte sector not claimed by a boot/root/bitmap block, a directory or file header, a file extension block, or a file data block. Driven by the generic `UnusedSpaceWiper` over the ADF extent map. Per-file cluster-tip wiping is not applied: an ADF file's extent is a coalesced run that interleaves the file header block, optional extension blocks and the data blocks (and, under OFS, every data block carries a 24-byte block header), so the file's logical bytes are not laid out as a flat `offset..offset+size` region. Treating the trailing bytes of that run as slack would clobber live metadata, so tip wiping is N/A here; only genuinely free sectors are zeroed. | - -#### `AdfModifier` - -Random-access in-place modifier for Amiga Disk File `.adf` images (FFS — Fast File System). Reads and writes only the root block, the bitmap, the optional hash-chain neighbour, the new file's header block, and the new file's data blocks — never the whole image. This is the O(touched bytes) path for the FFS layout the bundled `AdfWriter` emits. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds a file to an existing FFS image. Caller is responsible for ensuring the name does not already exist; use `RemoveFile` first for replace-by-name semantics. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file from the image. Returns true if found and removed. When `wipeData` is true, the data blocks and header block are zeroed. | - -#### `AdfReader` - -Reads and extracts files from an Amiga Disk File (.adf) image. Supports both OFS (Original File System) and FFS (Fast File System) disk images. Standard DD ADF images are exactly 901,120 bytes (1760 sectors of 512 bytes). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdfReader` | `AdfReader(Stream stream, bool leaveOpen = false)` | Initializes a new `AdfReader` and parses the ADF disk image. | -| `Entries` | `IReadOnlyList Entries { get; }` | Gets all file and directory entries found in the disk image. | -| `IsFfs` | `bool IsFfs { get; }` | Gets whether the disk uses FFS (Fast File System). When `false` the disk uses OFS (Original File System). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AdfEntry entry)` | Extracts and returns the raw byte content of the specified file entry. | - -#### `AdfWriter` - -Creates Amiga Disk File (.adf) images using the Fast File System (FFS). Produces standard DD disk images of exactly 901,120 bytes (1760 sectors of 512 bytes). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdfWriter` | `AdfWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? modTime = null)` | Adds a file to the disk image being built. | -| `Build` | `byte[] Build(string diskName = "DISK", byte fileSystemType = 1)` | Builds and returns the complete 901,120-byte ADF disk image. | - -### Namespace `FileSystem.AdvFs` - -[`AdvFsBlockMover`](#advfsblockmover) · [`AdvFsEntry`](#advfsentry) · [`AdvFsFormatDescriptor`](#advfsformatdescriptor) · [`AdvFsReader`](#advfsreader) · [`AdvFsWriter`](#advfswriter) - -#### `AdvFsBlockMover` - -Moves a file's bytes inside an AdvFS storage domain and repoints its row in the file table. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdvFsBlockMover` | `AdvFsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | One byte. A file table row holds an absolute byte offset, so nothing about the format asks a file to start on a boundary. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the RBMT page. | -| `Init` | `void Init(Stream image)` | Locates the file table and the start of the data area. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `AdvFsEntry` - -Logical entry surfaced by `AdvFsReader`. Header/metadata entries (`FULL.advfs`, `metadata.ini`, `rbmt_page0.bin`) carry `Offset = -1`; AdvFS-WB writer-emitted file entries carry the absolute byte offset into the image where their payload lives plus the payload length. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdvFsEntry` | `AdvFsEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | Absolute byte offset of the file payload inside the image, or -1 for synthetic header entries. | -| `Size` | `long Size { get; init; }` | | - -#### `AdvFsFormatDescriptor` - -Read-only descriptor for AdvFS (Tru64 UNIX Advanced File System, DEC/HP). Open-sourced by HP in 2008 under the GPL; the storage domain → file set → file model and the on-disk structures are described in `bs_ods.h`, `bs_disk_block.h`, and `bs_public.h` of that release. Walking the BMT (Bitfile Metadata Table) B-tree and following BFD (Bitfile Descriptor) extent chains to extract user files is explicitly out of scope (multi-week effort) — this descriptor surfaces: `FULL.advfs` — the raw image bytes`metadata.ini` — parsed BSR_DMN_ATTR/BSR_VD_ATTR/BSR_DMN_MATTR fields`rbmt_page0.bin` — 4 KB capture of RBMT page 0 (offset 131072) Detection: a 16-byte cookie `"ADVFS\0RBMT0\0\0\0\0\0"` at offset 131072 (= page 16 × 8192-byte AdvFS page). This is an internal convention rather than the canonical Tru64 on-disk magic (record type discriminators rather than a fixed bytes-at-offset signature). Real Tru64 images that don't carry the cookie will not auto-detect but can still be parsed when fed to the descriptor directly. Create / Modify: a clean-room AdvFS-WB storage-domain layout with a flat file table inside RBMT page 0; `AdvFsInPlaceModifier` performs genuine in-place add/replace/remove against that table. References: `https://sourceforge.net/projects/advfs/` — HP 2008 GPL releaseHP "AdvFS Technical Reference" (in the source tarball)Wikipedia "Advanced File System" - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdvFsFormatDescriptor` | `AdvFsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The one tunable the WORM writer honours: the textual volume tag stamped into the BSR_VD_ATTR record (64-byte field, capped at 63 ASCII bytes). `SetVolumeTag` writes it and `VolumeTag` reads it back, so the knob round-trips. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | WORM-emits a fresh AdvFS storage-domain image carrying the supplied `inputs`. Layout: zero-filled bootstrap pages 0..15, RBMT page 0 at offset 131072 with the detection cookie + DMN/VD/MATTR fields + AdvFS-WB file table, then a flat data area starting at offset 139264 holding each file's payload back-to-back. | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Everything ahead of the first payload is structure — the RBMT pages and the writer's directory — and each entry claims the bytes it was written to. What no entry claims is space a removal or a shorter replacement left. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `RebuildStreaming` | `void RebuildStreaming(Stream source, Stream target, LayoutRebuildOptions options)` | Relays the domain through the writer at the requested geometry. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | | - -#### `AdvFsReader` - -Parses the AdvFS (Tru64 UNIX Advanced File System) on-disk volume header. AdvFS was open-sourced by HP in 2008 (`https://sourceforge.net/projects/advfs/`); the on-disk layout below is taken from `bs_ods.h`, `bs_disk_block.h`, and `bs_public.h` in that release. AdvFS layout summary: Disk page size = 8192 bytes (`BS_BLKSIZE` = 512; `ADVFS_PGSZ` = 16 × 512 = 8192).Page 0 (LBA 0..15) — disk label / boot block area.Page 16 (LBA 32) — RBMT (Reserved Bitfile Metadata Table) page 0, containing the volume's bootstrap metadata records (`BSR_VD_ATTR`, `BSR_DMN_ATTR`, `BSR_DMN_MATTR`).Each metadata record starts with a `bsMR_t` record header (`bCnt`:uint16, `type`:uint16, `version`:uint16, then payload). Detection magic: this descriptor synthesises a 16-byte cookie at offset `131072` (= page 16 × 8192) — the start of the AdvFS RBMT page 0 — using the literal ASCII tag `"ADVFS\0RBMT0\0\0\0\0\0"`. This is an internal convention since the HP source release uses record-type discriminators (`BSR_VD_ATTR` = 13, `BSR_DMN_ATTR` = 14, `BSR_DMN_MATTR` = 15) rather than a single bytes-at-offset magic. Real Tru64 images that don't carry this tag will not be detected automatically but can still be inspected once the file is fed to the descriptor directly. References: `https://sourceforge.net/projects/advfs/` — HP 2008 open-source releaseHP "AdvFS On-Disk Structure Reference" (in the source tarball under `doc/`)Wikipedia "AdvFS" - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdvFsReader` | `AdvFsReader(Stream stream)` | | -| `DetectionCookie` | `static readonly byte[] DetectionCookie` | 16-byte internal cookie used for first-pass detection at `RbmtPageOffset`. | -| `HeaderCaptureSize` | `const int HeaderCaptureSize` | Header capture surfaced to the user as `volume_header.bin`. | -| `PageSize` | `const int PageSize` | AdvFS disk page size in bytes (8 × 1024 = 16 × 512 sectors). | -| `RbmtPageOffset` | `const long RbmtPageOffset` | RBMT page lives at logical page index 16 → byte offset 131072. | -| `DomainIdHex` | `string DomainIdHex { get; }` | Storage domain attribute record fields (`BSR_DMN_ATTR` at known RBMT offset). | -| `Entries` | `List Entries { get; }` | | -| `FileTableEntries` | `List FileTableEntries { get; }` | File-table rows parsed from the AdvFS-WB extension (empty on real Tru64 images that don't carry our writer's eyecatcher). | -| `HeaderRaw` | `byte[] HeaderRaw { get; }` | | -| `MountId` | `ulong MountId { get; }` | Recorded domain MountId — 8 bytes seconds + microseconds. | -| `OnDiskVersion` | `uint OnDiskVersion { get; }` | Recorded on-disk version number (`dmnVersion`). | -| `ParseStatus` | `string ParseStatus { get; }` | | -| `State` | `uint State { get; }` | Domain state flags (`state`: BSR_DMN_MATTR state field). | -| `Valid` | `bool Valid { get; }` | | -| `VdBlkCnt` | `ulong VdBlkCnt { get; }` | Volume size in 512-byte blocks (`vdBlkCnt`). | -| `VdCount` | `uint VdCount { get; }` | Total number of volumes recorded in the storage domain. | -| `VdIndex` | `uint VdIndex { get; }` | Volume number within the storage domain (`vdIndex`). | -| `VdMetaBlkCnt` | `uint VdMetaBlkCnt { get; }` | Per-volume metadata I/O block size (`vdMetaBlkCnt`). | -| `VolumeTag` | `string VolumeTag { get; }` | Optional textual volume tag captured from the RBMT page. | -| `ExtractFileTo` | `void ExtractFileTo(AdvFsEntry entry, Stream destination)` | Copies a payload into `destination` by absolute offset/length, straight from the source when it is seekable. | -| `ExtractFile` | `byte[] ExtractFile(AdvFsEntry entry)` | Reads a file payload by absolute offset/length. | - -#### `AdvFsWriter` - -Builds minimal AdvFS (Tru64 UNIX) volume images that round-trip cleanly through `AdvFsReader`. The on-disk layout is a clean-room subset of the HP-2008 open-sourced AdvFS storage-domain model: bootstrap pages 0..15 are zero, RBMT page 0 starts at byte offset `131072` with the 16-byte detection cookie `"ADVFS\0RBMT0\0\0\0\0\0"` followed by the `BSR_DMN_ATTR` / `BSR_VD_ATTR` / `BSR_DMN_MATTR` field bundle the reader documents. A trailing AdvFS-WB file table extension (eyecatcher `"ADVFSWBFT\0\0\0\0\0\0\0"`) follows the volume tag; the reader picks it up when present so file payloads survive a write→read round-trip. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AdvFsWriter` | `AdvFsWriter(Stream output, bool leaveOpen = false)` | | -| `AddFile` | `void AddFile(string path, byte[] data)` | Registers a file to be written into the storage domain. | -| `AddStreamingFile` | `void AddStreamingFile(string path, long size, Func openStream)` | Registers a file whose bytes are produced on demand. `size` must match what `openStream` yields; the layout is settled from it before a byte is read. | -| `Build` | `static byte[] Build(IEnumerable> files, string volumeTag = null)` | Convenience: builds the image to a byte array. | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Writes the complete image to `_output`. | -| `SetVolumeTag` | `void SetVolumeTag(string tag)` | Sets the textual volume tag surfaced in the BSR_VD_ATTR record (capped at 63 ASCII bytes). | - -### Namespace `FileSystem.Apfs` - -[`ApfsBlockMover`](#apfsblockmover) · [`ApfsEntry`](#apfsentry) · [`ApfsFormatDescriptor`](#apfsformatdescriptor) · [`ApfsReader`](#apfsreader) · [`ApfsStructuralValidator`](#apfsstructuralvalidator) · [`ApfsStructuralValidator.Report`](#apfsstructuralvalidatorreport) · [`ApfsWriter`](#apfswriter) - -#### `ApfsBlockMover` - -Moves a file's blocks inside an APFS container and rewrites the extent record that named them. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApfsBlockMover` | `ApfsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | A block, which is what an extent record counts in. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the container's own head. Blocks past the file data that belong to the trees are described as reserved rather than kept behind this, because they are not all in one place. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call rewrites the record naming the run it is given, so a file in several extents is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the container while the rest of the layout moves, which is what lets a full container be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads the container once and notes where every extent record is. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `ApfsEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApfsEntry` | `ApfsEntry()` | | -| `FirstBlock` | `ulong FirstBlock { get; init; }` | First physical block of the file's data extent (0 = no extent). | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `IsSymlink` | `bool IsSymlink { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `LinkTarget` | `string LinkTarget { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `ApfsFormatDescriptor` - -References: `https://developer.apple.com/support/downloads/Apple-File-System-Reference.pdf` — Apple File System Reference, the official on-disk format specification`https://github.com/libyal/libfsapfs` — libfsapfs, maintained open-source APFS reader with format documentation`https://en.wikipedia.org/wiki/Apple_File_System` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApfsFormatDescriptor` | `ApfsFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | APFS container image. The writer emits real NXSB/APSB superblocks, container/volume object maps, and a populated FS-tree B-tree with inode + drec + file_extent records under Fletcher-64 checksums. In-place mutation supports full-scope Add / Remove: multi-component nested paths, FS-tree and OMAP B-tree splits, arbitrary-depth tree height growth, and on-the-fly directory inode synthesis for missing path components. The mutation path advances the transaction id, rebuilds every touched B-tree top-down with valid Fletcher-64 on every node, tail-allocates new physical blocks for node splits and file data (mirroring the writer's spaceman-less layout), and zeroes data blocks of removed files. `ApfsStructuralValidator` runs a paranoid post-mutation cross-check (key ordering, checksum, xid monotonicity, DIR_REC↔INODE↔FILE_EXTENT linkage). Genuinely-out-of-scope: snapshots, encryption / FileVault, fusion / tiered storage, sparse clones. | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The only writer-honoured knob is the volume name, written to the APSB `apfs_volname` field. The container block size is fixed at 4 KiB and is not exposed. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds files to the volume in place via `ApfsModifier`. Supports nested paths (synthesises missing intermediate directory inodes), arbitrary FS-tree / OMAP B-tree splits with tree height growth, contiguous tail allocation for split nodes and file data, per-block Fletcher-64 recompute, and xid advance. Genuinely-out-of-scope features (snapshots, encryption, fusion, sparse clones) still throw `NotSupportedException`. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Streaming creation: each input's length settles the layout, then its bytes are copied into the block it was allocated. Nothing larger than one copy buffer is resident, so an entry past what a byte[] can hold is placed like any other. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware APFS defragmentor via read-extract-rebuild dispatch through `DefragRebuilder`. All four `DefragMode` values supported. The writer always emits a fresh contiguous-from-start image with valid Fletcher-64 checksums and a populated FS-tree B-tree. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Each file occupies one extent starting at its first block; everything ahead of the lowest of them is container and volume structure. Blocks no live extent covers are what a removal left behind. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes named entries from the volume in place. Records for each removed entry (DIR_REC, INODE, FILE_EXTENT) are deleted from the FS-tree, the tree is rebuilt, the file's data blocks are zeroed (no forensic recovery), per-block Fletcher-64 is recomputed, and the transaction id advanced. Same full-scope support as `Add`: arbitrary depth, splits, multi-component paths. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | | - -#### `ApfsReader` - -Reads Apple File System (APFS) images per Apple's "Apple File System Reference" (public spec). Walks the NXSB → container OMAP → APSB → volume OMAP → filesystem B-tree chain and extracts file data via `FILE_EXTENT` records. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApfsReader` | `ApfsReader(Stream stream, bool leaveOpen = false)` | | -| `BlockSize` | `uint BlockSize { get; }` | Container block size from the superblock. | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `ExtractTo` | `void ExtractTo(ApfsEntry entry, Stream destination)` | Copies an entry's bytes into `destination` a block at a time. An APFS file may be far larger than the byte[] `Extract` returns could hold. | -| `Extract` | `byte[] Extract(ApfsEntry entry)` | Extracts the raw data of a file entry by resolving its file-extent record's physical block number. | - -#### `ApfsStructuralValidator` - -Paranoid internal structural validator for APFS images. Because there is no `fsck_apfs` on Windows or Linux that we can rely on (Apple's tool is macOS-only; `apfs-fuse` only ships read code; libfsapfs is read-only), this validator is the real acceptance gate for in-place mutations. It walks every B-tree (container OMAP, volume OMAP, FS-tree), re-verifies every block's Fletcher-64, checks key ordering inside every node, cross-references OMAP entries against actual on-disk blocks, and checks the FS-tree integrity invariants: every `DIR_REC`'s child object id resolves to an `INODE` record;every non-root `INODE` has at least one `DIR_REC` naming it;every `FILE_EXTENT` belongs to an existing inode and points at a real block. xid monotonicity: every block touched by the mutator must carry an `o_xid` that is less than or equal to the container's `nx_next_xid`, with the checkpoint header carrying the highest xid. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Validate` | `static Report Validate(byte[] image)` | Walks an APFS image and returns a structural validation report. | - -#### `ApfsStructuralValidator.Report` - -The outcome of validating an APFS image — empty `Errors` means OK. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Report` | `Report()` | | -| `BlocksChecksumChecked` | `int BlocksChecksumChecked { get; set; }` | | -| `BtreeNodesVisited` | `int BtreeNodesVisited { get; set; }` | | -| `ContainerNextXid` | `ulong ContainerNextXid { get; set; }` | | -| `Errors` | `List Errors { get; }` | | -| `FsRecordsScanned` | `int FsRecordsScanned { get; set; }` | | -| `IsValid` | `bool IsValid { get; }` | | -| `MaxXidSeen` | `ulong MaxXidSeen { get; set; }` | | -| `Warnings` | `List Warnings { get; }` | | -| `ToString` | `override string ToString()` | | - -#### `ApfsWriter` - -Creates minimal Apple File System (APFS) container images per Apple's "Apple File System Reference" (public spec). The writer emits real `NXSB` and `APSB` superblocks, container and volume object maps, and a populated file-system B-tree containing inode, directory-record and file-extent records. All objects carry valid Fletcher-64 checksums per the spec. The FS B-tree grows automatically: when the inode / directory-record / file-extent records overflow a single node, they spill into several leaf nodes beneath an internal index node (a 2-level tree), so directories with many entries round-trip correctly. The tree depth is capped at two levels — the internal root holds one separator per leaf, which bounds the volume at a few hundred thousand small files (ample for image creation); a deeper tree is not emitted. Scope cuts: single container / single volume / single checkpoint / FS B-tree limited to two levels (root + leaves) / no snapshots / no encryption / no clones / no inline compression / no reaper / no spaceman (the allocation file is unused in a read-only writer context — macOS would require it for mount, but `fsck_apfs` structural validation of the superblocks and B-trees still passes). - -| Member | Signature | Summary | -| --- | --- | --- | -| `ApfsWriter` | `ApfsWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to be included in the volume image. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a file whose bytes are produced on demand. `size` must match what `openStream` yields; the layout is settled from it before a single byte is read, so a file larger than a byte[] can carry is placed like any other. | -| `BuildTo` | `void BuildTo(Stream output)` | Writes the volume to `output`: the metadata prefix, then the declared length, then each file's bytes at its allocated offset. Free space costs nothing, so a volume past the in-memory limit is producible. | -| `Build` | `byte[] Build()` | Builds and returns the complete APFS image. | -| `SetMinImageSize` | `void SetMinImageSize(long bytes)` | Overrides the minimum image size (default 512 MB = `MIN_APFS_IMAGE_SIZE`). Useful for tests that need smaller round-trip images. | -| `SetVolumeName` | `void SetVolumeName(string name)` | Sets the APFS volume name written to the APSB `apfs_volname` field (offset 968, 256-byte NUL-terminated UTF-8). Defaults to `CWB_Volume`. | - -### Namespace `FileSystem.AppleDos` - -[`AppleDosBlockMover`](#appledosblockmover) · [`AppleDosEntry`](#appledosentry) · [`AppleDosExtentMap`](#appledosextentmap) · [`AppleDosFormatDescriptor`](#appledosformatdescriptor) · [`AppleDosModifier`](#appledosmodifier) · [`AppleDosReader`](#appledosreader) · [`AppleDosWriter`](#appledoswriter) - -#### `AppleDosBlockMover` - -In-place Apple DOS 3.3 block mover. Moves sector-aligned extents within a .dsk image and patches the T/S list sector pointers + VTOC bitmap so the file remains reachable at its new location. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDosBlockMover` | `AppleDosBlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `AppleDosEntry` - -Directory entry in an Apple DOS 3.3 disk image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDosEntry` | `AppleDosEntry()` | | -| `FileType` | `byte FileType { get; init; }` | DOS 3.3 file type nibble. Low 7 bits: 0=T(ext), 1=I(nteger BASIC), 2=A(pplesoft BASIC), 4=B(inary), 8=S, 0x10=R, 0x20=AA, 0x40=BB. High bit = locked. | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `SectorCount` | `int SectorCount { get; init; }` | Sector count stored in the catalog (total sectors including T/S list). | -| `Size` | `long Size { get; init; }` | | - -#### `AppleDosExtentMap` - -Walks an Apple DOS 3.3 image (143,360 bytes, 35 tracks × 16 sectors, 256-byte sectors) and yields its actual on-disk byte layout — track 17 VTOC + catalog as metadata, every per-file (T/S list + data) sector chain as contiguous-run extents, and unallocated sectors as Free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `AppleDosFormatDescriptor` - -References: "Beneath Apple DOS" (Don Worth & Pieter Lechner, Quality Software, 1981) — the canonical DOS 3.3 on-disk reference (VTOC, catalog, track/sector lists)`https://github.com/fadden/CiderPress2` — CiderPress II, maintained implementation covering DOS 3.3 disk images`https://en.wikipedia.org/wiki/Apple_DOS` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDosFormatDescriptor` | `AppleDosFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | The Apple DOS 3.3 format has exactly one canonical image size. | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for Apple DOS 3.3 creation. The format has exactly one canonical geometry (35 tracks × 16 sectors × 256 bytes) and no concept of a volume name, so the only meaningful knob is the VTOC's disk volume number — used by DOS to disambiguate disks in a multi-volume session. Valid range 1..254 (0 = unset; 255 reserved). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing AppleDos image. Uses `AppleDosModifier` for true O(touched bytes) random-access I/O — only the VTOC, the catalog chain, and the file's data + T/S list sectors are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware Apple DOS 3.3 defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the VTOC + catalog (track 17) and per-file T/S list chains, yielding the actual on-disk byte layout. Track 17 becomes metadata; every file's T/S list + data sectors collapse into contiguous-run extents; un-attributed sectors are emitted as Free. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing AppleDos image. Uses `AppleDosModifier` for O(touched bytes) random-access I/O. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in an Apple DOS 3.3 image: every 256-byte sector not claimed by the VTOC/catalog (track 17) or by a live file's track/sector list and data sectors. Driven by the generic `UnusedSpaceWiper` over the AppleDOS extent map. Per-file cluster-tip wiping is not applied: an AppleDOS file's extent is a coalesced run that interleaves its track/sector-list sectors with the data sectors, so the file's logical bytes are not a flat `offset..offset+size` region. Treating the run's tail as slack would clobber a T/S-list sector or a neighbouring file, so tip wiping is N/A here; only genuinely free sectors are zeroed. | - -#### `AppleDosModifier` - -Random-access in-place modifier for Apple DOS 3.3 disk images. Reads and writes only the VTOC, the catalog chain, the new file's T/S list, and the new file's data sectors — never the whole image. Lets the host operate on huge underlying streams without paging the entire disk into memory. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte fileType = 4)` | Adds a file to an existing image. Caller is responsible for ensuring the name does not already exist (use `RemoveFile` first for replace-by-name semantics). | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file from the image. Returns true if found and removed. When `wipeData` is true, data sectors are zeroed. | - -#### `AppleDosReader` - -Reader for Apple DOS 3.3 `.dsk`/`.do` disk images. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDosReader` | `AppleDosReader(Stream stream)` | | -| `AppleDosReader` | `AppleDosReader(byte[] data)` | | -| `CatalogTrack` | `const int CatalogTrack` | | -| `SectorSize` | `const int SectorSize` | | -| `SectorsPerTrack` | `const int SectorsPerTrack` | | -| `StandardSize` | `const int StandardSize` | | -| `TracksPerDisk` | `const int TracksPerDisk` | | -| `VtocSector` | `const int VtocSector` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(AppleDosEntry entry)` | | - -#### `AppleDosWriter` - -Builds a fresh Apple DOS 3.3 `.dsk` / `.do` disk image (143 360 bytes) from scratch (Write-Once, Read-Many). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AppleDosWriter` | `AppleDosWriter()` | | -| `VolumeNumber` | `byte VolumeNumber { get; set; }` | VTOC disk-volume number (byte at VTOC offset 0x06). DOS 3.3 uses 254 by default; ProDOS-style images sometimes use 1..254 to disambiguate disks in a multi-volume set. Range 0..254; 0xFF is reserved. | -| `AddFile` | `void AddFile(string name, byte fileType, byte[] data)` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the disk image (default type = Binary 'B'). | -| `BuildFrom` | `static byte[] BuildFrom(IEnumerable> files)` | Escape hatch for callers that prefer to operate on an already-prepared List/Stream. | -| `Build` | `byte[] Build()` | Builds the complete 143 360-byte image. | - -### Namespace `FileSystem.Atari8` - -[`Atari8BlockMover`](#atari8blockmover) · [`Atari8Entry`](#atari8entry) · [`Atari8ExtentMap`](#atari8extentmap) · [`Atari8FormatDescriptor`](#atari8formatdescriptor) · [`Atari8Modifier`](#atari8modifier) · [`Atari8Reader`](#atari8reader) · [`Atari8Writer`](#atari8writer) - -#### `Atari8BlockMover` - -In-place Atari 8-bit block mover. Moves sector-aligned extents within an ATR image and patches the chain trailer bytes (file#/next-sector pointers in each sector's last 3 bytes) + VTOC bitmap so the file remains reachable at its new location. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Atari8BlockMover` | `Atari8BlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `Atari8Entry` - -Directory entry in an Atari 8-bit AtariDOS 2.x `.atr` disk image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Atari8Entry` | `Atari8Entry()` | | -| `Flags` | `byte Flags { get; init; }` | AtariDOS flags byte: bit 7=deleted, bit 6=in-use, bit 5=locked, bit 1=DOS-2 file, bit 0=open for write. | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `SectorCount` | `int SectorCount { get; init; }` | Sector count stored in the directory slot. | -| `Size` | `long Size { get; init; }` | | -| `StartSector` | `int StartSector { get; init; }` | First sector of the file's chain. | - -#### `Atari8ExtentMap` - -Walks an Atari 8-bit ATR image (AtariDOS 2.x) and yields the actual on-disk byte layout — 16-byte ATR header + sector 360 (VTOC) + sectors 361-368 (directory) as metadata, every per-file sector chain as one or more contiguous-run extents (chain followed via the 3-byte trailer), and the un-attributed sectors as Free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `Atari8FormatDescriptor` - -References: `https://www.atarimax.com/jindroush.atari.org/afmtatr.html` — ATR file format description (Jindroush archive); the header layout defined by Nick Kennedy's SIO2PCAtari DOS 2.0S/2.5 Reference Manual (Atari, Inc.) — VTOC + directory sector layout on the SS/SD 720-sector disk`https://en.wikipedia.org/wiki/Atari_DOS` — Wikipedia overview of the Atari 8-bit DOS family - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Atari8FormatDescriptor` | `Atari8FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | Canonical ATR sizes: SS/SD (92 176) is the one this WORM writer emits. | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for ATR creation. AtariDOS 2.x has no concept of a volume label and this writer emits only SS/SD geometry (720 × 128 = 92 160 bytes of data plus a 16-byte ATR header), so the only meaningful knob is the ATR header's write-protect flag at offset 15. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Atari8 image. Uses `Atari8Modifier` for true O(touched bytes) random-access I/O — only the VTOC, the touched directory sector, and the file's data sectors are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware AtariDOS defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the ATR header + VTOC + directory + per-file sector chains and yields the actual on-disk byte layout. Header / VTOC / directory sectors become `MetadataReserved`, file chains coalesce into contiguous-run extents, and un-attributed sectors are emitted as Free. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing Atari8 image. Uses `Atari8Modifier` for O(touched bytes) random-access I/O. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in an Atari 8-bit ATR (AtariDOS 2) image: the ATR header is preserved, and every sector not claimed by the VTOC, the directory, or a live file's sector chain is zeroed. Driven by the generic `UnusedSpaceWiper` over the Atari8 extent map. Per-file cluster-tip wiping is not applied: AtariDOS stores a 3-byte link trailer (file number, next sector, byte count) at the end of every data sector, so each sector mixes data with metadata and the file's logical bytes are not a flat `offset..offset+size` region. Treating a run's tail as slack would clobber a sector's link bytes, so tip wiping is N/A here; only genuinely free sectors are zeroed. | - -#### `Atari8Modifier` - -Random-access in-place modifier for Atari 8-bit `.atr` images (AtariDOS 2.x layout). Reads and writes only the ATR header, the VTOC (sector 360), the touched directory sector(s), and the file's data sectors — never the whole image. Supports SS/SD (128-byte) and DD (256-byte) images. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds a file to an existing image. Caller is responsible for ensuring the name does not already exist (use `RemoveFile` first for replace-by-name semantics). | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file from the image. Returns true if found and removed. When `wipeData` is true, data sectors are zeroed. | - -#### `Atari8Reader` - -Reader for Atari 8-bit AtariDOS 2.x `.atr` disk images. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Atari8Reader` | `Atari8Reader(Stream stream)` | | -| `Atari8Reader` | `Atari8Reader(byte[] data)` | | -| `AtrHeaderSize` | `const int AtrHeaderSize` | | -| `DefaultSectorSize` | `const int DefaultSectorSize` | | -| `DirectoryEntrySize` | `const int DirectoryEntrySize` | | -| `DirectorySectorCount` | `const int DirectorySectorCount` | | -| `DirectoryStartSector` | `const int DirectoryStartSector` | | -| `EntriesPerDirectorySector` | `const int EntriesPerDirectorySector` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `SectorSize` | `int SectorSize { get; }` | Sector size read from the ATR header (128 or 256). | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(Atari8Entry entry)` | | - -#### `Atari8Writer` - -Builds a fresh Atari 8-bit AtariDOS 2.x `.atr` disk image from scratch (WORM). - -| Member | Signature | Summary | -| --- | --- | --- | -| `Atari8Writer` | `Atari8Writer()` | | -| `ImageSize` | `const int ImageSize` | | -| `WriteProtected` | `bool WriteProtected { get; set; }` | When true, the ATR header's flags byte at offset 15 is set to 0x01, marking the disk image as write-protected. Compatible emulators (Atari800, Altirra, etc.) honour the flag and refuse writes through SIO patches. | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `Build` | `byte[] Build()` | Builds the complete SS/SD ATR image (92 176 bytes). | - -### Namespace `FileSystem.Bbc` - -[`BbcBlockMover`](#bbcblockmover) · [`BbcEntry`](#bbcentry) · [`BbcExtentMap`](#bbcextentmap) · [`BbcFormatDescriptor`](#bbcformatdescriptor) · [`BbcModifier`](#bbcmodifier) · [`BbcReader`](#bbcreader) · [`BbcWriter`](#bbcwriter) - -#### `BbcBlockMover` - -In-place BBC Micro DFS block mover. Moves sector-aligned extents within an SSD image and patches the catalog entry's start-sector field. BBC DFS files are contiguous, so a move simply updates the start-sector in the two-sector catalog (sectors 0 and 1). - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BbcBlockMover` | `BbcBlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `BbcEntry` - -Entry in a BBC Micro Acorn DFS catalog. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BbcEntry` | `BbcEntry()` | | -| `Directory` | `char Directory { get; init; }` | | -| `ExecAddress` | `uint ExecAddress { get; init; }` | | -| `FullName` | `string FullName { get; init; }` | "$.FILENAME" or "X.FILENAME" form where X is the DFS directory prefix. | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `IsLocked` | `bool IsLocked { get; init; }` | | -| `LoadAddress` | `uint LoadAddress { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `BbcExtentMap` - -Walks a BBC Micro Acorn DFS image (.ssd / .dsd, 256-byte sectors, 10 sectors/track) and yields its actual on-disk byte layout — sectors 0+1 of each side as the catalog (metadata), every per-file (start_sector, length) extent as a single contiguous run, and the unallocated sectors as Free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `BbcFormatDescriptor` - -References: `https://beebwiki.mdfs.net/Acorn_DFS_disc_format` — BeebWiki's Acorn DFS disc format page, the de-facto on-disk reference (catalog sectors, boot option)Acorn "Disc Filing System User Guide" (Acorn Computers) — original vendor documentation`https://en.wikipedia.org/wiki/Disc_Filing_System` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BbcFormatDescriptor` | `BbcFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | Canonical BBC DFS image sizes: 40-track SSD (102 400) and 80-track SSD (204 800). | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for BBC DFS creation. DFS stores a 12-character disk title across the two catalog sectors, plus a 2-bit "boot option" that controls what SHIFT-BREAK does. Disk geometry is fixed at 40-track SSD (100 KB). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Bbc image. Uses `BbcModifier` for true O(touched bytes) random-access I/O — only the two catalog sectors and the file's contiguous data run are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware BBC DFS defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. The source DFS directory prefix and load/exec/locked metadata are preserved per file. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the catalog (sectors 0-1 per side) and yields the actual on-disk byte layout — catalog sectors as `MetadataReserved`, every file as a single contiguous run starting at its `(start_sector, length)`, and unallocated sectors as Free. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing Bbc image. Uses `BbcModifier` for O(touched bytes) random-access I/O. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in a BBC DFS image: every sector not claimed by a live file, plus the cluster-tip slack — the bytes between a file's logical length and the end of its last (256-byte) sector. DFS stores each file as a single contiguous sector run starting at the catalog's start-sector, so the generic `UnusedSpaceWiper` driven by the DFS extent map plus a catalog-entry file-size lookup wipes tips precisely. | - -#### `BbcModifier` - -Random-access in-place modifier for BBC Micro Acorn DFS `.ssd` images. The DFS catalog is just two sectors (512 bytes total); only the catalog plus the file's contiguous data run are read or written. Files land in the lowest free contiguous gap above the catalog, leaving the rest of the disk untouched. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, char directory = '$', uint loadAddr = 6400, uint execAddr = 6400, bool locked = false)` | Adds a file to an existing single-sided DFS image. Caller is responsible for ensuring the name does not already exist (use `RemoveFile` first for replace-by-name semantics). The file is placed in the lowest contiguous gap large enough to hold it. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file from the image. Returns true if found and removed. When `wipeData` is true, the data sectors are zeroed. | - -#### `BbcReader` - -Reader for BBC Micro Acorn DFS `.ssd` (single-sided) and `.dsd` (double-sided interleaved) disk images. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BbcReader` | `BbcReader(Stream stream, bool doubleSided = false)` | | -| `MaxEntries` | `const int MaxEntries` | | -| `SectorSize` | `const int SectorSize` | | -| `SectorsPerTrack` | `const int SectorsPerTrack` | | -| `Ssd40TrackSize` | `const int Ssd40TrackSize` | | -| `Ssd80TrackSize` | `const int Ssd80TrackSize` | | -| `DiskTitle` | `string DiskTitle { get; }` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(BbcEntry entry)` | | - -#### `BbcWriter` - -Builds a fresh BBC Micro Acorn DFS `.ssd` single-sided disk image from scratch (WORM). - -| Member | Signature | Summary | -| --- | --- | --- | -| `BbcWriter` | `BbcWriter()` | | -| `DefaultTracks` | `const int DefaultTracks` | | -| `DiskSize40` | `const int DiskSize40` | | -| `MaxEntries` | `const int MaxEntries` | | -| `SectorSize` | `const int SectorSize` | | -| `SectorsPerTrack` | `const int SectorsPerTrack` | | -| `TotalSectors40` | `const int TotalSectors40` | | -| `AddFile` | `void AddFile(string name, byte[] data, char directory = '$', uint loadAddr = 6400, uint execAddr = 6400, bool locked = false)` | | -| `Build` | `byte[] Build(string diskTitle = "WORMDISK", int bootOption = 0)` | Builds the complete 40-track SSD image (100 000 bytes). | - -### Namespace `FileSystem.BcacheFs` - -[`BcacheFsBlockMover`](#bcachefsblockmover) · [`BcacheFsFormatDescriptor`](#bcachefsformatdescriptor) · [`BcacheFsReader`](#bcachefsreader) · [`BcacheFsReader.Entry`](#bcachefsreaderentry) · [`BcacheFsReader.Extent`](#bcachefsreaderextent) · [`BcacheFsWriter`](#bcachefswriter) - -#### `BcacheFsBlockMover` - -Moves a file's bytes inside a bcachefs volume and rewrites the extent keys that name them. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcacheFsBlockMover` | `BcacheFsBlockMover()` | | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | | -| `BlockSize` | `int BlockSize { get; }` | The unit a layout may place a run at: a whole bucket. | -| `FirstDataByte` | `long FirstDataByte { get; }` | The first byte a file's bytes may occupy. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | | -| `DescribeAllocationDiscrepancies` | `IReadOnlyList DescribeAllocationDiscrepancies(Stream image)` | Where the volume's two accounts of the same facts disagree, in words. | -| `Init` | `void Init(Stream image)` | Reads the extents b-tree so its pointers can be found again. | -| `MoveExtent` | `void MoveExtent(Stream image, long sourceOffset, long destinationOffset, long length, bool zeroSource = false)` | | -| `SettleAllocation` | `void SettleAllocation(Stream image)` | Rewrites the trees that say which buckets hold data, now that the data is in different buckets. | -| `Settle` | `void Settle(Stream image)` | Writes every pointer back and re-stamps the node that holds them. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long sourceOffset, long destinationOffset, long length)` | | - -#### `BcacheFsFormatDescriptor` - -Full workbench descriptor for the single-device bcachefs profile implemented here: native b-trees, true in-place CRUD, allocation/accounting maintenance, in-place defragmentation, purge and unused-space wiping. - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcacheFsFormatDescriptor` | `BcacheFsFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | True in-place add/replace. Unchanged file extents are not copied or relocated; new bytes go to free buckets and only bcachefs metadata is committed afterwards. | -| `AnalyzeLayout` | `LayoutAnalysis AnalyzeLayout(Stream image)` | bcachefs' allocation unit is fixed for this profile, so optimize means choosing a better extent placement; there is no fictional smaller bucket size to propose. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Runs the bcachefs-specific offline relocation engine. It operates from the physical bucket map, may COW-relocate metadata according to the requested metadata zone/interleave policy, then moves data around the resulting live metadata barriers and republishes allocation metadata from the final map. There is no extract/re-create fallback. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | | -| `PatchInPlace` | `void PatchInPlace(Stream image, LayoutPatch patch)` | | -| `RebuildStreaming` | `void RebuildStreaming(Stream source, Stream target, LayoutRebuildOptions options)` | Structural optimize contract. When source and target are the same stream the operation is genuinely in-place. A distinct target necessarily receives one copy first, then the exact same in-place optimizer runs on that target. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | True in-place remove/purge. Metadata keys are removed in the metadata zone and the old user extents are overwritten with zeroes after the new roots are live. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | Rebuilds the volume tightly around its content. The generic default writes the derived entries back as ordinary files, so the rebuilt volume lists more than the original did and the round-trip guard refuses it — leaving an oversized image at its original size. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Wipe/clean support: zero every unused byte plus optional final-extent slack, while preserving every live file and the image size. | - -#### `BcacheFsReader` - -Reads the files a bcachefs volume holds. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcacheFsReader` | `BcacheFsReader(Stream stream, bool leaveOpen = true)` | | -| `Directories` | `IReadOnlyList Directories { get; }` | Directories the volume holds, by full path. | -| `Entries` | `IReadOnlyList Entries { get; }` | Every file the volume holds, by full path. | -| `Label` | `string Label { get; }` | The label the superblock carries. | -| `Length` | `long Length { get; }` | The volume's length in bytes. | -| `Status` | `string Status { get; }` | Why the volume did not read, when it did not. | -| `Valid` | `bool Valid { get; }` | True when the volume's superblock and b-tree roots read as they should. | -| `Dispose` | `void Dispose()` | | -| `ExtractTo` | `void ExtractTo(Entry entry, Stream output)` | Writes one file's bytes to `output`. | -| `Read` | `byte[] Read(Entry entry)` | The whole of one file. | - -#### `BcacheFsReader.Entry` - -One file: its path, its length, and where its bytes are. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entry` | `Entry(string Name, long Size, ulong Inode, IReadOnlyList Extents)` | One file: its path, its length, and where its bytes are. | -| `Extents` | `IReadOnlyList Extents { get; init; }` | | -| `FirstSector` | `long FirstSector { get; }` | Where the file's first byte is, or zero when it holds none. | -| `Inode` | `ulong Inode { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `BcacheFsReader.Extent` - -One run of sectors belonging to a file. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Extent` | `Extent(long FirstSector, int Sectors, long FileOffset)` | One run of sectors belonging to a file. | -| `FileOffset` | `long FileOffset { get; init; }` | Which byte of the file it begins at. | -| `FirstSector` | `long FirstSector { get; init; }` | Where it starts on the device. | -| `Sectors` | `int Sectors { get; init; }` | How long it is. | - -#### `BcacheFsWriter` - -Writes a bcachefs volume: a superblock, the b-trees that describe the files, and the files themselves. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BcacheFsWriter` | `BcacheFsWriter()` | | -| `BcachefsMagic` | `static readonly byte[] BcachefsMagic` | BCHFS_MAGIC, in storage byte order. | -| `MinImageSize` | `const long MinImageSize` | Smallest volume this writes. A bcachefs device needs at least 512 buckets, and the two superblock slots at the front already claim thirty-three of them. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file, held in memory. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a file whose bytes are read as the volume is written. | -| `EstimateSize` | `static long EstimateSize(IEnumerable fileSizes)` | The smallest volume that holds `fileSizes`: the superblock slots, the journal, one bucket per b-tree, the file data, and the slot at the tail. | -| `SetImageSize` | `void SetImageSize(long bytes)` | Sets the total volume size in bytes. | -| `SetInternalUuid` | `void SetInternalUuid(Guid uuid)` | Overrides the internal UUID, which is also what the metadata magic is derived from. | -| `SetLabel` | `void SetLabel(string label)` | Sets the volume label; it is truncated into the superblock's 32-byte field. | -| `SetUserUuid` | `void SetUserUuid(Guid uuid)` | Overrides the user-facing UUID. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the volume. | - -### Namespace `FileSystem.Bfs` - -[`BfsBlockMover`](#bfsblockmover) · [`BfsFormatDescriptor`](#bfsformatdescriptor) - -#### `BfsBlockMover` - -Moves a file's block runs inside a BFS volume, repoints the run in its inode, and moves the allocation with it. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BfsBlockMover` | `BfsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Block size in bytes, as the superblock records it. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the superblock, the log and the bitmap. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the run it is given and nothing else, so an owner scattered over several runs is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads the geometry and finds the allocation bitmap. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `BfsFormatDescriptor` - -R/W descriptor for BeOS / Haiku BFS filesystem images. Can list, extract, create (WORM), modify (via rebuild), and defragment BFS images. The writer produces a minimal single-AG image with a single B+ tree leaf for the root directory and direct block_run extents for file data. References: "Practical File System Design with the Be File System" (Dominic Giampaolo, Morgan Kaufmann, 1999) — the canonical BFS on-disk reference by its author`https://github.com/haiku/haiku/tree/master/src/add-ons/kernel/file_systems/bfs` — Haiku's maintained BFS implementation`https://en.wikipedia.org/wiki/Be_File_System` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BfsFormatDescriptor` | `BfsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation: the pre-known per-input sizes drive the BFS block allocation + inode + B+ tree layout in pass 1 (identical to `Create`); pass 2 streams each file's bytes from its `OpenStream` factory into its contiguous data-block run via 64 KB chunks — no file is ever buffered as a `byte[]`. Output is byte-identical to `Create` for the same inputs. Falls back to a buffered build when the target stream is not seekable. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in a BFS image: every block not claimed by a live inode, B+ tree node, journal, bitmap or file data run — and the cluster-tip slack inside the last data block of each file. The BFS extent map emits a file's data run clamped to its logical size, so the trailing bytes of its final allocated block fall outside any live extent and are zeroed by the generic `UnusedSpaceWiper` as free space; the file-size lookup covers any reader that reports a block-aligned extent. | - -### Namespace `FileSystem.Btrfs` - -[`BtrfsBlockMover`](#btrfsblockmover) · [`BtrfsEntry`](#btrfsentry) · [`BtrfsExtentMap`](#btrfsextentmap) · [`BtrfsFormatDescriptor`](#btrfsformatdescriptor) · [`BtrfsInPlaceAdder`](#btrfsinplaceadder) · [`BtrfsModifier`](#btrfsmodifier) · [`BtrfsReader`](#btrfsreader) · [`BtrfsWriter`](#btrfswriter) - -#### `BtrfsBlockMover` - -In-place Btrfs block mover for the WORM writer profile. Moves data extents within a Btrfs image and patches the fs-tree leaf's `EXTENT_DATA` item (`disk_bytenr`) so the file remains reachable at its new location, then recomputes the CRC-32C checksum on every metadata block that was modified. The bundled `BtrfsWriter` uses identity logical→physical mapping (logical == physical for all chunks), so only the fs-tree leaf needs patching — no chunk-tree updates are required.Inline extents (type 0) cannot be moved because their data lives inside the metadata leaf itself. The extent map surfaces them as `MetadataReserved`, and the planner never schedules them for moves.Streaming: the image is never loaded whole. `Init` reads only the 4 KiB superblock to cache `nodeSize`, the boot `sys_chunk_array` map, and the logical addresses of the chunk + root trees. `UpdateAllocationAfterMove` walks the chunk tree, root tree, and fs-tree leaf via a `SectorCache` and writes back only the patched fs-tree leaf (one node-sized write). A 50 TB image needs a few MB of cache, not 50 TB of RAM. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BtrfsBlockMover` | `BtrfsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Streaming initialiser. Reads only the 4 KiB superblock and parses the `sys_chunk_array` for the boot chunk map. Subsequent moves walk the rest of the chunk tree through a `SectorCache` on demand. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file's extent may occupy: past the superblock and the trees the writer lays down in front of the data chunk. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the item naming the extent it is given and leaves the leaf's other items alone, so a file in several extents is several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | An extent may be held outside the image while the rest of the layout moves, which is what lets a full image be rearranged at all. | -| `Init` | `void Init(Stream image)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `SettleExtentTree` | `void SettleExtentTree(Stream image)` | Brings the extent tree along with the extents it accounts for. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `BtrfsEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `BtrfsEntry` | `BtrfsEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `BtrfsExtentMap` - -Walks a Btrfs image (single-device, non-RAID) and yields its actual on-disk byte layout. Targets the WORM-minimal writer profile: a single fs-tree leaf with INODE_ITEM + DIR_INDEX + (mostly inline) EXTENT_DATA items per file, plus a populated chunk tree for logical→physical translation. Inline extents surface as MetadataReserved (they live inside the metadata leaf); regular extents surface as Used runs. Streaming: reads go through a `SectorCache` so a 50 TB Btrfs image needs only a few MB of working set, not 50 TB of RAM. Only the 4 KiB superblock + a handful of node-sized reads (chunk tree, root tree, fs-tree leaf) actually hit the disk. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | Single-pass walker. Parses the superblock at 0x10000, the `sys_chunk_array` for the boot chunk map, the chunk tree to extend it, the root tree to find the FS tree, and finally the FS tree leaves to emit per-file EXTENT_DATA runs. Reads flow through a `SectorCache` — the image is never loaded whole. | - -#### `BtrfsFormatDescriptor` - -References: `https://btrfs.readthedocs.io/en/latest/dev/On-disk-format.html` — official btrfs on-disk format documentation (superblock, chunk/root/fs trees)`https://github.com/torvalds/linux/tree/master/fs/btrfs` — mainline kernel implementation`https://en.wikipedia.org/wiki/Btrfs` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BtrfsFormatDescriptor` | `BtrfsFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | Btrfs copy-on-write filesystem image. The writer emits a populated `sys_chunk_array` inside the superblock and a real chunk tree with three chunks (`SYSTEM`, `METADATA`, `DATA`) that map every logical range used by the image to its physical offset, a dev tree with a `DEV_ITEM` for the single device, a root tree, and an FS tree leaf with inode + dir-index + inline `EXTENT_DATA` items per file. All metadata blocks carry CRC-32C (Castagnoli) at the start. | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Add/replace via `AddOrReplace`. Small inline files targeting the root directory are inserted with genuine copy-on-write in place (new FS/extent/root tree blocks for the changed path only; existing data extents and untouched nodes stay byte-identical at their offsets; the result passes `btrfs check`). Unhandled shapes fall back to the verified rebuild. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation. Pass 1 plans the chunk/extent/inode layout from each input's pre-known size; pass 2 emits all metadata (with CRC-32C) plus inline file data, then streams each regular (non-inline) file's bytes into its DATA-chunk extent via 64 KB chunks — file bytes never travel through a writer-held `byte[]`. Btrfs data extents carry no checksum (the inode is NODATASUM and the CSUM_TREE is empty), so post-filling the extent bytes after the metadata CRCs are stamped is sound and the output is byte-identical to `Create` for the same inputs. Files smaller than one sector are stored inline in the FS-tree leaf, so their (bounded) bytes are read up front and treated like a classic `AddFile`. Non-seekable targets fall back to the buffering base implementation. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the superblock + chunk tree + root tree + fs-tree leaf and yields the actual on-disk byte layout. Targets the WORM writer profile (single fs-tree leaf, mostly inline EXTENT_DATA): inline extents surface as MetadataReserved tiles (file content lives inside the metadata leaf), regular extents surface as Used runs after logical→physical translation through the chunk map. Multi-leaf b-trees are not walked here — the WORM writer doesn't produce them. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Rebuild-style remove (see `BtrfsModifier`). The removed file's data does not survive into the rebuilt image because the new writer emits a fresh superblock, chunk tree, and fs-tree leaf. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | | - -#### `BtrfsInPlaceAdder` - -Genuine copy-on-write in-place add for Btrfs images produced by `BtrfsWriter` — the spec-faithful alternative to the whole-image rebuild in `BtrfsModifier`. A file is added (or replaced) by writing NEW (CoW) tree blocks only for the path that changed and leaving every untouched node and every existing data extent byte-identical at its original offset. The full add pipeline: The FS, extent, csum and root trees are each read into one flat, key-ordered item list with the generic arbitrary-depth descender — a single leaf, an internal node over leaves, or any deeper tree are all handled, and every block visited is recorded so the whole tree can be CoW-rebuilt.The target parent directory is resolved, creating any missing intermediate directory inodes (`INODE_ITEM`/`INODE_REF`/parent links) for nested targets.The new file's items are inserted. Files below one sector stay inline in the FS-tree leaf; files at/above one sector get a real data extent allocated from the DATA chunk's free space, the payload written there, a regular `EXTENT_DATA` item, a data `EXTENT_ITEM` (with inline `EXTENT_DATA_REF`) in the extent tree, and per-sector CRC-32C `EXTENT_CSUM` items in the csum tree.Each tree's flat item set is re-sorted and re-packed into leaves, then rebuilt as a B-tree of whatever height its leaf count demands: a single leaf stays level 0; otherwise internal index levels are stacked until one root node remains. The tree GROWS in height when its leaves overflow one internal node — the FS, extent and csum trees are all rebuilt this way.Every CoW'd metadata block (every leaf and internal node of the FS / extent / csum / root trees) is allocated — preferring genuinely-free node slots, then recycling the blocks this operation frees. The extent tree's own block count is found by a fixed-point that accounts for the TREE_BLOCK `EXTENT_ITEM` it must hold for every metadata block (its own included); block-group accounting and the superblock `bytes_used` are recomputed.The `FS_TREE` / `EXTENT_TREE` / `CSUM_TREE``ROOT_ITEM`s are repointed (with each tree's new root level) and the superblock `root` + `root_level` + `generation` bumped; CRC-32C is recomputed for every new block and the superblock. Verified against `btrfs check` (incl. `--check-data-csum`) for: inline and regular (data-extent) files, nested sub-directory targets, multi-leaf FS trees (internal root node), leaf splits, add-or-replace of existing inline/regular files, and a multi-level (internal-node-over-leaves) extent tree grown in place by adding many data-extent files. The tree-rebuild path is height-generic, so an FS / extent / csum / root tree of arbitrary depth is read and re-emitted; an FS tree that overflows one internal node is grown to the next height by the same code. Cases still throwing `NotSupportedException` for the rebuild fallback: non-default node/sector sizes, a full metadata or DATA chunk (no room to CoW the new blocks or place the new data extent). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream archive, string name, byte[] data)` | Adds (or replaces) a small file in the root directory of `archive` via copy-on-write. Throws `NotSupportedException` for any shape the in-place path does not handle so the caller can rebuild instead. | -| `AddFile` | `static void AddFile(byte[] image, string name, byte[] data)` | In-memory variant operating directly on the image bytes. | - -#### `BtrfsModifier` - -Modifier for Btrfs images produced by `BtrfsWriter`. `AddOrReplace` first attempts a genuine copy-on-write in-place add via `BtrfsInPlaceAdder`: it writes NEW (CoW) FS-tree / extent-tree / root-tree blocks for the changed path only, repoints the superblock, bumps the generation, and recomputes CRC-32C — leaving every untouched node and every existing data extent byte-identical at its offset (verified with `btrfs check`). That path covers adding/replacing inline (< one sector) and regular (data-extent) files, in the root or in nested sub-directories, across both single-leaf and multi-leaf (internal-node) FS trees — splitting leaves as needed and writing genuine per-sector CRC-32C csum-tree entries for regular extents. Cases the in-place adder does not handle — a multi-level root/extent/csum tree, an FS tree deeper than one internal node, a full metadata or DATA chunk, or non-default node/sector sizes — throw `NotSupportedException` and fall back to the verified "rebuild" strategy below: read all entries via `BtrfsReader`, apply the modifications in memory, and emit a fresh image over the old bytes via `BtrfsWriter`. `Remove` is always rebuild-based. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddOrReplace` | `static void AddOrReplace(Stream archive, IReadOnlyList> toAddOrReplace)` | Adds or replaces files in `archive`. Tries genuine in-place copy-on-write first (per file, in order); if any add hits an unhandled shape the whole batch falls back to a single rebuild that applies every change. Existing entries are preserved except those whose names are overridden by the new inputs. | -| `Remove` | `static void Remove(Stream archive, IReadOnlyCollection names)` | Rebuilds `archive` without the named entries. | - -#### `BtrfsReader` - -Reads Btrfs filesystem images (single-device, non-RAID). Parses superblock, builds chunk map (logical-to-physical translation), traverses B-trees to enumerate files and extract uncompressed extents. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BtrfsReader` | `BtrfsReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `UsedRealChunkTree` | `bool UsedRealChunkTree { get; }` | Diagnostic: indicates whether the chunk map used during reading was non-empty, i.e. this image carries a real chunk tree as opposed to relying on identity-mapping fallback for synthetic test data. | -| `Dispose` | `void Dispose()` | | -| `ExtractTo` | `void ExtractTo(BtrfsEntry entry, Stream destination)` | Writes `entry`'s bytes to `destination` without materialising them, truncating to the entry's recorded size. Required for a file larger than a byte[] can hold. | -| `Extract` | `byte[] Extract(BtrfsEntry entry)` | | - -#### `BtrfsWriter` - -Writes spec-compliant Btrfs filesystem images. Every image contains a populated `sys_chunk_array` inside the superblock, a real chunk tree with three `CHUNK_ITEM` entries (`SYSTEM`, `METADATA`, `DATA`) that map every logical range used by the image to its physical offset, a dev tree with one `DEV_ITEM` for the single device, a root tree pointing at the FS tree, and an FS tree leaf holding inode / directory-index / inline extent-data items for every added file. All metadata blocks carry the 4-byte little-endian CRC-32C (Castagnoli) at byte offset 0 per the on-disk spec. - -| Member | Signature | Summary | -| --- | --- | --- | -| `BtrfsWriter` | `BtrfsWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the image. The `name` may contain '/' (or '\\') separators; each path component becomes a real directory inode in the FS tree. File data becomes an inline `EXTENT_DATA` item in the FS tree leaf. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a streaming file: `size` drives extent + inode + chunk sizing in pass 1; the bytes are pulled from `openStream` in pass 2 of `BuildToStreaming`. A file whose size is below the inline threshold (`MaxInlineDataSize`) is stored inline inside the FS-tree leaf, so its (small, bounded) bytes are read up front here and treated exactly like an `AddFile` entry; only files at or above the threshold (regular data extents) are streamed and never buffered as a `byte[]` by the writer. | -| `BuildToStreaming` | `void BuildToStreaming(Stream output)` | Two-pass streaming variant of `WriteTo`: pass 1 builds the complete disk image byte[] exactly as `WriteTo` would (all metadata + CRC-32C + inline file data), but leaves the bytes of every regular (non-inline) data extent zero and records each extent's absolute image offset; pass 2 writes the image to `output` and then streams each recorded extent's bytes from its factory into place via 64 KB chunks. Data extents carry no Btrfs csum (the inode is NODATASUM and the CSUM_TREE is empty), so post-filling them does not invalidate any checksum. The produced bytes are identical to `WriteTo` for the same inputs. | -| `SetUuids` | `void SetUuids(Guid filesystem, Guid device)` | Fixes the volume and device identities, for a build that has to come out the same twice. | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileSystem.CbmNibble` - -[`CbmNibbleReader`](#cbmnibblereader) · [`CbmNibbleReader.ImageKind`](#cbmnibblereaderimagekind) · [`CbmNibbleReader.NibbleImage`](#cbmnibblereadernibbleimage) · [`CbmNibbleReader.Track`](#cbmnibblereadertrack) · [`CbmNibbleWriter`](#cbmnibblewriter) · [`G64FormatDescriptor`](#g64formatdescriptor) · [`NibFormatDescriptor`](#nibformatdescriptor) - -#### `CbmNibbleReader` - -Reader for Commodore 1541/1571 nibble dumps — both the raw .nib format (used by nibtools and ZoomFloppy) and the .g64 GCR track container produced by emulators like VICE. Converting GCR back to a cleanly sectored D64 is outside scope for this sweep; this reader detects the format variant and surfaces each track as a raw byte buffer for downstream tools to consume. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CbmNibbleReader` | `CbmNibbleReader()` | | -| `G64Signature` | `static readonly byte[] G64Signature` | | -| `NibExpectedFileSize` | `const int NibExpectedFileSize` | | -| `NibTrackCount` | `const int NibTrackCount` | | -| `NibTrackSize` | `const int NibTrackSize` | | -| `BuildMetadata` | `static byte[] BuildMetadata(NibbleImage img)` | | -| `Read` | `static NibbleImage Read(ReadOnlySpan data, string fileName = null)` | | - -#### `CbmNibbleReader.ImageKind` - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Nib` | `0` | | -| `G64` | `1` | | - -#### `CbmNibbleReader.NibbleImage` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NibbleImage` | `NibbleImage(ImageKind Kind, byte Version, int TrackCount, int MaxTrackSize, List Tracks, long TotalFileSize)` | | -| `Kind` | `ImageKind Kind { get; init; }` | | -| `MaxTrackSize` | `int MaxTrackSize { get; init; }` | | -| `TotalFileSize` | `long TotalFileSize { get; init; }` | | -| `TrackCount` | `int TrackCount { get; init; }` | | -| `Tracks` | `List Tracks { get; init; }` | | -| `Version` | `byte Version { get; init; }` | | - -#### `CbmNibbleReader.Track` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Track` | `Track(int Index, byte[] Data, uint SpeedZone)` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Index` | `int Index { get; init; }` | | -| `SpeedZone` | `uint SpeedZone { get; init; }` | | - -#### `CbmNibbleWriter` - -From-scratch writer for the Commodore nibble container the `CbmNibbleReader` consumes. The Commodore 1541 filesystem is flat — files live in the single directory on track 18 with a BAM — so the writer first builds a standard sectored D64 image (reusing `D64Writer` for the BAM, directory and linked sector chains) and then GCR-encodes every track into the VICE `.g64` wire format, framing each sector with sync marks, a header block and a data block exactly as a real 1541 lays them down on disk. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CbmNibbleWriter` | `CbmNibbleWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the flat directory. Commodore names are PETSCII and at most 16 characters; longer names are truncated. The default file type is PRG. | -| `Build` | `byte[] Build()` | Builds the G64 GCR nibble image holding all added files. | -| `DecodeToD64` | `static byte[] DecodeToD64(NibbleImage image)` | Reconstructs a standard 174 848-byte D64 image from the GCR tracks of a nibble image previously parsed by `CbmNibbleReader`. Each track is rescanned for sync marks and its header/data blocks GCR-decoded back into the correct sector slots. | -| `SetDisk` | `void SetDisk(string name, char id1 = '0', char id2 = '0')` | Sets the on-disk volume name (PETSCII, ≤16 chars) and the 2-byte disk id. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the G64 image to `output`. | - -#### `G64FormatDescriptor` - -Commodore G64 GCR track container (VICE emulator). Detected by the 8-byte "GCR-1541" ASCII magic at offset 0. References: `http://unusedino.de/ec64/technical/formats/g64.html` — Peter Schepers' G64 format specification`https://vice-emu.sourceforge.io` — VICE emulator, the origin and maintained implementation of G64 - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `G64FormatDescriptor` | `G64FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Builds a fresh G64 image from the inputs. The Commodore filesystem is flat, so names are reduced to their filename component and stored in the single track-18 directory by `CbmNibbleWriter`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -#### `NibFormatDescriptor` - -Commodore NIB raw nibble dump (nibtools / ZoomFloppy). No magic header — detected by file extension only; the typical dump is exactly 84 × 8192 bytes. References: nibtools (Pete Rittwage's C64 Disk Preservation Project) — the tool that defines and produces the de-facto NIB dump layout`http://unusedino.de/ec64/technical/formats/g64.html` — Peter Schepers' GCR track documentation (shared with G64) - -Implements `IArchiveFormatOperations`, `IFormatDescriptor`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `NibFormatDescriptor` | `NibFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | - -### Namespace `FileSystem.CpcDsk` - -[`CpcDskBlockMover`](#cpcdskblockmover) · [`CpcDskEntry`](#cpcdskentry) · [`CpcDskExtentMap`](#cpcdskextentmap) · [`CpcDskFormatDescriptor`](#cpcdskformatdescriptor) · [`CpcDskModifier`](#cpcdskmodifier) · [`CpcDskReader`](#cpcdskreader) · [`CpcDskWriter`](#cpcdskwriter) - -#### `CpcDskBlockMover` - -Says why an AMSDOS disk is laid out again rather than shuffled in place. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpcDskBlockMover` | `CpcDskBlockMover()` | | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | | -| `BlockSize` | `int BlockSize { get; }` | An allocation block: the unit any legal layout is expressed in. | -| `FirstDataByte` | `long FirstDataByte { get; }` | The first byte past the directory, which is where the files begin. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | | -| `Init` | `void Init(Stream image)` | Reads the geometry, and reports that the disk cannot be shuffled in place. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `CpcDskEntry` - -One file on an Amstrad CPC disk, as its AMSDOS directory entry describes it. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpcDskEntry` | `CpcDskEntry()` | | -| `Name` | `string Name { get; init; }` | The file's name, in CP/M's eight-and-three. | -| `SectorId` | `byte SectorId { get; init; }` | Id of the sector its first block starts at; DATA-format disks run from &C1. | -| `Side` | `int Side { get; init; }` | Side its first block starts on (0 or 1). | -| `Size` | `int Size { get; init; }` | The file's length in bytes, which CP/M records only as a count of 128-byte records — so it is the written length rounded up to the next record. | -| `Track` | `int Track { get; init; }` | Track its first block starts on (0-based). | - -#### `CpcDskExtentMap` - -Describes what occupies each stretch of a CPC DSK image: the container's own headers, the AMSDOS directory, each file's blocks, and the blocks nothing has been given. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `CpcDskFormatDescriptor` - -References: `https://www.cpcwiki.eu/index.php/Format:DSK_disk_image_file_format` — CPCWiki's DSK / Extended DSK image format specification`https://www.seasip.info/Unix/LibDsk/` — John Elliott's LibDsk, the maintained multi-format floppy-image library incl. CPC DSKAmstrad AMSDOS documentation (SOFT 968 firmware guide era) — the filesystem stored inside the image - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpcDskFormatDescriptor` | `CpcDskFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for CPC DSK creation. AMSDOS has no volume label; the only per-image knobs are the physical disk geometry the FDC presents. Default Tracks=40, Sides=1 (1 × 40 × 9 × 512 = 180 KB; the canonical CPC 3" floppy size used by AMSDOS). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing CPC DSK image. Uses `CpcDskModifier` for true O(touched bytes) random-access I/O — only the disk header, the directory area on track 0, and the freshly allocated data sectors are read or written. The full image is not paged in. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware CPC DSK defragmentor. Tries planner-driven in-place path first, falls back to rebuild path on error. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks a Standard or Extended CPC DSK image and yields the actual on-disk byte layout — the disk-info header + per-track Track Info Blocks + AMSDOS directory area (track 0 side 0) as `MetadataReserved`, every AMSDOS file's allocated sector list (coalesced into contiguous runs by physical block number) as `Used`, unallocated data sectors as `Free`. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing CPC DSK image. Uses `CpcDskModifier` for O(touched bytes) random-access I/O — walks the directory on track 0, secure-wipes the file's data sectors, and marks the directory entry's user-number byte as 0xE5 (CP/M unused). | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in a CPC DSK image: unallocated data sectors and the cluster-tip slack at the tail of each AMSDOS file's last sector. CP/M allocates whole sectors but tracks length only to 128-byte record granularity, so the bytes between a file's real length and its last allocated sector boundary are slack and get zero-filled when `wipeClusterTips` is set. Live file data and the AMSDOS directory / Track-Info metadata are preserved. | - -#### `CpcDskModifier` - -Adds and removes files on an Amstrad CPC disk image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Puts a file on the disk, replacing one of the same name. | -| `EnumerateLogicalFiles` | `static IEnumerable> EnumerateLogicalFiles(Stream image)` | Every file the disk holds, with its bytes. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Takes a file off the disk. False when it was not there. | - -#### `CpcDskReader` - -Reads the files out of an Amstrad CPC DSK image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpcDskReader` | `CpcDskReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `IsExtended` | `bool IsExtended { get; }` | | -| `Sides` | `int Sides { get; }` | | -| `Tracks` | `int Tracks { get; }` | | -| `Extract` | `byte[] Extract(CpcDskEntry entry)` | Returns one file's bytes, gathered from the blocks the directory gives it. | - -#### `CpcDskWriter` - -Writes a Standard CPC DSK image holding an AMSDOS DATA-format filesystem. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpcDskWriter` | `CpcDskWriter(Stream stream, bool leaveOpen = false, int tracks = 40, int sides = 1, int sectorsPerTrack = 9, int sectorSize = 512)` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `Dispose` | `void Dispose()` | | -| `Finish` | `void Finish()` | Lays the directory and the file data down and writes the image. | - -### Namespace `FileSystem.Cpm` - -[`CpmBlockMover`](#cpmblockmover) · [`CpmExtentMap`](#cpmextentmap) · [`CpmFormatDescriptor`](#cpmformatdescriptor) · [`CpmModifier`](#cpmmodifier) · [`CpmReader`](#cpmreader) · [`CpmReader.CpmFile`](#cpmreadercpmfile) · [`CpmReader.Volume`](#cpmreadervolume) · [`CpmWriter`](#cpmwriter) - -#### `CpmBlockMover` - -In-place CP/M block mover. Moves 1024-byte allocation blocks within a CP/M image and patches the directory entry's 16-byte block-pointer list so the file remains reachable at its new location. CP/M has no separate allocation bitmap — block usage is implicit in the union of directory-entry block lists. Updating the block pointers in the affected directory entries is sufficient to redirect the file. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpmBlockMover` | `CpmBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Allocation block size in bytes (1024). | -| `DataOrigin` | `long DataOrigin { get; }` | Byte offset where the file-data region begins, i.e. past the BIOS-reserved tracks AND the 2 KB directory area. The directory is metadata that the defrag planner must never overwrite. Block N still maps to `ReservedBytes + N*BlockSize`; we just exclude blocks 0 and 1 (the directory) from the data-region origin so the planner picks them as forbidden when finding target slots. | -| `BlockToOffset` | `long BlockToOffset(int block)` | Converts a block index to a byte offset. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OffsetToBlock` | `int OffsetToBlock(long offset)` | Converts a byte offset to a block index. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `CpmExtentMap` - -Walks a Digital Research CP/M 2.2 reference disk image (8" SSSD geometry — 256 256 bytes, 2 reserved tracks, 1024-byte allocation blocks, 64-entry directory) and yields the actual on-disk byte layout — the reserved tracks (BIOS) + 2 KB directory blocks as `MetadataReserved`, every per-file allocation-block list as one or more contiguous-run extents, and unused blocks as `Free`. Used by the defrag window's block-map preview. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `CpmFormatDescriptor` - -Read+write descriptor for CP/M 2.2 disk images using the 8" SSSD reference geometry (256 256 bytes, 2 reserved tracks, 1024-byte blocks, 64 directory entries). Kaypro/Osborne/Amstrad and other manufacturer-specific geometries are not emitted by the writer; the reader still parses any image that matches this layout. References: "CP/M 2.2 Operating System Manual" (Digital Research, 1979) — the original vendor documentation of the directory/extent model`http://www.moria.de/~michael/cpmtools/` — cpmtools (Michael Haardt), maintained implementation with the diskdefs geometry database`https://en.wikipedia.org/wiki/CP/M` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpmFormatDescriptor` | `CpmFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for CP/M creation. CP/M has no volume label; the only per-volume knob the writer exposes is the user-area code (0..15) that every directory entry is tagged with. CP/M 2.2 lets users switch between user areas with the `USER n` command — choosing a non-zero default puts the volume's entries in that user area at mount time. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing CP/M image. Uses `CpmModifier` for true O(touched bytes) random-access I/O — only the 2 KB directory + the affected file's data blocks are read or written. Replacement semantics: pre-existing entries with the same (name, ext) under user code 0 are removed (and their data wiped) before the new file is written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation: the pre-known per-input sizes drive the CP/M block allocation + directory layout in pass 1 (identical to `Create`); pass 2 streams each file's bytes from its `OpenStream` factory into its contiguous data-block run via 64 KB chunks — no file is ever buffered as a `byte[]`. Output is byte-identical to `Create` for the same inputs. Falls back to the buffered base implementation when the target stream is not seekable. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware CP/M defragmentor. Tries planner-driven in-place path first, falls back to rebuild path on error. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the 64-entry CP/M directory and yields the actual on-disk byte layout — the 2 reserved tracks (BIOS) + the 2 KB directory area as `MetadataReserved`, every per-file allocation-block list as one or more contiguous-run extents (coalesced across extents), and unreferenced data blocks as `Free`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing CP/M image. Uses `CpmModifier` for O(touched bytes) random-access I/O — matching directory entries are flipped to 0xE5 and data blocks are zeroed. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in a CP/M image: unreferenced 1024-byte allocation blocks and the cluster-tip slack at the tail of each file's last block. CP/M allocates whole blocks but tracks length to 128-byte record granularity, so the bytes between a file's real length and its last allocated block boundary are slack and get zero-filled when `wipeClusterTips` is set. Live file data, the BIOS reserved tracks, and the 2 KB directory are preserved. | - -#### `CpmModifier` - -True random-access in-place modifier for CP/M 2.2 disk images using the 8" SSSD reference geometry. Performs add / remove on an existing image with O(touched bytes) I/O — reads only the directory area (2 KB) once to learn which blocks are in use (CP/M tracks block usage implicitly via the union of directory-entry block lists; there's no separate bitmap), then writes only the affected directory entries plus the file's data blocks. CP/M 2.2 uses 8-bit block numbers when the disk has ≤ 256 allocation blocks (our reference 243-block geometry qualifies); larger DPBs use 16-bit pointers, which this modifier does not currently emit. Each directory entry tracks 16 block pointers ⇒ a single extent covers up to 16 KB of file data; larger files fan out across additional directory entries (extents) keyed by `(userCode, name.ext)` with the extent counter spliced across `S1 (entry[12])` and `S2 (entry[14])`.Companion `CpmWriter` rebuilds an image from scratch; this class is for the "I have an existing image, mutate it" path that `IArchiveModifiable` exposes. Multi-extent files are handled by both `AddFile` (allocates as many directory slots as needed) and `RemoveFile` (walks every `(user,name,ext)`-matching entry and frees its blocks). - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte userCode = 0)` | Adds a file to the existing CP/M image. Performs in-place modification: scans the directory area (2 KB) to discover free blocks, allocates the required number of 1024-byte data blocks, fills directory entries (one per 16 KB extent), and writes the data. Bytes touched: 2 KB directory read + ⌈len/1024⌉ × 1024 data writes + ⌈extents⌉ × 32-byte directory writes. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, byte? userCode = null, bool wipeData = true)` | Removes the named file from the existing CP/M image. Walks the directory to find every extent matching `(userCode, name, ext)`, marks each as deleted by setting the user-code byte to `0xE5`, optionally wipes the data blocks. Returns true if at least one extent was found. Bytes touched: 2 KB directory read + N × 32-byte directory writes + (optional) N × 1024-byte block writes. | - -#### `CpmReader` - -Reader for CP/M 2.2 disk images (8" SSSD reference geometry). Each file is reconstructed from its directory extents; extents are matched by `(userCode, name.ext)` and ordered by the extent counter before their block lists are concatenated. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpmReader` | `CpmReader()` | | -| `Read` | `static Volume Read(ReadOnlySpan image)` | | - -#### `CpmReader.CpmFile` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpmFile` | `CpmFile(byte UserCode, string Name, string Extension, bool ReadOnly, bool System, bool Archive, int RecordCount, byte[] Data)` | | -| `Archive` | `bool Archive { get; init; }` | | -| `Data` | `byte[] Data { get; init; }` | | -| `Extension` | `string Extension { get; init; }` | | -| `FullName` | `string FullName { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `ReadOnly` | `bool ReadOnly { get; init; }` | | -| `RecordCount` | `int RecordCount { get; init; }` | | -| `System` | `bool System { get; init; }` | | -| `UserCode` | `byte UserCode { get; init; }` | | - -#### `CpmReader.Volume` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Volume` | `Volume(IReadOnlyList Files, byte[] Image)` | | -| `Files` | `IReadOnlyList Files { get; init; }` | | -| `Image` | `byte[] Image { get; init; }` | | - -#### `CpmWriter` - -Writer for CP/M 2.2 disk images using the 8" SSSD reference geometry. Files are split into 16 KB extents; each extent carries up to 16 block numbers and the record count of its final used sector. The writer enforces the built-in disk size limit (241 data blocks, 64 directory entries) and rejects overflow explicitly rather than producing a truncated volume. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CpmWriter` | `CpmWriter()` | | -| `BuildToStreaming` | `static void BuildToStreaming(Stream output, IReadOnlyList, byte>> files)` | Two-pass streaming Build: pass 1 lays out the identical CP/M image (same block allocation + directory entries as `Build`) with each streaming file's data region left zero; pass 2 seeks to each file's first data-block byte offset and copies its bytes from the opener in 64 KB chunks. The output is byte-for-byte identical to writing `Build`'s result for the same inputs. | -| `Build` | `static byte[] Build(IReadOnlyList> files)` | | - -### Namespace `FileSystem.CramFs` - -[`CramFsBlockMover`](#cramfsblockmover) · [`CramFsEntry`](#cramfsentry) · [`CramFsFormatDescriptor`](#cramfsformatdescriptor) · [`CramFsReader`](#cramfsreader) · [`CramFsWriter`](#cramfswriter) - -#### `CramFsBlockMover` - -Moves a file's compressed blocks inside a CramFS image and repoints both its inode and the block pointer table that travels with it. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CramFsBlockMover` | `CramFsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Four bytes. An inode records a file's start divided by four, so that is the grid a table can begin on. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the superblock and the inodes. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Finds where the first file's table starts, and indexes the inodes. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `RestampChecksum` | `static void RestampChecksum(Stream image)` | Recomputes the checksum the superblock carries over the whole image, with the checksum field itself read as zero — which is how it was computed. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `CramFsEntry` - -Represents a single inode entry discovered while walking a CramFS image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CramFsEntry` | `CramFsEntry()` | | -| `FullPath` | `string FullPath { get; init; }` | Absolute path within the filesystem, using '/' as separator. | -| `Gid` | `byte Gid { get; init; }` | Group GID (8-bit cramfs field). | -| `InodeOffset` | `int InodeOffset { get; init; }` | Byte offset of this entry's own inode. The inode records where the file's data starts, so anything moving the data has to know where to write the new position down. | -| `IsDirectory` | `bool IsDirectory { get; }` | Returns true when this entry represents a directory. | -| `IsRegularFile` | `bool IsRegularFile { get; }` | Returns true when this entry represents a regular file. | -| `IsSymlink` | `bool IsSymlink { get; }` | Returns true when this entry represents a symbolic link. | -| `Mode` | `ushort Mode { get; init; }` | Unix mode bits including file type and permissions. | -| `Name` | `string Name { get; init; }` | The filename component (no path separator). | -| `Size` | `int Size { get; init; }` | Uncompressed file size in bytes (0 for directories). | -| `Uid` | `ushort Uid { get; init; }` | Owner UID (16-bit cramfs field). | - -#### `CramFsFormatDescriptor` - -References: `https://docs.kernel.org/filesystems/cramfs.html` — Linux kernel cramfs documentation`https://github.com/torvalds/linux/tree/master/fs/cramfs` — mainline implementation (its README documents the on-disk layout)`https://en.wikipedia.org/wiki/Cramfs` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CramFsFormatDescriptor` | `CramFsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Lays the image out again. A file is a block pointer table followed by the compressed blocks it ends, and its inode says where that pair starts — so a move is the copy, one field, and the same delta added to every entry in the table, which is cheaper than decompressing every file and compressing it back. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Reports where the image's bytes actually are: the superblock and the inode area as structure, and each file's block pointer table and compressed blocks under its name. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | CramFS is a compressed, read-only ROM filesystem: the superblock, inode tables, block-pointer tables and zlib-compressed page blocks are laid out tightly back-to-back (only 4-byte alignment padding, which is already zero) with no free space and no cluster tips. File data is packed at the compressed-block level, so there is no allocation slack to wipe. Note: `EnumerateExtents` reports Used runs at synthetic, uncompressed-size offsets for the defrag preview — those offsets do not map to real on-disk positions, so this method deliberately does not drive the generic wiper from them (doing so would zero live compressed bytes). Nothing is reclaimable; this returns 0. | - -#### `CramFsReader` - -Reads a CramFS (Compressed ROM Filesystem) image. CramFS is a Linux read-only compressed filesystem where file data is stored as independently-compressed 4 KB zlib blocks. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CramFsReader` | `CramFsReader(Stream stream)` | Initialises a `CramFsReader` by loading the entire image into memory. | -| `Entries` | `IReadOnlyList Entries { get; }` | Flat list of all entries (files, directories, symlinks) found in the image. | -| `BlockCount` | `static int BlockCount(CramFsEntry entry)` | How many block pointers a file's table holds. | -| `DataExtent` | `ValueTuple DataExtent(CramFsEntry entry)` | Where on disk `entry`'s bytes actually sit: its block pointer table followed by the compressed blocks the table ends. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(CramFsEntry entry)` | Extracts (decompresses) the data for a file or symlink entry. | - -#### `CramFsWriter` - -Writes a CramFS (Compressed ROM Filesystem) image. Entries are collected via `AddFile`, `AddDirectory`, and `AddSymlink`, and the entire image is serialised on `Dispose`. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CramFsWriter` | `CramFsWriter(Stream stream, bool leaveOpen = false)` | Initialises a new `CramFsWriter` that will write to the given stream. | -| `MaxFileBytes` | `const int MaxFileBytes` | Adds a regular file with the given path and content. | -| `MaxImageBytes` | `const long MaxImageBytes` | Largest image cramfs can address: the inode's data offset is 26 bits of 4-byte units, so nothing may live past 256 MiB. | -| `AddDirectory` | `void AddDirectory(string path)` | Adds an explicit directory entry. | -| `AddFile` | `void AddFile(string path, byte[] data)` | | -| `AddSymlink` | `void AddSymlink(string path, string target)` | Adds a symbolic link. | -| `Dispose` | `void Dispose()` | Serialises the entire CramFS image to the output stream. | - -### Namespace `FileSystem.D64` - -[`D64BlockMover`](#d64blockmover) · [`D64Entry`](#d64entry) · [`D64ExtentMap`](#d64extentmap) · [`D64FormatDescriptor`](#d64formatdescriptor) · [`D64Modifier`](#d64modifier) · [`D64Reader`](#d64reader) · [`D64Writer`](#d64writer) - -#### `D64BlockMover` - -In-place D64 block mover. Moves sector-aligned extents within a 1541 disk image and patches the T/S chain links + BAM bitmap so the file remains reachable at its new location. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D64BlockMover` | `D64BlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `D64Entry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D64Entry` | `D64Entry()` | | -| `FileType` | `byte FileType { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `D64ExtentMap` - -Walks a Commodore 1541 D64 image (174,848 bytes, 35 tracks, 256-byte sectors, zoned 21/19/18/17 sectors per track) and yields the actual on-disk byte layout — track 18 (BAM + directory) as metadata, every per-file sector chain as a sequence of contiguous-run extents, and the remaining sectors as Free. Used by the defragment window's block-map preview. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `D64FormatDescriptor` - -References: `http://unusedino.de/ec64/technical/formats/d64.html` — Peter Schepers' D64 format specification (BAM, directory, track/sector layout)"Inside Commodore DOS" (Richard Immers & Gerald Neufeld, Datamost, 1984) — the canonical 1541 DOS internals book`https://en.wikipedia.org/wiki/Commodore_1541` — Wikipedia overview of the drive whose disks D64 images - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D64FormatDescriptor` | `D64FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for D64 creation. The Commodore 1541 stores a 16-char PETSCII disk name plus a 2-char disk ID in the BAM (track 18 sector 0); both are user-visible from the C64 directory listing. Disk geometry is fixed at the single-sided 1541 size (174 848 bytes). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing D64 image. Uses `D64Modifier` for true O(touched bytes) random-access I/O — only the BAM (1 sector) + directory chain (≤19 sectors) + the new file's data sectors (⌈len/254⌉ sectors) are read or written. The 174 848-byte image isn't touched outside that. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware D64 defragmentor. Tries the planner-driven in-place path first (using the planner + `D64BlockMover`), falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the directory chain on track 18 and yields the actual on-disk byte layout — track 18 (BAM + directory) as `MetadataReserved`, every per-file sector chain as one or more contiguous-run extents, and the un-attributed sectors as `Free`. Used by the defragment window's block-map preview. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing D64 image. Uses `D64Modifier` for O(touched bytes) random-access I/O — walks the file chain, marks each sector free in the BAM, secure-wipes data sectors, and clears the directory entry's file-type byte. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in a D64 image: unallocated sectors and the cluster-tip slack at the tail of each file's last sector. A D64 file is a linked chain of 256-byte sectors — each carries a 2-byte next-track/next-sector link followed by up to 254 data bytes. The final sector's link is `(0, used+1)`, so the bytes after the last used data byte up to the sector boundary are slack. Those slack bytes are zero-filled when `wipeClusterTips` is set, while the 2-byte link headers, live file data, and the track-18 BAM/directory are preserved. Because file content is interleaved with per-sector link bytes and chains may be fragmented, the simple "offset + size" cluster-tip model of the generic wiper does not apply; tip wiping is done here by walking each chain to its final sector. Free-space wiping is delegated to the generic wiper using the extent map. | - -#### `D64Modifier` - -In-place D64 modifier. Performs add / remove on an existing 1541 disk image with strict O(touched bytes) I/O — only reads the BAM (1 sector), the directory chain (≤19 sectors), and the affected file's data chain (one sector per 254 bytes of file data). Never reads or writes the entire image, so this scales to multi-TB virtual-disk images even though D64 itself is 174 848 bytes. The companion `D64Writer` rebuilds an image from scratch; this class is for the "I have an existing image, mutate it" path that `IArchiveModifiable` exposes.Layout reminders (for the reader of this code, not for the disk): 1541 geometry: 35 tracks; 21 / 19 / 18 / 17 sectors per zone (1-17 / 18-24 / 25-30 / 31-35).Each sector is 256 bytes. Total image: 174 848 bytes.BAM lives at track 18 / sector 0. Directory chain starts at track 18 / sector 1.Each file is a chain of sectors. Each sector starts with 2 bytes (T,S of next sector, or T=0 + S=byte-count+1 for the last sector). Remaining 254 bytes are file data.Each directory sector holds 8 entries of 32 bytes. Bytes 0-1 of the sector store the T,S of the next directory sector (or 0,$FF if last). Entries 1-7 have unused bytes at offsets +0 and +1. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte fileType = 130)` | Adds a file to the existing D64 image. Performs in-place modification: allocates new sectors via BAM bit-flips, writes the file chain, writes the directory entry. Bytes touched: 1 BAM sector + ≤ ⌈log₈(entries)⌉ directory sectors + ⌈len/254⌉ file data sectors. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes the named file from the existing D64 image. Walks the file's chain to free its sectors in the BAM, optionally wipes data bytes, and clears the directory entry's file-type byte to 0 ("scratched"). Returns true if the file was found and removed, false otherwise. Bytes touched: 1 BAM sector + 1 directory sector + N file sectors. | - -#### `D64Reader` - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D64Reader` | `D64Reader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(D64Entry entry)` | | - -#### `D64Writer` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D64Writer` | `D64Writer()` | | -| `AddFile` | `void AddFile(string name, byte fileType, byte[] data)` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `Build` | `byte[] Build(string diskName = "DISK", string diskId = "00")` | Builds the complete D64 image. | - -### Namespace `FileSystem.D71` - -[`D71BlockMover`](#d71blockmover) · [`D71Entry`](#d71entry) · [`D71ExtentMap`](#d71extentmap) · [`D71FormatDescriptor`](#d71formatdescriptor) · [`D71Modifier`](#d71modifier) · [`D71Reader`](#d71reader) · [`D71Writer`](#d71writer) - -#### `D71BlockMover` - -In-place D71 block mover. Moves sector-aligned extents within a 1571 double-sided disk image and patches the T/S chain links + dual BAM bitmaps so the file remains reachable at its new location. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D71BlockMover` | `D71BlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `D71Entry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D71Entry` | `D71Entry()` | | -| `FileType` | `byte FileType { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `D71ExtentMap` - -Walks a Commodore 1571 D71 image (349,696 bytes, 70 tracks, 256-byte sectors, double-sided 1541 layout) and yields the actual on-disk byte layout — track 18 (BAM side 1 + directory) and track 53 (BAM side 2) as metadata, every per-file sector chain as a sequence of contiguous runs, and the remaining sectors as Free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `D71FormatDescriptor` - -References: `http://unusedino.de/ec64/technical/formats/d71.html` — Peter Schepers' D71 format specification (double-sided BAM, directory layout)Commodore 1571 Disk Drive User's Guide (Commodore, 1985) — original vendor documentation`https://en.wikipedia.org/wiki/Commodore_1571` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D71FormatDescriptor` | `D71FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for D71 creation. The Commodore 1571 stores a 16-char PETSCII disk name plus a 2-char disk ID in the BAM (track 18 sector 0); both appear in the C128 directory header. Geometry is fixed at the double-sided 1571 size (349 696 bytes). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing D71 image. Uses `D71Modifier` for true O(touched bytes) random-access I/O — only the BAM (2 sectors), the directory chain, and the file's data sectors are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware D71 defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the directory chain on track 18 (and BAM mirror on track 53) and yields the actual on-disk byte layout — track 18 BAM+directory and the BAM mirror as `MetadataReserved`, every per-file sector chain as one or more contiguous-run extents, and the un-attributed sectors as `Free`. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing D71 image. Uses `D71Modifier` for O(touched bytes) random-access I/O. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the D71 image: every sector not claimed by a live file chain or by the directory/BAM metadata is overwritten with zeros. Cluster-tip wiping is not applicable to the 1571 layout: files are stored as a chain of 256-byte sectors carrying a 2-byte track/sector link header plus 254 payload bytes, so the directory-entry size is expressed in 254-byte units that do not map onto a contiguous, cluster-aligned tail. The trailing slack inside a file's final sector is therefore left to the reader/writer; this method clears only whole free sectors. | - -#### `D71Modifier` - -In-place D71 modifier — same blueprint as `D64Modifier`, adapted for the 1571's double-sided geometry. Performs O(touched bytes) random-access I/O: only reads the two BAM sectors (T18S0 + T53S0), the directory chain (≤19 sectors on T18), and the file's data chain. Layout reminders: 1571 = 70 tracks (35 per side). Total: 1366 sectors, 349 696 bytes.Track 18 / sector 0: side-1 BAM bitmaps + per-track free counts for side 2 (offsets 0xDD–0xFF).Track 53 / sector 0: side-2 BAM bitmaps (3 bytes per track, no free-count byte).Directory chain at T18S1+ (single side, same shape as D64).Each sector: 256 B; data sectors carry T,S link + 254 data bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte fileType = 130)` | Adds a file to an existing D71 image with O(touched bytes) I/O. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file with O(touched bytes) I/O. Returns true if removed. | - -#### `D71Reader` - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D71Reader` | `D71Reader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(D71Entry entry)` | | - -#### `D71Writer` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D71Writer` | `D71Writer()` | | -| `AddFile` | `void AddFile(string name, byte fileType, byte[] data)` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `Build` | `byte[] Build(string diskName = "DISK", string diskId = "00")` | Builds the complete D71 image. | - -### Namespace `FileSystem.D81` - -[`D81BlockMover`](#d81blockmover) · [`D81Entry`](#d81entry) · [`D81ExtentMap`](#d81extentmap) · [`D81FormatDescriptor`](#d81formatdescriptor) · [`D81Modifier`](#d81modifier) · [`D81Reader`](#d81reader) · [`D81Writer`](#d81writer) - -#### `D81BlockMover` - -In-place D81 block mover. Moves sector-aligned extents within a 1581 disk image (80 tracks x 40 sectors, uniform geometry) and patches the T/S chain links + dual BAM bitmaps so the file remains reachable. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D81BlockMover` | `D81BlockMover()` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `D81Entry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D81Entry` | `D81Entry()` | | -| `FileType` | `byte FileType { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `D81ExtentMap` - -Walks a Commodore 1581 D81 image (819,200 bytes, 80 tracks × 40 sectors, 256-byte sectors) and yields the actual on-disk byte layout — track 40 header + BAM1 + BAM2 + directory chain as metadata, every per-file sector chain as a sequence of contiguous runs, and the remaining sectors as Free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `D81FormatDescriptor` - -References: `http://unusedino.de/ec64/technical/formats/d81.html` — Peter Schepers' D81 format specification (header block, BAM, directory)Commodore 1581 Disk Drive User's Guide (Commodore, 1987) — original vendor documentation`https://en.wikipedia.org/wiki/Commodore_1581` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D81FormatDescriptor` | `D81FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs for D81 creation. The Commodore 1581 stores a 16-char PETSCII disk name plus a 2-char disk ID in the header block (track 40 sector 0); both appear in the C128 directory header. Geometry is fixed at the 1581 size (819 200 bytes). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing D81 image. Uses `D81Modifier` for true O(touched bytes) random-access I/O — only the BAM (2 sectors), the directory chain, and the file's data sectors are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware D81 defragmentor. Tries the planner-driven in-place path first, falling back to the rebuild path on error or for `CarveHole`. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks track 40 (header + BAM1 + BAM2 + directory chain) and yields the actual on-disk byte layout — header/BAM/directory sectors as `MetadataReserved`, every per-file sector chain as one or more contiguous-run extents, and the un-attributed sectors as `Free`. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing D81 image. Uses `D81Modifier` for O(touched bytes) random-access I/O. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the D81 image: every sector not claimed by a live file chain or by the header/BAM/directory metadata is overwritten with zeros. Cluster-tip wiping is not applicable to the 1581 layout: files are stored as a chain of 256-byte sectors carrying a 2-byte track/sector link header plus 254 payload bytes, so the directory-entry size is expressed in 254-byte units that do not map onto a contiguous, cluster-aligned tail. This method clears only whole free sectors. | - -#### `D81Modifier` - -In-place D81 modifier — same blueprint as `D64Modifier` / `D71Modifier`, adapted for the 1581's 3.5" geometry. Performs O(touched bytes) random-access I/O: only reads the two BAM sectors (T40S1 + T40S2), the directory chain (T40S3+), and the file's data chain. Layout reminders: 1581 = 80 tracks × 40 sectors = 3200 sectors = 819 200 bytes (uniform).Track 40 / sector 0: header.Track 40 / sector 1: BAM bitmaps for tracks 1-40 (6 bytes per track: 1 free + 5 bitmap).Track 40 / sector 2: BAM bitmaps for tracks 41-80 (same shape).Track 40 / sector 3+: directory chain.Each sector: 256 B; data sectors carry T,S link + 254 data bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data, byte fileType = 130)` | Adds a file with O(touched bytes) I/O. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file with O(touched bytes) I/O. | - -#### `D81Reader` - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `D81Reader` | `D81Reader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(D81Entry entry)` | | - -#### `D81Writer` - -| Member | Signature | Summary | -| --- | --- | --- | -| `D81Writer` | `D81Writer()` | | -| `AddFile` | `void AddFile(string name, byte fileType, byte[] data)` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `Build` | `byte[] Build(string diskName = "DISK", string diskId = "00")` | Builds the complete 1581 D81 image (819 200 bytes). | - -### Namespace `FileSystem.DoubleSpace` - -[`CvfVariant`](#cvfvariant) · [`DoubleSpaceBlockMover`](#doublespaceblockmover) · [`DoubleSpaceEntry`](#doublespaceentry) · [`DoubleSpaceExtentMap`](#doublespaceextentmap) · [`DoubleSpaceFormatDescriptor`](#doublespaceformatdescriptor) · [`DoubleSpaceInPlaceModifier`](#doublespaceinplacemodifier) · [`DoubleSpaceReader`](#doublespacereader) · [`DoubleSpaceWriter`](#doublespacewriter) · [`DriveSpaceFormatDescriptor`](#drivespaceformatdescriptor) · [`DsCompression`](#dscompression) · [`GenuineCvfReader`](#genuinecvfreader) · [`GenuineCvfWriter`](#genuinecvfwriter) - -#### `CvfVariant` - -Variant of the CVF (Compressed Volume File) being produced. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `DoubleSpace60` | `0` | MS-DOS 6.0 DoubleSpace. OEM name `MSDSP6.0`, CvfSignature `DBLS`. Codec: DS LZ77 (4 KiB window). | -| `DriveSpace62` | `1` | MS-DOS 6.22 DriveSpace. OEM name `MSDSP6.2`, CvfSignature `DVRS`. Codec: DS LZ77 (8 KiB window). | -| `DriveSpace30` | `2` | Windows 95 OSR2 DriveSpace 3.0. OEM name `DRVSPACE`, CvfSignature `DVRS`. Codec: DS LZ77 (8 KiB window). | -| `DriveSpace3` | `3` | Windows 95 Plus! Pack (1995) DriveSpace 3. OEM name `MS_DSP3`, CvfSignature `DVR3`. Codec: MS LZH (LZ77 + canonical Huffman). | - -#### `DoubleSpaceBlockMover` - -In-place DoubleSpace/DriveSpace CVF block mover. Moves compressed cluster runs within the DATA region and patches the MDFAT + BitFAT + inner FAT chain so the file remains reachable at its new physical location. Unlike a plain FAT block mover that moves raw cluster bytes and patches a FAT chain, DoubleSpace has a two-level indirection: the inner FAT maps files to logical clusters, and the MDFAT maps logical clusters to physical sector offsets within the DATA region. A "move" here relocates the compressed run in the DATA region and patches the MDFAT entry for the corresponding logical cluster to point at the new physical sector offset. The inner FAT chain is unchanged (logical cluster numbers don't move). - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceBlockMover` | `DoubleSpaceBlockMover()` | | -| `BytesPerSector` | `int BytesPerSector { get; }` | Bytes per sector. | -| `DataRegionByteStart` | `long DataRegionByteStart { get; }` | Byte offset of the DATA region start. | -| `Init` | `void Init(byte[] image)` | Initialises the mover by parsing MDBPB fields from `image`. Must be called before any move operations. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | Patches MDFAT and BitFAT after a raw extent move within the DATA region. Finds the MDFAT entry whose physical sector range matches the old offset, rewrites it to point at the new physical sector, and updates BitFAT bits accordingly (clears old sectors, sets new sectors). The inner FAT chain is NOT touched because logical cluster numbers do not change during a physical move — only the MDFAT indirection changes. | - -#### `DoubleSpaceEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceEntry` | `DoubleSpaceEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `DoubleSpaceExtentMap` - -Walks a DoubleSpace/DriveSpace CVF image and yields the actual on-disk byte layout: metadata regions (MDBPB, inner FAT, root dir, MDFAT, BitFAT), every compressed/stored cluster run per file (mapped through MDFAT), and free physical sectors in the DATA region. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | Enumerates the on-disk layout of a CVF image. Parses the MDBPB, walks the inner FAT chain per file, resolves each logical cluster through the MDFAT to its physical sector run in the DATA region, and emits one `DefragBlockInfo` per contiguous physical run per file. | - -#### `DoubleSpaceFormatDescriptor` - -References: `https://github.com/sandsmark/dmsdos` — dmsdos, the GPL Linux CVF driver whose source + `doc/dmsdos.doc` are the de-facto MDBPB/MDFAT/BitFAT on-disk specificationMicrosoft MS-DOS 6 documentation (DoubleSpace chapter) — original vendor description of the compressed volume file`https://en.wikipedia.org/wiki/DriveSpace` — Wikipedia article covering DoubleSpace and its successors - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceFormatDescriptor` | `DoubleSpaceFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | Microsoft DoubleSpace compressed volume file (MS-DOS 6.0). Spec-compliant MDBPB + MDFAT + BitFAT + DATA layout. Inner FAT16 volume with VFAT long filenames. Writer emits stored (uncompressed) runs; the JM/DSS LZ payload variant is a future enhancement (see `DoubleSpaceWriter`). | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | True in-place add: BitFAT bits flip, MDFAT cluster-allocation entries are written in place, inner FAT chains extended, and VFAT dirents are inserted into the root directory without rewriting any unrelated bytes. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware CVF defragmentor. Supports planner-driven in-place defrag (using `DefragPlanner` + `DoubleSpaceBlockMover`) with rebuild fallback on error. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | True in-place remove: walks the inner FAT chain, zeros each physical run, clears BitFAT bits, zeros MDFAT entries, zeros inner FAT chain, and scratches the dirent (+ LFN chain) with 0xE5. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the CVF image: every physical sector in the DATA region not claimed by a live file/directory run, plus any gaps outside the metadata regions, is overwritten with zeros. Cluster-tip wiping is not applicable to a CVF: the DATA region holds compressed/stored sector runs whose physical byte length is unrelated to the logical (uncompressed) file size recorded in the inner FAT directory. Zeroing a tail by logical-size offset would corrupt the encoded run, so only whole free sectors are cleared. | - -#### `DoubleSpaceInPlaceModifier` - -True in-place modifier for Microsoft DoubleSpace / DriveSpace CVF images. Mutates the MDBPB-driven volume structure directly: BitFAT bits flip, MDFAT cluster-allocation entries are written in place, inner FAT chains are extended/zeroed at the cluster slot, VFAT root dirents are added/ scratched in place, and physical compressed runs are placed in the DATA region without rewriting any unrelated bytes. Unlike the `ModifyRebuilder` path, this modifier never rebuilds the image. Bytes outside the touched cluster slot, MDFAT entry, BitFAT byte, FAT chain entry, dirent record and freshly-allocated physical run are guaranteed byte-identical.Scope. Add, Remove, and Replace target the inner root directory only. Subdirectory mutation is not supported (legacy CVF images created by DBLSPACE/DRVSPACE never used subdirs as a normal authoring pattern). The variant (DoubleSpace 6.0 / DriveSpace 6.22 / DriveSpace 3.0) is auto-detected from the OEM signature so the same modifier services both descriptors. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Add` | `static void Add(Stream image, IReadOnlyList inputs)` | Adds (or replaces) files in-place. For each input: walks the inner FAT to find `count` free logical clusters, allocates a contiguous physical run at the end of the in-use DATA region, compresses each cluster, writes MDFAT + BitFAT + inner FAT entries in place, and writes the VFAT dirent (+ LFN chain) into the first free dirent slots of the root directory. If an input name matches an existing entry, the old entry's clusters are freed first (so the slot can be re-used and the old physical run is wiped). | -| `Remove` | `static void Remove(Stream image, string[] entryNames)` | Removes the named entries in place. For each entry: walks the inner FAT chain, zeros each physical compressed run, clears BitFAT bits for the freed sectors, zeros the MDFAT entries, zeros the inner FAT chain, and scratches the dirent + LFN chain by writing 0xE5 into byte 0 of each dirent. Bytes outside those allocation-table slots and the freed physical runs are guaranteed byte-identical to the source image. | - -#### `DoubleSpaceReader` - -Reads Microsoft DoubleSpace / DriveSpace Compressed Volume Files (CVF). The MDBPB (offset 0) starts with a standard FAT BPB (first 36 bytes) and is followed by CVF-specific fields at offset 36 (CvfSignature, CvfVersion, MdfatStart/Len, BitFatStart/Len, DataStart/Len). The reader follows the MDFAT indirection when available and falls back to the inline inner data region otherwise. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceReader` | `DoubleSpaceReader(Stream stream, bool leaveOpen = false)` | | -| `CvfSignature` | `string CvfSignature { get; }` | Raw CvfSignature at offset 36 (`DBLS`, `DVRS`, or `DVR3`). | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `IsDriveSpace3` | `bool IsDriveSpace3 { get; }` | True for DriveSpace 3 (Win95 Plus! Pack, 1995) images — the variant that uses the MS LZH codec rather than DS LZ77. Detected by the 7-char `MS_DSP3` prefix in the OEM area (the 8th byte is a NUL pad). | -| `IsDriveSpace` | `bool IsDriveSpace { get; }` | True if DriveSpace (any), false if DoubleSpace 6.0. | -| `Signature` | `string Signature { get; }` | OEM name in the MDBPB: `MSDSP6.0`, `MSDSP6.2`, `DRVSPACE`, or `MS_DSP3`. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DoubleSpaceEntry entry)` | Extracts file data. Traverses the inner FAT chain starting from the file's first cluster, resolves each cluster through the MDFAT (when available) to its compressed run in the DATA region, and decompresses. Falls back to the inner data region for clusters with no MDFAT mapping. | - -#### `DoubleSpaceWriter` - -Builds a spec-compliant Microsoft DoubleSpace / DriveSpace Compressed Volume File (CVF). Layout produced (in sector units, 512 B / sector): Sector 0 — MDBPB (Master DoubleSpace BIOS Parameter Block). First 36 bytes are a standard FAT BPB so the host can identify the volume. Offsets 36..71 are the CVF-specific fields (CvfSignature, CvfVersion, MdfatStart/Len, BitFatStart/Len, DataStart/Len, HostFatCopyStart).Inner FAT1/FAT2 — the inner FAT12/16 tables used by the compressed volume's filesystem.Inner root directory — fixed-size FAT12/16 root with 8.3 entries plus VFAT LFN chains for names that don't fit 8.3.MDFAT — one uint32 entry per logical cluster of the data area; maps logical cluster → first physical sector of the compressed run, run length in sectors and a flags nibble (0=free, 1=stored, 2=compressed).BitFAT — 1 bit per 8 KB region of the data area marking in-use regions.DATA region — compressed clusters packed as `DsCompression` blocks (2-byte header + payload). This writer emits only stored runs (header bit 15 clear) containing the raw cluster contents — the JM/DSS LZ variant is NOT produced. A real DRVSPACE.BIN driver accepts stored runs transparently.Codec selection: driven by `Variant`: `DoubleSpace60` → DS LZ77 (4 KiB window).`DriveSpace62` / `DriveSpace30` → DS LZ77 (8 KiB window).`DriveSpace3` (Win95 Plus! Pack 1995) → MS LZH (LZ77 + canonical Huffman), routed through `CompressMsLzh`. The 2-byte CVF run header (bit 15 = compressed, low 12 bits = size−1) is shared across all codecs, so the on-disk MDBPB + MDFAT + BitFAT layout is byte-compatible across the family — only the OEM bytes, CvfSignature and inner payload encoding change. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DoubleSpaceWriter` | `DoubleSpaceWriter()` | | -| `CompressionLevel` | `byte CompressionLevel { get; set; }` | DriveSpace 3 (Win95 Plus! Pack) compression-level byte stored at MDBPB offset 76. Values 0..2 correspond to the "Standard", "HiPack", and "UltraPack" UI labels in Microsoft's tooling. Ignored by the codec itself; preserved for round-trip compatibility with third-party readers. Only emitted when `Variant` is `DriveSpace3`. | -| `DriveSpace` | `bool DriveSpace { get; set; }` | Back-compat shim: `true` = any DriveSpace flavour, `false` = DoubleSpace 6.0. Setter targets DriveSpace 6.22. | -| `EnableCompression` | `bool EnableCompression { get; set; }` | When `true` (default), per-cluster JM/LZ compression is attempted and the compressed payload is emitted whenever it shrinks the cluster. Clusters that do not compress are stored raw (MDFAT flags = 1). | -| `MethodName` | `string MethodName { get; set; }` | Compression method id, following the writer's published method list (`stored`, `ds-lz77`, `ds-lz77+`, `ds-lz77++`). Parsed via `Parse` on each `Build`: an unknown base method falls back to `ds-lz77`; a trailing `+` bumps the parse-effort tier (1 = lazy matching, 2+ = iterated multi-pass). Defaults to `ds-lz77` for parity with what real DOS DBLSPACE/DRVSPACE drivers produce. Special id `stored` forces the legacy uncompressed-runs writer even when `EnableCompression` is on — useful for diagnostic images or for inputs where compression would only waste CPU. | -| `Variant` | `CvfVariant Variant { get; set; }` | Which CVF variant to produce (signatures and CvfVersion differ). | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file. `name` may be a long filename; a VFAT LFN chain is emitted automatically. | -| `AddFile` | `void AddFile(string name, byte[] data, bool compress)` | Adds a file with an explicit per-file compression opt-in. Use `compress`=`false` to force stored runs for that file even when `EnableCompression` is on (useful for mixed stored/compressed tests or for already-compressed payloads where LZ would only waste CPU). | -| `Build` | `byte[] Build()` | Builds the complete CVF image. | - -#### `DriveSpaceFormatDescriptor` - -References: `https://github.com/sandsmark/dmsdos` — dmsdos, the GPL Linux CVF driver whose source + `doc/dmsdos.doc` are the de-facto on-disk specification (incl. the JM-0-0 cluster codec)Microsoft MS-DOS 6.22 documentation (DriveSpace chapter) — original vendor description`https://en.wikipedia.org/wiki/DriveSpace` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DriveSpaceFormatDescriptor` | `DriveSpaceFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | Microsoft DriveSpace compressed volume file (MS-DOS 6.22+/Windows 95). Spec-compliant MDBPB + MDFAT + BitFAT + DATA layout. Inner FAT16 volume with VFAT long filenames. Writer emits stored (uncompressed) runs; the JM/DSS LZ payload variant is a future enhancement. | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Sole tunable the DriveSpace writer honours: the per-cluster compression method. "stored" forces uncompressed runs; the ds-lz77 family selects the genuine DS LZ77 codec at increasing effort tiers (lazy matching, then Zopfli-style iteration). The geometry (MDBPB/MDFAT/BitFAT) is fixed. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | True in-place add: BitFAT bits flip, MDFAT cluster-allocation entries are written in place, inner FAT chains extended, and VFAT dirents are inserted into the root directory without rewriting any unrelated bytes. Variant auto-detected from the OEM signature in the existing image. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware CVF defragmentor. Supports planner-driven in-place defrag (using `DefragPlanner` + `DoubleSpaceBlockMover`) with rebuild fallback on error. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | True in-place remove: walks the inner FAT chain, zeros each physical run, clears BitFAT bits, zeros MDFAT entries, zeros inner FAT chain, and scratches the dirent (+ LFN chain) with 0xE5. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the CVF image: every physical sector in the DATA region not claimed by a live file/directory run, plus any gaps outside the metadata regions, is overwritten with zeros. Cluster-tip wiping is not applicable to a CVF: the DATA region holds compressed/stored sector runs whose physical byte length is unrelated to the logical (uncompressed) file size recorded in the inner FAT directory. Zeroing a tail by logical-size offset would corrupt the encoded run, so only whole free sectors are cleared. | - -#### `DsCompression` - -DoubleSpace / DriveSpace sector-level LZ77 compression. Each CVF "compressed run" consists of a 2-byte little-endian header plus a payload. In the header: bit 15 indicates compressed (`1`) or stored (`0`); bits 0..11 carry `payload_size − 1` (so a payload of 4096 B encodes as `0x0FFF`). The compression algorithm itself is delegated to `DoubleSpaceCompressor` (DBLS, 4 KiB window) and `DriveSpaceCompressor` (DVRS, 8 KiB window) in `Compression.Core.BuildingBlocks`. Both produce a stream prefixed with a 4-byte little-endian uncompressed-size header followed by the variable bit-length token sequence. When the compressed payload would not fit in the 12-bit header size field (> 4096 B) or is not smaller than the raw input, a stored run is emitted instead. On decode, the header's bit 15 picks the branch. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CompressDriveSpace` | `static byte[] CompressDriveSpace(ReadOnlySpan input)` | Compresses using the DriveSpace LZ algorithm (8 KiB window) instead of DoubleSpace JM. The CVF header framing is identical so the reader handles both transparently. | -| `CompressDriveSpace` | `static byte[] CompressDriveSpace(ReadOnlySpan input, int effort)` | DriveSpace variant with an explicit parse-effort tier — see `Compress`. | -| `CompressMsLzh` | `static byte[] CompressMsLzh(ReadOnlySpan input)` | Compresses a single cluster with the MS LZH codec (Win95 Plus! Pack DriveSpace 3) at the default effort 0 (greedy + fixed Huffman tables) and wraps it in the shared CVF 2-byte header. Falls back to a stored run when the compressed payload either exceeds the 12-bit CVF size cap (> 4096 B) or is no smaller than the raw input — the same shrink-or-store invariant the DS LZ77 path honours. | -| `CompressMsLzh` | `static byte[] CompressMsLzh(ReadOnlySpan input, int effort)` | Compresses a single cluster with the MS LZH codec at an explicit parse-effort tier (`0` = greedy, `1` = lazy matching, `2+` = iterated multi-pass). The shrink-or-store fallback applies at every effort level — incompressible clusters always end up as stored CVF runs regardless of effort. | -| `Compress` | `static byte[] Compress(ReadOnlySpan input)` | Compresses a single sector (at most 4096 B) using the DoubleSpace JM algorithm and returns the complete CVF run (2-byte header + payload). Falls back to a stored run if compression does not shrink the data. | -| `Compress` | `static byte[] Compress(ReadOnlySpan input, int effort)` | Compresses with an explicit parse-effort tier (`0` = greedy, `1` = lazy matching, `2+` = iterated multi-pass) routed through `DsLz77Compressor`. Falls back to a stored run if compression does not shrink the data. | -| `DecompressMsLzh` | `static byte[] DecompressMsLzh(ReadOnlySpan block)` | Decompresses a single CVF run produced by `CompressMsLzh` / `CompressMsLzh`. Header bit 15 dispatches between MS LZH (set) and raw stored (clear). | -| `Decompress` | `static byte[] Decompress(ReadOnlySpan block)` | Decompresses a single CVF run (2-byte header + payload). The compressed payload is decoded with the DoubleSpace/DriveSpace building block — both variants share the same token grammar, so a single decoder handles them. | - -#### `GenuineCvfReader` - -Reads a genuine MS-DOS DoubleSpace/DriveSpace (v1/v2) CVF — the real `MSDBL6.0` container that `GenuineCvfWriter` emits and that the independent `dmsdos` driver mounts ("drivespace CVF version 2"). This is the read half of the genuine v2 round trip; with the driver-proven writer it gives a full read/write path over the genuine on-disk format. MDBPB at sector 0 carries the BPB plus the CVF geometry (inner base @0x27, MDFAT start @0x24, cluster index base @0x2D, root offset @0x29). The inner FAT12 volume lives at the base sector; file data clusters are located through the 4-byte MDFAT (DBLSP/DRVSP packing: physical sector in bits 0..20, stored run length and flags in the high bits). Stored clusters are read verbatim and truncated by the directory's file size. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `GenuineCvfReader` | `GenuineCvfReader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `VolumeLabel` | `string VolumeLabel { get; }` | The inner volume label (0x08 root entry), or "" when none was written. | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DoubleSpaceEntry entry)` | | - -#### `GenuineCvfWriter` - -Builds a genuine MS-DOS DoubleSpace/DriveSpace Compressed Volume File (CVF) in the on-disk shape a real DoubleSpace/DriveSpace driver mounts — verified by the independent GPL `dmsdos` driver (the Linux DoubleSpace/DriveSpace/Stacker driver): it mounts this writer's output, lists the inner directory, and reads every file back byte-exact (detected as "drivespace CVF version 2"). Unlike `DoubleSpaceWriter` (which emits the older `MSDSP*` / offset-36 layout our own reader round-trips), this writer reproduces the real `MSDBL6.0` container: Sector 0 — MDBPB: standard BPB (512 B/sector, 16 sec/cluster, 16 reserved, 1 FAT, 512 root entries, 128-sector FAT) plus the DoubleSpace geometry substructure (inner-volume base sector @0x27, root @0x29, first-data @0x2B, MDFAT index offset @0x2D, MDFAT-start-1 @0x24).Sector 130 — MDFAT: one little-endian u32 per inner-volume cluster at `(0x24+1)*512 + (0x2D + cluster)*4`; physical sector = `(entry & 0x1FFFFF) + 1`; stored clusters carry the run-length flag bits (0xFFC0… full, 0xC000… final).Sector 417 (inner base) — a complete FAT12 volume (boot, FAT, root directory, data) laid out contiguously; clusters are stored verbatim (no compression), which the driver reads transparently. The fixed geometry matches a ~557 KB compressed volume; files must fit the inner FAT12 data area (≈ 69 clusters of 8 KB). - -| Member | Signature | Summary | -| --- | --- | --- | -| `GenuineCvfWriter` | `GenuineCvfWriter()` | | -| `CompressionLevel` | `int CompressionLevel { get; init; }` | Codec effort (search depth). Higher = better ratio, slower. | -| `CompressionMethod` | `CvfLzMethod CompressionMethod { get; init; }` | Per-cluster compression codec. Stored (default) emits uncompressed clusters; DS = DoubleSpace DS-0-x, JM = DriveSpace JM-0-x. | -| `ForceCompress` | `bool ForceCompress { get; init; }` | Keep a compressed cluster even if it does not shrink (auto-best off). | -| `Timestamp` | `DateTime Timestamp { get; init; }` | Creation/modification timestamp stamped on every file entry. Default (before 1980) leaves the FAT date/time fields zero. | -| `VolumeLabel` | `string VolumeLabel { get; init; }` | Optional inner-volume label (≤11 chars). Empty = no label entry. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the root directory of the compressed volume. | -| `Build` | `byte[] Build()` | Builds the CVF image bytes. | - -### Namespace `FileSystem.DragonFs` - -[`DragonFsBlockMover`](#dragonfsblockmover) · [`DragonFsEntry`](#dragonfsentry) · [`DragonFsExtentMap`](#dragonfsextentmap) · [`DragonFsFormatDescriptor`](#dragonfsformatdescriptor) · [`DragonFsModifier`](#dragonfsmodifier) · [`DragonFsReader`](#dragonfsreader) · [`DragonFsWriter`](#dragonfswriter) - -#### `DragonFsBlockMover` - -Moves a file inside a DragonFS volume by moving its directory record and its bytes together, and repointing whoever linked to them. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DragonFsBlockMover` | `DragonFsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | One byte. A record is reached by an absolute offset, so nothing about the format asks a file to start on a boundary. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the boot area and the root record. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the record it is given and nothing else, so an owner in several runs — which this format cannot produce — would be several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Nothing to read: the layout is the format's, not the image's. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `DragonFsEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `DragonFsEntry` | `DragonFsEntry()` | | -| `DataOffset` | `int DataOffset { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `DragonFsExtentMap` - -Reports where a DragonFS volume's bytes are: each file as its directory record followed by its data, and whatever nothing links to as free. - -| Member | Signature | Summary | -| --- | --- | --- | -| `RecordSize` | `const int RecordSize` | Bytes one directory record occupies. | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `DragonFsFormatDescriptor` - -Read-only descriptor for DragonFS — the embedded read-only filesystem used by Libdragon (open Nintendo 64 SDK) to bundle assets inside an N64 ROM image. DragonFS is big-endian throughout, uses 32-byte directory records starting at file offset 256 (Libdragon DFS_ROOT_OFFSET), and lacks an unambiguous fixed magic in original images — detection is by .dfs extension plus an optional "DragonFS" ASCII tag at offset 0 for self-produced research images. References: `https://github.com/DragonMinded/libdragon` — Libdragon source, the origin of DragonFS (`dragonfs.c` / `mkdfs` define the format)`https://libdragon.dev` — official Libdragon documentation site - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DragonFsFormatDescriptor` | `DragonFsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing DragonFS image using `DragonFsModifier`. The modifier appends new records + data at the image tail and relinks the singly-linked chain, so existing files' data bytes stay byte-identical at their original offsets — a genuine in-place mutation (the image grows only at the end). | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Produces a fresh DragonFS image from scratch holding `inputs`. DragonFS is a flat filesystem, so subdirectory paths are flattened to their leaf names via `AddFile`. | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Lays the volume out again. A file here is its directory record followed by its bytes — the record is what gives the bytes their address — so the pair moves together and what is rewritten is the pointer that reached it. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries in place by blanking their directory records (the chain stays intact; the reader skips blank records). | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zero-fills every byte no record and no file claims — which is where a removed file's bytes stay until something else takes them. | - -#### `DragonFsModifier` - -In-place modifier for DragonFS (Libdragon / Nintendo 64) images. The filesystem is a singly-linked list of 32-byte directory records, each immediately followed by that file's inline data, with absolute `next_entry_offset` pointers. This lets us mutate without re-packing: Add: append the new record + its data at the end of the image and patch the previous tail record's `next_entry_offset` to point at it. Existing files' data bytes stay byte-identical at their original offsets; only the predecessor's link word (4 bytes) and the appended tail bytes change. I/O = chain walk (one 32-byte record read per entry) + one tail record rewrite + the appended record/data.Remove: blank the record's name field (the reader skips blank records but still follows the link), optionally wiping the inline data. No other byte moves.Record layout (big-endian): next_offset u32 @0, flags u32 @4 (0x0001 = dir, 0x0002 = end-of-directory), name[20] @8 (NUL-terminated), size u32 @28. File data starts at record_offset + 32. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds a file by appending a record + data at the image tail and relinking the chain. The image grows by (32 + data.Length) bytes at the end; nothing before the old end moves. | -| `IsDragonFs` | `static bool IsDragonFs(Stream image)` | True if the stream is large enough to hold a DragonFS root entry. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes the named file in place by blanking its directory record's name field (the reader skips blank-name records while still following the chain). Optionally wipes the inline data. Returns true if found. | - -#### `DragonFsReader` - -Reads DragonFS images — the read-only embedded filesystem used by Libdragon (the open Nintendo 64 SDK) to bundle assets into a N64 ROM. DragonFS is big-endian throughout (MIPS R4300i convention), uses 32-byte directory records, and a singly-linked list for file chunks. Root directory entry sits at file offset 256 (Libdragon DFS_ROOT_OFFSET). Directory entry layout (32 bytes BE): 0x00 u32 next_entry_offset (0 = end of dir) 0x04 u32 flags 0x0001 = directory 0x0002 = end-of-directory marker 0x08 char[20] name (NUL-terminated, ASCII) 0x1C u32 file_size (for files) / first_entry_offset (for dirs) File data starts at offset_of_entry + 32 unless the file uses indirection (large files chain via "next chunk" pointers); this reader handles the common direct-contiguous-data case. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DragonFsReader` | `DragonFsReader(Stream stream)` | | -| `DefaultRootOffset` | `const int DefaultRootOffset` | | -| `OptionalTag` | `static readonly byte[] OptionalTag` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `RootOffset` | `int RootOffset { get; }` | | -| `ValidRoot` | `bool ValidRoot { get; }` | | -| `BuildSurfaceMetadata` | `byte[] BuildSurfaceMetadata()` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(DragonFsEntry entry)` | | - -#### `DragonFsWriter` - -Builds a fresh, read-only DragonFS image (Libdragon / Nintendo 64) from a flat set of input files. The produced image round-trips through `DragonFsReader`. Layout produced (big-endian throughout): 0x000..0x007 "DragonFS" ASCII tag (enables self-detection) 0x008..0x107 zero padding 0x108 start of the root directory's child chain (DFS_ROOT_OFFSET = 8 + 256 = 264) Each child is a 32-byte directory record immediately followed by that file's raw bytes: 0x00 u32 next_entry_offset (absolute byte offset of the next record; 0 = last) 0x04 u32 flags (0 = regular file) 0x08 char[20] name (NUL-terminated ASCII; DragonDOS-style 8.3 leaf names) 0x1C u32 file_size File data follows the record at record_offset + 32; the next record begins at record_offset + 32 + file_size (no inter-file padding is required by the reader, but each record's start is what the previous record's next_entry_offset points at). - -| Member | Signature | Summary | -| --- | --- | --- | -| `DragonFsWriter` | `DragonFsWriter()` | | -| `EntryRecordSize` | `const int EntryRecordSize` | Size of one directory record in bytes. | -| `MaxNameLength` | `const int MaxNameLength` | Maximum name length stored in a directory record (NUL-terminated within 20 bytes). | -| `RootChainOffset` | `const int RootChainOffset` | Byte offset of the first directory record (the root chain head). | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to the image. Names are flattened to an 8.3-style leaf and truncated to fit the record's 20-byte (NUL-terminated) name field. | -| `Build` | `byte[] Build()` | Builds the complete DragonFS image as a byte array. | -| `WriteTo` | `void WriteTo(Stream output)` | Emits the complete DragonFS image into `output`. | - -### Namespace `FileSystem.Erofs` - -[`ErofsBlockMover`](#erofsblockmover) · [`ErofsFormatDescriptor`](#erofsformatdescriptor) · [`ErofsReader`](#erofsreader) · [`ErofsReader.Entry`](#erofsreaderentry) · [`ErofsWriter`](#erofswriter) - -#### `ErofsBlockMover` - -Moves a file's blocks inside an EROFS image and repoints its inode. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ErofsBlockMover` | `ErofsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Block size in bytes, as the superblock's blkszbits gives it. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the superblock and the inode area. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads the geometry and where the metadata area starts. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `ErofsFormatDescriptor` - -Descriptor for EROFS images. Reading covers the uncompressed + inline inode layouts; creation produces a minimal uncompressed (FLAT_PLAIN) image via `ErofsWriter`. Full-fidelity, compressed images remain the job of `mkfs.erofs`; our writer targets the round-trippable WORM subset (compact inodes, plain data, nested directories). References: `https://docs.kernel.org/filesystems/erofs.html` — Linux kernel EROFS documentation (on-disk overview)`https://github.com/torvalds/linux/tree/master/fs/erofs` — mainline implementation (`erofs_fs.h` defines the on-disk structures)`https://en.wikipedia.org/wiki/EROFS` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ErofsFormatDescriptor` | `ErofsFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The one tunable the uncompressed writer honours: the volume label written into the superblock `volume_name` field (16 bytes) via `VolumeName` and read back as `ErofsReader.VolumeName`. The 4 KB block size is fixed by the FLAT_PLAIN/FLAT_INLINE layout, so it is not exposed. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Lays the image out again. Moving what is out of place beats writing the image out anew: EROFS lays a file's blocks out contiguously from the raw block address in its inode, so a move is the copy plus four bytes. The default this replaces offered start-packing only, through a rebuild. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | The superblock, inode and directory region is structure; each file's full blocks are the run its inode addresses. A short file whose tail is stored inline with its inode has no run of its own, and needs none. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single EROFS file as a bounded read-only stream. The reader produces the decoded file bytes; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length. | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | | - -#### `ErofsReader` - -Reads EROFS (Enhanced Read-Only File System) images as used by Android system/APEX partitions and produced by `mkfs.erofs`. Handles the uncompressed inode layouts (FLAT_PLAIN and FLAT_INLINE) for both compact (32-byte) and extended (64-byte) inodes; LZ4 / LZMA compressed clusters and fragments are deferred — an inode with a compressed datalayout surfaces as a zero-length / unsupported payload rather than failing the whole image. The superblock lives at file offset 1024; on-disk magic is the little-endian word `0xE0F5E1E2` (bytes `E2 E1 F5 E0`). Block size is `2^sb.blkszbits` (almost always 4096). A node id (`nid`) addresses a 32-byte granule measured from `meta_blkaddr * blockSize`, i.e. the inode lives at `meta_blkaddr * blockSize + nid * 32`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ErofsReader` | `ErofsReader(Stream stream)` | Reads an image straight from a seekable stream. | -| `ErofsReader` | `ErofsReader(byte[] data)` | | -| `Magic` | `const uint Magic` | On-disk superblock magic, little-endian word `0xE0F5E1E2`. | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `VolumeName` | `string VolumeName { get; }` | Volume label from the superblock `volume_name` field (16 bytes, NUL-trimmed ASCII). | -| `ExtractFile` | `byte[] ExtractFile(Entry entry)` | Extracts the raw bytes of a given entry. Throws `NotSupportedException` if the entry points at a compressed-layout inode (until LZ4 support lands). | -| `TryGetDataExtent` | `bool TryGetDataExtent(Entry entry, out long offset, out long length)` | Where an entry's full data blocks live: EROFS lays them out contiguously from the inode's raw block address. A residual tail stored inline with the inode is part of the metadata region, not of this run. Returns false when the inode has no out-of-line data at all. | - -#### `ErofsReader.Entry` - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Entry` | `Entry(string Path, long Size, bool IsDirectory, ulong Nid, bool IsSymlink = false, string LinkTarget = null)` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `IsSymlink` | `bool IsSymlink { get; init; }` | | -| `LinkTarget` | `string LinkTarget { get; init; }` | | -| `Nid` | `ulong Nid { get; init; }` | | -| `Path` | `string Path { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `ErofsWriter` - -Builds a valid, uncompressed EROFS image from a set of files and their (possibly nested) paths, matching the on-disk encoding produced by `mkfs.erofs` for plain data and accepted by `fsck.erofs`: extended (64-byte) inodes (`erofs_inode_extended`) so size, uid/gid, mtime and a full 32-bit link count are all expressible;the FLAT_INLINE datalayout: any residual tail (object size modulo block size) is stored inline immediately after the inode header, and only whole blocks spill into the data region. Objects smaller than one block carry their entire body inline with the block-address field set to the `0xFFFFFFFF` "no full block" sentinel — exactly as `mkfs.erofs` encodes small files;node ids (`nid`) as 32-byte granules measured from `meta_blkaddr * blockSize`; inodes are packed with their inline tails and the next inode is re-aligned to a 32-byte boundary. Directories are emitted as EROFS directory chunks: a contiguous array of 12-byte `erofs_dirent` headers followed by the packed entry names, with the conventional "." and ".." entries first. Directory bodies follow the same FLAT_INLINE rule. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ErofsWriter` | `ErofsWriter()` | | -| `VolumeName` | `string VolumeName { get; set; }` | Volume label written into the superblock `volume_name` field (16 bytes, NUL-padded; longer strings are truncated). Empty leaves the field zero. | -| `AddFile` | `void AddFile(string path, byte[] content)` | | -| `AddStreamingFile` | `void AddStreamingFile(string path, long size, Func openStream)` | Registers a file at the given archive path. Path segments are split on '/' and the intermediate directories are created on demand so nested layouts round-trip with their full directory chain intact. | -| `Build` | `byte[] Build()` | Produces the complete EROFS image as a byte array. | -| `SetUuid` | `void SetUuid(ReadOnlySpan uuid)` | Fixes the image's identity, for a build that has to come out the same twice. | -| `WriteTo` | `void WriteTo(Stream output)` | Writes the complete EROFS image to `output`. | - -### Namespace `FileSystem.ExFat` - -[`ExFatBlockMover`](#exfatblockmover) · [`ExFatEntry`](#exfatentry) · [`ExFatExtentMap`](#exfatextentmap) · [`ExFatFormatDescriptor`](#exfatformatdescriptor) · [`ExFatModifier`](#exfatmodifier) · [`ExFatReader`](#exfatreader) · [`ExFatRemover`](#exfatremover) · [`ExFatWriter`](#exfatwriter) - -#### `ExFatBlockMover` - -In-place exFAT block mover. Moves cluster-aligned extents and patches FAT chain entries, allocation bitmap, directory entry sets, and VBR PercentInUse. Streaming: never loads the whole image. All metadata updates are targeted writes with `Flush` barriers between the four steps so a crash mid-operation leaves the image in an fsck-recoverable state. The FAT (potentially 50 GB on a 50 TB volume) is navigated via `SectorCache` with a bounded ~256 MB memory cap. - -Implements `IFilesystemBlockMover`, `IFilesystemMetadataMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExFatBlockMover` | `ExFatBlockMover()` | | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | | -| `ClusterSize` | `int ClusterSize { get; }` | | -| `FirstDataByte` | `long FirstDataByte { get; }` | | -| `RelocatableMetadata` | `IReadOnlySet RelocatableMetadata { get; }` | The allocation bitmap and the up-case table. exFAT keeps both as ordinary files: each has a directory entry in the root recording its first cluster, which is the whole of what says where it is. The FAT and the boot region are pinned — their positions are fields in the boot sector, and rewriting those means recomputing the boot checksum sector as well, which is a different operation from repointing a file. The root directory is pinned for the same reason. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `SupportsScatteredRelink` | `bool SupportsScatteredRelink { get; }` | | -| `VolumeSize` | `long VolumeSize { get; }` | Upper bound of the exFAT volume as declared by the VBR — clusterHeapOffset + clusterCount × clusterSize. The defrag planner must use THIS as its "imageSize" rather than the stream length: when the exFAT image sits inside a larger container (partition window, sparse VHD), the stream length includes padding bytes that are outside the volume. Targeting offsets above this bound corrupts the FAT (cluster N's entry lives at fatOffset + N*4 — large N writes into the cluster heap). | -| `Init` | `void Init(Stream image)` | Stream-based init — reads only the 512-byte VBR. | -| `Init` | `void Init(byte[] image)` | Initialises the mover by parsing exFAT VBR from a byte buffer. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldBlockOffsets, IReadOnlyList newBlockOffsets, IReadOnlySet blocksLiveElsewhere)` | Rewrites one file's whole allocation in a single pass, after every byte has moved. | -| `UpdateMetadataAfterMove` | `void UpdateMetadataAfterMove(Stream image, string metadataName, long oldOffset, long newOffset, long length, IReadOnlyList> liveRanges = null)` | | - -#### `ExFatEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExFatEntry` | `ExFatEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `ExFatExtentMap` - -Walks an exFAT image and yields its actual on-disk byte layout — the reserved boot region (VBR + backup VBR + OEM parameters), the FAT, every cluster-chain run per file, and the free-cluster set. Honours the FAT-chain bypass bit (NoFatChain) for contiguous extent shortcuts. Streaming: reads only the VBR + dir clusters from disk. FAT navigation flows through a `SectorCache` so a 50 TB exFAT image with a 50 GB FAT keeps memory bounded to ~256 MB. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | Single-pass walker. Parses the VBR, then for each directory entry set (File 0x85 + Stream 0xC0 + Name 0xC1) walks the FAT chain (or the contiguous range when `GeneralSecondaryFlags.NoFatChain` is set), emitting one `DefragBlockInfo` per contiguous run. | - -#### `ExFatFormatDescriptor` - -References: `https://learn.microsoft.com/en-us/windows/win32/fileio/exfat-specification` — Microsoft's official exFAT file system specification`https://github.com/torvalds/linux/tree/master/fs/exfat` — mainline kernel implementation`https://en.wikipedia.org/wiki/ExFAT` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExFatFormatDescriptor` | `ExFatFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunables surfaced by the Convert Archive dialog / CLI for exFAT creation: image size (Auto / floppy-to-card presets), volume label (written as a Volume Label Directory Entry, type 0x83), and cluster size. Auto sizing runs the layout optimiser over the file set; an empty label still emits the entry with character count 0 to match Windows' format.com behaviour. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files to an existing exFAT image. Uses `ExFatModifier` for true O(touched bytes) random-access I/O — only the FAT entries for new clusters, the allocation-bitmap byte(s) covering them, the root-directory cluster(s) holding the entry-set, the new file's data clusters, and the VBR PercentInUse byte are touched. The up-case table and all other files are never read. | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation: pre-known per-input sizes drive the cluster geometry in pass 1; pass 2 emits the boot region, FAT, allocation bitmap, up-case table and directory tree with empty file clusters, then streams each input's bytes from its `OpenStream` factory into the pre-allocated cluster run via 64 KB chunks. Cluster tails past each entry's exact `Size` stay sparse-zero. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware exFAT defragmentor. Supports planner-driven in-place path and falls back to legacy rebuild path. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the VBR + FAT + cluster heap and yields the actual on-disk layout — VBR/backup VBR + FAT region as MetadataReserved, allocation bitmap + up-case table as MetadataReserved, every file's cluster-chain run (or the contiguous range when `NoFatChain` is set) as Used, and the un-owned cluster gaps as Free. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes files from an existing exFAT image with full secure wipe (cluster bytes, FAT chain, allocation bitmap bits, directory entry set). Uses `ExFatModifier` for O(touched bytes) random-access I/O — no forensic recovery of the removed content is possible from the resulting bytes. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the exFAT image: free clusters, cluster-tip slack (the bytes between a file's real size and the end of its last allocated cluster), and any gaps outside the reserved/FAT/heap-used regions. Driven by the generic `UnusedSpaceWiper` over the exFAT extent map, with a directory-entry-based file-size lookup for cluster-tip precision. | - -#### `ExFatModifier` - -In-place exFAT modifier — true O(touched bytes) random-access I/O. Touches only: VBR primary+backup (3 bytes — PercentInUse), the FAT entries for the new/freed clusters, the allocation-bitmap byte(s) covering those clusters, the root-directory cluster(s) holding the entry-set, and the new file's data clusters. The up-case table and other files are never read. Layout reminders (matches `ExFatWriter`): VBR at sector 0; backup VBR at sector 12.FAT starts at `fatOffsetSectors`; 4 bytes per cluster, EOC = 0xFFFFFFFF.Cluster heap at `clusterHeapOffsetSectors`; cluster numbering starts at 2.Cluster 2 = root dir, cluster 3 = allocation bitmap, cluster 4 = up-case table.Root entry-set order: 0x83 VolumeLabel, 0x81 AllocationBitmap, 0x82 UpCase, then files.Per-file entry-set: 0x85 File + 0xC0 StreamExtension + N × 0xC1 FileName (15 UTF-16 chars each).Entry-set checksum per spec §7.4.3 — rotate-right-add over every byte except bytes 2-3 of the File entry. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds a file with O(touched bytes) I/O. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes a named file with O(touched bytes) I/O. Returns false if not found. | - -#### `ExFatReader` - -Reads exFAT filesystem images. Parses VBR, FAT, and directory entry sets (File 0x85 + Stream Extension 0xC0 + File Name 0xC1). Supports subdirectories. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExFatReader` | `ExFatReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(ExFatEntry entry)` | | - -#### `ExFatRemover` - -Secure-remove implementation for exFAT images. Finds a root-directory file's entry set (File `0x85` + Stream Extension `0xC0` + N × File Name `0xC1`), zeros every cluster in its allocation chain, clears its FAT entries, clears its bits in the allocation bitmap, and wipes the directory entry set itself — preserving only each entry's first byte with its type bit (bit 7) cleared so exFAT readers treat the slots as "unused in-use" instead of end-of-directory. Root-directory-only for now; nested-directory removal is a follow-up. No set-checksum update is needed on removed entries — a cleared type bit makes readers skip them entirely, including their checksum field. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Remove` | `static void Remove(byte[] image, string fileName)` | Removes `fileName` from the in-memory exFAT image. Throws `FileNotFoundException` if no root-dir entry matches. The image is modified in place. | - -#### `ExFatWriter` - -Builds exFAT filesystem images that Windows 10+ actually mounts. Default layout: 8 MB image, 512 B/sector, 8 sectors/cluster (4 KB clusters). VBR at sector 0, backup VBR at sector 12, FAT at sector 24, cluster heap thereafter; cluster 2 = root, cluster 3 = allocation bitmap, cluster 4 = up-case table. Key real-world fixes over the original implementation: Set-checksum on each File directory entry set (required — Windows silently ignores files whose set-checksum is wrong), up-case table checksum, timestamps on create/modify/access, volume serial number, filesystem revision (1.0), stream-extension GeneralSecondaryFlags advertising FAT-chain allocation. These are the fields fsck/chkdsk and `diskutil`/`fsck_exfat` audit before declaring the volume clean. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExFatWriter` | `ExFatWriter()` | | -| `DeclaredVolumeBytes` | `long DeclaredVolumeBytes { get; }` | Declared volume size in bytes of the most recent build. `BuildCore` materialises only the written prefix, so a caller holding that prefix must extend its output to this length; the free space past the prefix is sparse zeros. | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a streaming file: its `size` is known up front (so the writer can plan cluster geometry), but its bytes are fetched on demand from `openStream` during `BuildToStreaming`. Never buffered in memory by the writer. | -| `BuildAutoSized` | `byte[] BuildAutoSized(int requestedClusterBytes = 0, string volumeLabel = null)` | Builds the exFAT image using the smallest size that fits all files, with the cluster size chosen by `FilesystemLayoutOptimizer` to minimise internal slack + FAT overhead. | -| `BuildToStreaming` | `void BuildToStreaming(Stream output, int requestedClusterBytes = 0, string volumeLabel = null)` | Two-pass streaming Build: pass 1 derives cluster geometry from the declared sizes of `AddStreamingFile` entries; pass 2 emits the boot region + FAT + allocation bitmap + up-case table + directory tree (file-data clusters left zero), then streams each entry's bytes from its factory straight into its allocated cluster run via 64 KB chunks. Cluster tail past each entry's exact `Size` stays sparse zero (the in-memory disk byte[] was zero-initialised and the per-entry stream copy never reads past the entry's logical size). | -| `BuildTo` | `void BuildTo(Stream output, int totalSizeMB = 8, int requestedClusterBytes = 0, string volumeLabel = null)` | Writes the volume to `output`, emitting only the region that actually carries data and then extending the stream to the declared size. Free space costs nothing, so volumes far past the in-memory limit are producible. | -| `Build` | `byte[] Build(int totalSizeMB = 8, int requestedClusterBytes = 0, string volumeLabel = null)` | Builds the exFAT image. | - -### Namespace `FileSystem.Ext` - -[`ExtBlockMover`](#extblockmover) · [`ExtEntry`](#extentry) · [`ExtExtentMap`](#extextentmap) · [`ExtFormatDescriptor`](#extformatdescriptor) · [`ExtInPlaceShrinker`](#extinplaceshrinker) · [`ExtInPlaceShrinker.ShrinkResult`](#extinplaceshrinkershrinkresult) · [`ExtModifier`](#extmodifier) · [`ExtModifier.InPlaceUnsupportedException`](#extmodifierinplaceunsupportedexception) · [`ExtReader`](#extreader) · [`ExtRemover`](#extremover) · [`ExtShrinkHelper`](#extshrinkhelper) · [`ExtShrinkHelper.ShrinkResult`](#extshrinkhelpershrinkresult) · [`ExtWriter`](#extwriter) · [`ExtWriter.ExtVersion`](#extwriterextversion) - -#### `ExtBlockMover` - -In-place ext2/3/4 block mover. Moves block-aligned extents within an ext image and patches inode block pointers, block bitmap, and group descriptor free counts. Streaming: the image is never loaded whole. Reads go through a `SectorCache`; metadata updates (inode block pointers, bitmap bits) are targeted single-region writes with `Flush` barriers between steps so a crash mid-update leaves the image in an fsck-recoverable state. Scope: single-cylinder-group profile (matches what `ExtWriter` emits). Multi-group ext4 (required for 50 TB volumes created elsewhere) needs additional work — walk the BGD table for the target block's group rather than assuming group 0. - -Implements `IFilesystemBlockMover`, `IFilesystemMetadataMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtBlockMover` | `ExtBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | | -| `FirstDataByte` | `long FirstDataByte { get; }` | | -| `RelocatableMetadata` | `IReadOnlySet RelocatableMetadata { get; }` | Each group's block bitmap, inode bitmap and inode table. All three are located by fields in that group's descriptor, so moving one is a matter of writing the new block number there — which is how a real resize2fs shifts them about. The superblock, the descriptor table and their backups are pinned: their positions are computed from the geometry, not recorded. | -| `Init` | `void Init(Stream image)` | Streaming init — reads only the superblock + first BGD (~2 KB total). | -| `Init` | `void Init(byte[] image)` | Initialises the mover from a byte buffer (legacy callers). | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length, bool releaseOldSpace)` | | -| `UpdateMetadataAfterMove` | `void UpdateMetadataAfterMove(Stream image, string metadataName, long oldOffset, long newOffset, long length, IReadOnlyList> liveRanges = null)` | | - -#### `ExtEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtEntry` | `ExtEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `IsSymlink` | `bool IsSymlink { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `LinkTarget` | `string LinkTarget { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `ExtExtentMap` - -Walks an ext2/3/4 image and yields its actual on-disk byte layout — per-file extent runs (one `DefragBlockInfo` per contiguous block range) plus metadata regions (superblock, group descriptors, block + inode bitmaps, inode table). Used by the defragment window's block-map preview. Streaming: never loads the whole image. All reads flow through a `SectorCache` so multi-TB ext4 images (a 50 TB volume's BGD table + bitmaps are tens of MB) work without OOM. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | Single-pass walker. Parses superblock + BGD table; emits the metadata regions (SB, BGDT, block bitmap, inode bitmap, inode table) of every group as `MetadataReserved` extents; walks the directory tree from inode 2 and emits one extent per contiguous data-block run per file. | - -#### `ExtFormatDescriptor` - -References: `https://docs.kernel.org/filesystems/ext4/index.html` — the kernel's ext4 on-disk layout documentation (superblock, group descriptors, inodes, extents; ext2/3 are subsets)`https://e2fsprogs.sourceforge.net/ext2intro.html` — Card/Ts'o/Tweedie, "Design and Implementation of the Second Extended Filesystem"`https://github.com/tytso/e2fsprogs` — e2fsprogs, the canonical userspace implementation`https://en.wikipedia.org/wiki/Ext4` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtFormatDescriptor` | `ExtFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunables surfaced by the Convert Archive dialog / CLI for ext creation — revision (ext2/3/4), block size, optional journal toggle (gated on the revision selector via DependsOn), volume label, and inode size. The Journal knob is hidden in the UI for ext2 (which has no journal); for ext3/ext4 it defaults to enabled to match mkfs.ext{3,4} convention. | -| `ReclaimSupport` | `LayoutReclaim ReclaimSupport { get; }` | ext records an absent block as a zero pointer, so runs of zeros need not be allocated at all; and it counts the directory entries naming an inode, so identical files can share one copy under several names. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing ext2/3/4 image. Uses `ExtModifier` for true O(touched bytes) random-access I/O — only the superblock, BGD entry, block + inode bitmaps, the affected inode slot, the root dir block, and the file's data blocks are read or written. | -| `AnalyzeLayout` | `LayoutAnalysis AnalyzeLayout(Stream image)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation: pre-known per-input sizes drive ext block group sizing in pass 1; pass 2 emits superblock + BGD + bitmaps + inode table + directory blocks with file data blocks left zero, then streams each input's bytes from its `OpenStream` factory into its first allocated block via 64 KB chunks. Block tail past each entry's exact `Size` stays sparse-zero. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware ext2/3/4 defragmentor. Supports planner-driven in-place path (using `DefragPlanner` + `ExtBlockMover`) and the legacy rebuild path (using `DefragRebuilder`). | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the superblock + BGD table + inode tree and yields the actual on-disk byte layout — every metadata region (SB, BGDT, block + inode bitmaps, inode tables) plus one extent per contiguous block run per file (coalesced for direct/indirect pointers; native ext4 extent runs surface as-is). Used by the defragment window's block-map preview. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `PatchInPlace` | `void PatchInPlace(Stream image, LayoutPatch patch)` | | -| `RebuildStreaming` | `void RebuildStreaming(Stream source, Stream target, LayoutRebuildOptions options)` | | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Securely removes files from an existing ext2/3/4 image. Uses `ExtModifier` for O(touched bytes) random-access I/O — file data blocks are wiped during removal so no forensic trace remains. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | Genuine in-place ext shrink: trims trailing free blocks via `ExtInPlaceShrinker` (updating bitmap / descriptors / superblock / backups / checksums; every surviving block stays byte-identical). Falls back to the `IArchiveShrinkable` default (verified rebuild / copy-through) when the in-place path declines — e.g. a target that would need genuine block relocation or block-group removal. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the ext2/3/4 image: free blocks, block-tip slack (the bytes between a file's real size and the end of its last allocated block), and any gaps outside the metadata regions. Driven by the generic `UnusedSpaceWiper` over the ext extent map, with an inode-size-based file-size lookup for block-tip precision. | - -#### `ExtInPlaceShrinker` - -Genuine in-place ext2/3/4 volume shrink. Frees the blocks above the new boundary, updating the block bitmap, the block group descriptor free count, the superblock `s_blocks_count` / `s_free_blocks_count` (and their 64-bit hi halves), the scaled reserved-block count, every sparse_super backup superblock + GDT, and recomputing crc32c/crc16 metadata checksums where the volume enables them — then truncating the image. Work is `O(metadata touched + bytes relocated)`: surviving blocks stay byte-identical and only the data blocks that sit above the boundary are physically moved, so this is a true in-place edit and not a re-pack. Two paths. When no referenced block sits at or above the new boundary the shrink is a pure trailing-free trim that relocates nothing. When referenced data blocks do sit above the boundary the shrinker relocates whole runs down into free space below the boundary (via `ExtBlockMover`, which copies the block bytes and patches the owning inode's direct pointers / depth-0 extent leaves + the block bitmap), then applies the same geometry trim.Supported relocation shapes. A single-block-group volume whose above-boundary files are direct-block-only (no indirect blocks) or use a depth-0 extent tree (extents live inline in the inode; no interior/index nodes). Whole runs move as a unit so an extent's length stays correct.Refused (→ `NotSupportedException`, caller rebuilds). Multi-group volumes (the mover's inode lookup assumes group 0); any above-boundary file that uses indirect blocks or an extent tree of depth > 0 (the mover cannot relocate those metadata blocks); a target that would drop a whole block group or fall below the metadata floor; and a target with insufficient free space below the boundary to hold every relocated run. Refusing rather than emitting an image the e2fsck oracle rejects keeps correctness over coverage.`ShrinkToFit` always succeeds (it picks the boundary one past the highest in-use block, so no relocation is ever needed). An explicit over-tight `ShrinkToBlocks` target is what drives relocation — or a refusal when the shape is out of scope. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinkToBlocks` | `static ShrinkResult ShrinkToBlocks(Stream image, uint targetBlocks)` | Shrinks an ext image in place to exactly `targetBlocks` blocks. | -| `ShrinkToFit` | `static ShrinkResult ShrinkToFit(Stream image)` | Shrinks an ext image in place to the smallest block count that still holds the current allocation (auto-fit), relocating trailing in-use blocks down. | - -#### `ExtInPlaceShrinker.ShrinkResult` - -Result of an ext shrink attempt: the before/after byte sizes and how much was physically rewritten. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinkResult` | `ShrinkResult(long OriginalSize, long NewSize, long BytesRelocated, long BlocksRelocated)` | Result of an ext shrink attempt: the before/after byte sizes and how much was physically rewritten. | -| `BlocksRelocated` | `long BlocksRelocated { get; init; }` | | -| `BytesRelocated` | `long BytesRelocated { get; init; }` | | -| `NewSize` | `long NewSize { get; init; }` | | -| `OriginalSize` | `long OriginalSize { get; init; }` | | -| `WasReduced` | `bool WasReduced { get; }` | True when the image was actually made smaller. | - -#### `ExtModifier` - -In-place ext2/3/4 modifier. Performs O(touched bytes) random-access I/O against an ext image: only the superblock, the relevant block-group descriptors, the block + inode bitmaps of the touched groups, the affected inode slots, the root directory's data blocks (plus any newly-grown directory block), and the file's own data/metadata blocks are read and written. Genuine in-place coverage (no whole-image re-pack):Large files — ext2/3 single + double + triple indirect blocks; ext4 inode-resident extent leaves (when the inode carries the EXTENTS flag and the volume advertises the EXTENTS feature). Block allocation, i_blocks/i_size, group-descriptor + superblock free counts all maintained.Bigger directories — when the root directory's blocks are full a new linear directory block is appended (i_size and the dir's block map grow). htree (EXT4_INDEX) directories are detected and routed to the rebuild fallback.Multiple block groups — allocation scans every group with free space; the right group's descriptor + bitmaps (and, when `metadata_csum` / `uninit_bg` is set, their checksums and the INODE/BLOCK_UNINIT flags + `itable_unused`) are updated.Checksums — when `metadata_csum` is set: crc32c bitmap, inode, group-descriptor and superblock checksums are recomputed; when the older `gdt_csum` (uninit_bg) is set the crc16 group-descriptor checksum is used. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds (or fails if an entry of the same name already exists) a file inside an existing ext2/3/4 image, genuinely in place. | -| `Mutate` | `static void Mutate(Stream archive, IReadOnlyList> replacements, IReadOnlyCollection deletions)` | | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes the named entry from an existing ext image, in place. Returns false if no entry with that name exists in the root directory. | - -#### `ExtModifier.InPlaceUnsupportedException` - -Thrown when a case genuinely cannot be handled in place (e.g. htree directory growth, or a nested target path). Callers may fall back to a rebuild on this. - -Inherits `IOException`. Implements `ISerializable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `InPlaceUnsupportedException` | `InPlaceUnsupportedException(string message)` | Thrown when a case genuinely cannot be handled in place (e.g. htree directory growth, or a nested target path). Callers may fall back to a rebuild on this. | - -#### `ExtReader` - -Reads ext2/ext3/ext4 filesystem images. Parses the superblock, block group descriptors, inode table, and directory entries. Supports both direct/indirect block pointers (ext2/3) and extent trees (ext4). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtReader` | `ExtReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `ExtractTo` | `void ExtractTo(ExtEntry entry, Stream destination)` | Copies `entry`'s bytes into `destination` without buffering the whole file, which an entry approaching ext's 4 GB i_size ceiling would not survive. | -| `Extract` | `byte[] Extract(ExtEntry entry)` | | - -#### `ExtRemover` - -Secure-remove implementation for ext2 images produced by `ExtWriter`. Finds the named file in the root directory (inode 2), zeros every data block the file occupies (trailing block-tip slack past `i_size` is included because we zero whole blocks), zeros the inode, clears the corresponding bits in the block and inode bitmaps, wipes the directory entry bytes, and updates the free-space bookkeeping in both the superblock and the block group descriptor. After the operation no bytes of the original filename or content remain recoverable. Scope: root-directory-only; only direct block pointers are supported (files up to `12 * blockSize` bytes — matching the range `ExtWriter` can create). Indirect, double-indirect, and triple-indirect blocks are NOT traversed here; if encountered we throw to prevent a half-wiped file. Dirent strategy: rather than stitch the victim's `rec_len` into the previous entry's record, we clear the dirent bytes and set the `inode` field of the entry to zero. Our `ExtReader` stops iterating at a zero-inode slot; that truncates enumeration of anything that follows in the same directory block but satisfies the "no forensic trace" contract. For the descriptor's `Add`-then-`Remove` usage pattern the file being removed will typically be the last entry, so the truncation is harmless. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Remove` | `static void Remove(byte[] image, string fileName)` | Removes `fileName` from the in-memory ext2 image. Throws `FileNotFoundException` if no root-dir entry matches. The image is modified in place. | - -#### `ExtShrinkHelper` - -Shrinks an ext2/3/4 filesystem image by defragmenting (consolidate at start) and then truncating trailing free blocks. Updates the superblock s_blocks_count and the BGD free-block count to reflect the reduced geometry. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Shrink` | `static ShrinkResult Shrink(Stream image)` | Shrinks an ext2/3/4 image by extracting all files, then rebuilding with a minimal total-blocks count, and finally updating the superblock metadata. This is simpler and more reliable than defrag-then-truncate because the ExtWriter always produces a tightly-packed image. | - -#### `ExtShrinkHelper.ShrinkResult` - -Result of an ext shrink operation: original and new sizes, plus whether the image was actually reduced. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinkResult` | `ShrinkResult(long OriginalSize, long NewSize, bool WasReduced)` | Result of an ext shrink operation: original and new sizes, plus whether the image was actually reduced. | -| `NewSize` | `long NewSize { get; init; }` | | -| `OriginalSize` | `long OriginalSize { get; init; }` | | -| `WasReduced` | `bool WasReduced { get; init; }` | | - -#### `ExtWriter` - -Builds minimal ext2 filesystem images from scratch. Uses 1024-byte blocks by default with a single block group. Files are stored using direct block pointers. Produces fsck-clean output: free-block/free-inode counts, used-dirs count, inode link counts, inode i_blocks (sector tally), and all three inode timestamps are populated so that `dumpe2fs` / `e2fsck` do not report inconsistencies. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ExtWriter` | `ExtWriter()` | | -| `DeduplicateWithLinks` | `bool DeduplicateWithLinks { get; set; }` | Store one copy of files whose bytes are identical and give the rest a second name for it. | -| `MakeSparse` | `bool MakeSparse { get; set; }` | Store a file's runs of zeros as holes rather than allocating blocks for them. | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a streaming file: `size` drives extent + inode + block-group sizing in pass 1; bytes are pulled from `openStream` in pass 2 of `BuildToStreaming`. Never buffered as `byte[]`. | -| `BuildAutoSized` | `byte[] BuildAutoSized(int requestedBlockSize = 0)` | Builds the image with the block size chosen by `FilesystemLayoutOptimizer` to minimise slack + metadata overhead, and the block count sized to exactly hold the files. | -| `BuildAutoSized` | `byte[] BuildAutoSized(int requestedBlockSize, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Auto-sizes the volume to the files added, honouring the requested version, journal, label and inode size. | -| `BuildToStreamingAutoSized` | `void BuildToStreamingAutoSized(Stream output, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Two-pass streaming Build with auto-sized geometry. | -| `BuildToStreamingAutoSized` | `void BuildToStreamingAutoSized(Stream output, int requestedBlockSize, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Two-pass streaming Build with auto-sized geometry and a caller-chosen block size. | -| `BuildToStreaming` | `void BuildToStreaming(Stream output, int blockSize, int totalBlocks, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Two-pass streaming Build: pass 1 derives block-group geometry from the declared sizes of `AddStreamingFile` entries; pass 2 emits the superblock + BGD + bitmaps + inode table + directory blocks with file data blocks left zero, then streams each entry's bytes from its factory into its first allocated block via 64 KB chunks. Block tail past each entry's exact `Size` stays sparse-zero. | -| `BuildTo` | `void BuildTo(Stream output, int blockSize, int totalBlocks, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Lays the volume out and writes it straight into a seekable stream. Only the blocks the filesystem actually touches are ever resident, so a volume larger than a byte[] can address is written without being materialised. | -| `Build` | `byte[] Build(int blockSize = 1024, int totalBlocks = 4096)` | Legacy two-argument `Build()` overload — emits the historical minimal ext2 layout (dynamic-rev superblock with FILETYPE only, 128-byte inodes, no journal, no extents, no 64BIT). Kept byte-compatible with the upstream writer so `ExtModifier`, `BuildAutoSized`, the external-conformance tests, and the version detector (which classifies the image by feature flags) all observe the same ext2 baseline this writer has always produced. The verbose `Build(int, int, ExtVersion, bool, string, int)` overload — invoked from the descriptor's Create() — drives the new ext3/ext4 paths. | -| `Build` | `byte[] Build(int blockSize, int totalBlocks, ExtVersion version, bool journal, string volumeLabel, int inodeSize)` | Builds an ext2/3/4 filesystem image with caller-selected revision, block size, journal flag, volume label, and inode size. The default overload (above) keeps the historical "minimal ext4 image" behaviour; the verbose overload is invoked by the format descriptor's Create() once it has resolved the user-supplied options. | -| `SelectOptimalBlockSize` | `int SelectOptimalBlockSize(int inodeSize = 128)` | Picks the block size (bytes) that minimises file-tail slack plus the ext metadata footprint (superblock + group descriptor + block/inode bitmaps + inode table) for the current file-set, via the shared `LayoutOptimizerAdapter`. Every candidate is a legal ext block size, so the chosen image always round-trips. | - -#### `ExtWriter.ExtVersion` - -ext filesystem revision selector used by the writer's `Build` overload. Drives the feature-flag set in the superblock — ext2 leaves HAS_JOURNAL/EXTENTS/64BIT clear; ext3 adds HAS_JOURNAL + a journal inode; ext4 adds EXTENTS + 64BIT on top. - -| Value | Numeric | Summary | -| --- | --- | --- | -| `Ext2` | `0` | | -| `Ext3` | `1` | | -| `Ext4` | `2` | | - -### Namespace `FileSystem.Ext1` - -[`Ext1BlockMover`](#ext1blockmover) · [`Ext1Entry`](#ext1entry) · [`Ext1ExtentMap`](#ext1extentmap) · [`Ext1FormatDescriptor`](#ext1formatdescriptor) · [`Ext1Modifier`](#ext1modifier) · [`Ext1Reader`](#ext1reader) · [`Ext1Writer`](#ext1writer) - -#### `Ext1BlockMover` - -In-place ext1 block mover. Moves block-aligned extents within an ext1 image and patches inode block pointers + block bitmap so the file remains reachable. Streaming: the image is never loaded whole. Reads go through a `SectorCache`; metadata updates (inode block pointers, bitmap bits) are targeted single-region writes with `Flush` barriers between steps so a crash mid-update leaves the image in an fsck-recoverable state. Scope: ext1 is rev-0 only (no extents, no FILETYPE, 128-byte inodes, single-CG profile in our writer). - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ext1BlockMover` | `Ext1BlockMover()` | | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | | -| `BlockSize` | `int BlockSize { get; }` | | -| `FirstDataByte` | `long FirstDataByte { get; }` | | -| `SupportsScatteredRelink` | `bool SupportsScatteredRelink { get; }` | | -| `Init` | `void Init(Stream image)` | Streaming init — reads only the superblock + first BGD (~1 KB total). | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldBlockOffsets, IReadOnlyList newBlockOffsets, IReadOnlySet blocksLiveElsewhere)` | Rewrites one file's whole allocation once every byte has moved. | - -#### `Ext1Entry` - -Single entry returned by `Ext1Reader`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ext1Entry` | `Ext1Entry()` | | -| `Inode` | `uint Inode { get; init; }` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `Ext1ExtentMap` - -Walks an ext1 image and yields its actual on-disk byte layout — per-file block-pointer runs plus metadata regions (superblock, BGD table, block + inode bitmaps, inode table). ext1 is rev-0 only: 128-byte inodes, no extents, 8-byte directory header with 16-bit name_len. Used by the defragment window's block-map preview. Streaming: never loads the whole image. All reads flow through a `SectorCache` so multi-GB ext1 images work without OOM. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `Ext1FormatDescriptor` - -Descriptor for ext1 filesystem images — the 1992 predecessor of ext2 by Rémy Card. ext1's on-disk superblock layout is identical to the GOOD_OLD-revision ext2 superblock with one crucial difference: the s_magic field at offset 56 of the superblock (file-relative offset 1080) reads `0xEF51` instead of ext2's `0xEF53`. ext1 has no journal, no extents, and no FEATURE_INCOMPAT_FILETYPE — directory entries are 8-byte fixed-header (with a 16-bit `name_len`) + name only. Detection, structural surfacing and round-trip read+write of small WORM images are supported; vintage pre-1993 Linux disk images and forensic tooling for early Linux installs are the consumers. References: `https://e2fsprogs.sourceforge.net/ext2intro.html` — Card/Ts'o/Tweedie, "Design and Implementation of the Second Extended Filesystem", which documents the original ext it replaced`https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/` — historic kernel trees whose `fs/ext` is the primary source for the 1992 layout`https://en.wikipedia.org/wiki/Extended_file_system` — Wikipedia article on the original ext - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ext1FormatDescriptor` | `Ext1FormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | The single tunable ext1 honours: the on-disk block size (`s_log_block_size`). 1024/2048/4096 bytes are the legal rev-0 values; the 4 MiB image footprint stays constant across the choice. ext1 is the GOOD_OLD revision and stores no volume name (`s_volume_name` only exists in the dynamic revision), so no label knob is offered. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Adds (or replaces by name) files inside an existing Ext1 image. Uses `Ext1Modifier` for true O(touched bytes) random-access I/O — only the superblock, BGD entry, block + inode bitmaps, the affected inode slot, the root dir block, and the file's data blocks are read or written. | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Streaming creation: each input's length settles the layout, then its bytes are copied into the blocks it was allocated, so an entry past what a byte[] can hold never has to be materialised. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware ext1 defragmentor via read-extract-rebuild dispatch through `DefragRebuilder`. The writer emits a fresh contiguous-from-start rev-0 layout at the source volume's own block size and block count -- the canonical 4 MiB footprint WriteTo produces only fits a few megabytes, so rebuilding into it dropped everything a larger volume held. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the rev-0 superblock + BGD table + inode tree and yields the actual on-disk byte layout — every metadata region (SB, BGDT, block + inode bitmaps, inode table) plus one extent per contiguous block run per file. Used by the defragment window's block-map preview. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `RebuildStreaming` | `void RebuildStreaming(Stream source, Stream target, LayoutRebuildOptions options)` | Re-lays the volume out with the requested geometry. The generic default wrote the synthetic entries back as files, so the rebuilt volume listed more entries than the original and the rebuild was refused. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes the named entries from an existing Ext1 image. Uses `Ext1Modifier` for O(touched bytes) random-access I/O — file data blocks are wiped during removal so no forensic trace remains. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the ext1 image: free blocks, inter-file gaps and the block-tip slack between a file's logical size and the end of its last allocated 1024-byte block. The extent map clamps each file's run to its logical byte length, so any trailing slack inside the final block presents as a free gap that the generic `UnusedSpaceWiper` zero-fills. A directory-path-keyed size lookup makes the explicit cluster-tip pass exact for the (rare) case where an extent reports a block-rounded length. | - -#### `Ext1Modifier` - -In-place ext1 modifier — same blueprint as `D81Modifier`, adapted for the ext1 / GOOD_OLD_REV layout. Performs O(touched bytes) random-access I/O against an ext1 image: only the superblock, the BGD entry, the block bitmap, the inode bitmap, the affected inode slots, the root directory's data block, and the file's own data blocks are read and written. Layout reminders (matching `Ext1Writer`'s default geometry): Block size 1024, single block group, direct block pointers only (max 12 blocks = 12 KiB per file — same ceiling as the writer).Superblock at file offset 1024 (magic `0xEF51` at +56).BGD at block (firstDataBlock+1), block bitmap at (firstDataBlock+2), inode bitmap at (firstDataBlock+3), inode table at (firstDataBlock+4).Root inode is inode 2; root dir is one direct block of rev-0 dirents.Inodes 1..10 reserved; user inodes start at 11. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(Stream image, string name, byte[] data)` | Adds (or fails if an entry of the same name already exists) a file inside an existing ext1 image. Touches only the superblock, BGD entry, block + inode bitmaps, the new inode slot, the root dir block, and the new data blocks. | -| `RemoveFile` | `static bool RemoveFile(Stream image, string name, bool wipeData = true)` | Removes the named entry from an existing ext1 image. Touches only the metadata blocks plus (optionally) the data blocks of the removed file. Returns false if no entry with that name exists in the root directory. | - -#### `Ext1Reader` - -Reads ext1 (1992) filesystem images — the predecessor of ext2 by Rémy Card. Identical to GOOD_OLD-revision ext2 byte-for-byte except: Magic at superblock offset 56 is `0xEF51` (not `0xEF53`).Directory entries use rev-0 layout: `inode(4) + rec_len(2) + name_len(2) + name[]` — the 16-bit `name_len` is NOT split into `name_len(8) + file_type(8)`.Inodes are a fixed 128 bytes (no `s_inode_size` field — rev-0 does not honour dynamic-rev fields). Only direct + indirect block pointers are honoured (no extents, since extents arrived with ext4). Use `Ext1Reader` for full file content extraction; the broader `Ext1FormatDescriptor` still surfaces a `FULL.ext1` + metadata view. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ext1Reader` | `Ext1Reader(Stream stream)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Dispose` | `void Dispose()` | | -| `ExtractTo` | `void ExtractTo(Ext1Entry entry, Stream destination)` | Copies `entry`'s bytes into `destination` without buffering the whole file, which an entry approaching ext1's 4 GB i_size ceiling would not survive. | -| `Extract` | `byte[] Extract(Ext1Entry entry)` | | - -#### `Ext1Writer` - -Builds minimal ext1 (1992) filesystem images from scratch — the predecessor of ext2 by Rémy Card. The on-disk superblock layout is identical to GOOD_OLD-revision ext2 byte-for-byte except for the magic value (`0xEF51` instead of ext2's `0xEF53`) at offset 1080 of the file. Differences from the ext2 writer: Magic: `0xEF51`.`s_rev_level` = 0 (GOOD_OLD_REV) — no dynamic-rev fields (`s_first_ino`, `s_inode_size`, feature flags) are honoured.Inodes are a fixed 128 bytes (no `s_inode_size` field).No journal, no extents, no FILETYPE feature.Directory entries use the rev-0 layout: `inode(4) + rec_len(2) + name_len(2) + name[]` — the 16-bit `name_len` is NOT split into `name_len(8) + file_type(8)` as in rev-1 with FILETYPE. No `mkfs.ext1` exists — ext1's magic was retired in 1993, so no Linux validator can mount or fsck the resulting images. Tests verify our reader can round-trip the output. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Ext1Writer` | `Ext1Writer()` | | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a file to be packed into the next `Build` call. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a file whose bytes are produced on demand. `size` must match what `openStream` yields; the layout is settled from it before a byte is read, so a file larger than a byte[] can carry is placed like any other. | -| `BuildTo` | `void BuildTo(Stream output, int blockSize, int totalBlocks)` | Writes the volume into a seekable stream: the metadata, then each file's bytes at the blocks it was allocated. Only the blocks the filesystem touches are held, so a volume larger than a byte[] can address is producible. | -| `Build` | `byte[] Build(int blockSize = 1024, int totalBlocks = 4096)` | Materialises a complete ext1 image as a byte array. Default geometry produces a 4 MiB image with 1024-byte blocks (`s_log_block_size` = 0) and a single block group — the canonical layout for early-1990s small partitions. | -| `PlanTotalBlocks` | `int PlanTotalBlocks(int blockSize)` | Block count a volume needs to hold the files added, at the given block size. The 4 MiB default footprint only fits a few megabytes of payload, so anything larger has to be sized from the file set. | -| `WriteTo` | `void WriteTo(Stream output, int blockSize = 1024)` | Materialises the image and writes it to the given stream. The optional `blockSize` selects the 1024/2048/4096-byte block size (`s_log_block_size`); the total image is sized to a constant 4 MiB so larger blocks mean fewer total blocks. | - -### Namespace `FileSystem.F2fs` - -[`F2fsBlockMover`](#f2fsblockmover) · [`F2fsEntry`](#f2fsentry) · [`F2fsFormatDescriptor`](#f2fsformatdescriptor) · [`F2fsReader`](#f2fsreader) · [`F2fsWriter`](#f2fswriter) - -#### `F2fsBlockMover` - -Moves a file's data blocks inside an F2FS volume, repoints the address that named each, and brings the volume's account of its segments along. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `F2fsBlockMover` | `F2fsBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | A block, which is what an address counts in. | -| `DataRegionEnd` | `long DataRegionEnd { get; }` | Last byte of that region, which a pass must also stay inside. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a data block may occupy: the start of the region the volume has already given over to file data. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the address naming the block it is given, so a file in several blocks is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A block may be held outside the volume while the rest of the layout moves, which is what lets a full region be rearranged at all. | -| `FindDataRegion` | `void FindDataRegion(Stream image, IEnumerable dataOffsets)` | Works out the region file data lives in, from the types the segment table records. | -| `Init` | `void Init(Stream image)` | Reads the geometry and notes which field names each data block. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `SettleSegmentTables` | `void SettleSegmentTables(Stream image)` | Brings the segment table and the summary area to where the blocks now are. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `F2fsEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `F2fsEntry` | `F2fsEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `F2fsFormatDescriptor` - -References: `https://docs.kernel.org/filesystems/f2fs.html` — Linux kernel F2FS documentation (on-disk layout: SB/CP/SIT/NAT/SSA/main area)`https://www.usenix.org/conference/fast15/technical-sessions/presentation/lee` — Lee et al., "F2FS: A New File System for Flash Storage" (USENIX FAST '15), the design paper`https://en.wikipedia.org/wiki/F2FS` — Wikipedia overview - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IArchiveWriteConstraints`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `F2fsFormatDescriptor` | `F2fsFormatDescriptor()` | | -| `AcceptedInputsDescription` | `string AcceptedInputsDescription { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | F2FS flash-friendly filesystem image — R/W via log-structured append. Add/Remove mutate in place: writes land in the open WARM_DATA/WARM_NODE current segments (no full image rebuild) and advance to fresh main-area segments of the right CURSEG_* type when the open one fills. On-disk NAT and SIT entries are always updated; the NAT/SIT journals in the compact summary block are mirrored when there is room and silently fall through to disk when full (the on-disk entry is authoritative — f2fs-tools treats the journal as overrides over disk). When the root inline-dentry region is full the directory is converted in place to a regular block-based dentry directory whose entries live in HOT_DATA blocks. The checkpoint version + CRC are advanced into the alternate pack so the prior pack stays as a roll-back. Genuinely out of scope: subdirectory creation, nested removal, growing the main-area segment count, and multi-level indirect inode trees. | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `MaxTotalArchiveSize` | `long? MaxTotalArchiveSize { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `MinTotalArchiveSize` | `long? MinTotalArchiveSize { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `CanAccept` | `bool CanAccept(ArchiveInputInfo input, out string reason)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming creation: pre-known per-input sizes drive the F2FS segment geometry in pass 1; pass 2 emits the metadata image with each file's WARM_DATA blocks left zero, then streams each input's bytes from its `OpenStream` factory into its first allocated data block via 64 KB chunks. The output is byte-identical to `Create` for the same inputs (F2FS has no per-block content checksum). Falls back to the buffered default when the target stream is not seekable. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Everything below the main area — superblocks, checkpoints, SIT, NAT and SSA — is structure, and inside the main area each live file claims both its data blocks and the node blocks that address them. Blocks nothing claims still hold whatever was last written to them. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction routed through the bounded `OpenEntry`. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single filesystem entry as a bounded read-only stream. The reader produces the decoded file bytes by walking the entry's extent or block chain; the matched bytes are wrapped in a `BoundedEntryStream` sized to the entry's logical length so cluster/extent slack past the entry's end is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | | - -#### `F2fsReader` - -Reads F2FS filesystem images using the on-disk layout defined by the Linux kernel header `include/linux/f2fs_fs.h`. Handles both traditional data-block dentries and inline dentries (i_inline F2FS_INLINE_DENTRY flag). - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `F2fsReader` | `F2fsReader(Stream stream, bool leaveOpen = true)` | | -| `BlockSize` | `int BlockSize { get; }` | Block size of the volume, from the superblock. | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Length` | `long Length { get; }` | Total size of the backing image in bytes. | -| `MainAreaStart` | `long MainAreaStart { get; }` | First block of the main area; everything below it is metadata. | -| `Dispose` | `void Dispose()` | | -| `EnumerateBlocks` | `IEnumerable> EnumerateBlocks(F2fsEntry entry)` | Where an entry's blocks are: its data blocks, and the node blocks that address them. Both have to survive a wipe — the node blocks are what turn the data back into a file. | -| `ExtractTo` | `long ExtractTo(F2fsEntry entry, Stream destination)` | Writes `entry`'s contents into `destination` block by block, following the inode's node tree. Returns the byte count. | -| `Extract` | `byte[] Extract(F2fsEntry entry)` | | -| `RootBlocks` | `IEnumerable RootBlocks()` | The blocks the root directory occupies: its inode and, when its dentries do not fit inline, the blocks holding them. Nothing in the listing points at these, so they have to be claimed on their own account. | -| `SizeOf` | `long SizeOf(F2fsEntry entry)` | The file's logical size, straight from its inode. | - -#### `F2fsWriter` - -Builds spec-compliant F2FS filesystem images that are accepted by Linux `fsck.f2fs`. Layout (4 KiB blocks, 512 blocks per 2 MiB segment, single-segment sections, single-section zones): Block 0..1: superblock copies (struct at offset 1024 inside block 0/1).Segment 1 reserved (segment0 region) — empty per mkfs convention.Segments 1-2: checkpoint pair. Each pack = 6 blocks (cp1 + compact-summary + 3 node summaries + cp2).Segments 3-4: SIT pair (Segment Information Table).Segments 5-6: NAT pair (Node Address Table).Segment 7: SSA (Segment Summary Area) — one f2fs_summary_block per main segment.Segments 8+: Main area, laid out as contiguous multi-segment regions. The main area holds, in order, the populated regions sized to their actual block counts — HOT_NODE (root inode), WARM_NODE (subdirectory + file inodes), HOT_DATA (directory dentry data blocks), WARM_DATA (file data blocks) — followed by six reserved, empty "current" segments (one per `CURSEG_*` type). Every written block therefore lives in an ordinary, non-current segment whose owner is recorded in the on-disk SSA, and the checkpoint's `cur_*_blkoff` are all zero. This keeps fsck's two summary sources (the checkpoint for current segments, the SSA for everything else) from ever disagreeing. Small directories use inline dentries (`F2FS_INLINE_DENTRY`) embedded in the inode at `i_addr[1]` (offset 364). Larger directories spill into regular 4 KiB dentry data blocks organised by the kernel's multi-level hash-bucket scheme (see `PlanHashBucketDentries`): a name lands in bucket `hash % dir_buckets(level)` at the lowest level whose target bucket has room, so `fsck.f2fs`'s `f2fs_check_dirent_position` agrees with where each name is stored. SIT entries (written for every main segment) encode the valid-block count (low 10 bits) and the segment type (high 6 bits); the SSA footer entry_type classifies each segment as node or data. fsck cross-checks all of these against the reachable inode/dentry tree. - -| Member | Signature | Summary | -| --- | --- | --- | -| `F2fsWriter` | `F2fsWriter()` | | -| `MinimumSegmentCount` | `const int MinimumSegmentCount` | The smallest total segment count `Build` accepts. Equals the metadata area, the populated regions and the six reserved current segments plus slack (20 segments = 40 MiB). | -| `AddFile` | `void AddFile(string name, byte[] data)` | | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a streaming file: `size` drives the WARM_DATA block allocation + inode sizing in pass 1; bytes are pulled from `openStream` in pass 2 of `BuildToStreaming`. Never buffered as `byte[]`. F2FS never stores file contents inline (only directory dentries are inline), so every file — regardless of size — is laid out into ordinary WARM_DATA blocks and is streamable. | -| `BuildAutoSized` | `byte[] BuildAutoSized()` | Builds an F2FS image sized to just hold the added files, plus metadata overhead and roughly ten percent headroom, clamped to `MinimumSegmentCount` (40 MiB). | -| `BuildToStreaming` | `void BuildToStreaming(Stream output, int totalSegments = 0)` | Two-pass streaming Build: pass 1 derives segment geometry from the declared sizes of `AddStreamingFile` entries and emits the full metadata image (checkpoint, SIT, NAT, SSA, superblocks, inodes, dentries) with the streaming entries' WARM_DATA blocks left zero; pass 2 seeks to each entry's first data-block byte offset and streams its bytes from the factory in 64 KB chunks. The byte output is identical to `Build` for the same inputs — only WHERE the file-data bytes come from differs. F2FS has no per-block content checksum (its CRC-32 covers only the checkpoint header), so streaming the data blocks in afterward is byte-safe. | -| `Build` | `byte[] Build(int totalSegments = 32)` | | -| `ComputeAutoSegmentCount` | `int ComputeAutoSegmentCount()` | Computes the total segment count needed to hold all added files: the metadata area, the payload's node/data/dentry regions sized to the actual block counts, the six reserved current segments, plus ~10% headroom — clamped to `MinimumSegmentCount`. | -| `SetVolumeLabel` | `void SetVolumeLabel(string label)` | Sets the UTF-16 volume label stored in the superblock's `volume_name` field. Empty or null leaves the default label. F2FS allows up to 512 UTF-16 code units. | -| `WriteTo` | `void WriteTo(Stream output)` | | - -### Namespace `FileSystem.Fat` - -[`FatBlockMover`](#fatblockmover) · [`FatChainStream`](#fatchainstream) · [`FatEntry`](#fatentry) · [`FatExtentMap`](#fatextentmap) · [`FatFormatDescriptor`](#fatformatdescriptor) · [`FatModifier`](#fatmodifier) · [`FatReader`](#fatreader) · [`FatRemover`](#fatremover) · [`FatShrinkHelper`](#fatshrinkhelper) · [`FatShrinkHelper.ClusterHintResult`](#fatshrinkhelperclusterhintresult) · [`FatShrinkHelper.ClusterSizeStats`](#fatshrinkhelperclustersizestats) · [`FatShrinkHelper.ShrinkResult`](#fatshrinkhelpershrinkresult) · [`FatWriter`](#fatwriter) - -#### `FatBlockMover` - -In-place FAT12/16/32 block mover. Moves cluster-aligned extents within a FAT image and patches the FAT chain + directory entries so the file remains reachable at its new location. Designed for use with the planner-driven defrag path. The caller (typically `Defragment`) enumerates extents, feeds them to the planner, then applies each planned move via `MoveExtent` + `UpdateAllocationAfterMove`. - -Implements `IFilesystemBlockMover`, `IFilesystemMetadataMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatBlockMover` | `FatBlockMover()` | | -| `AllocationBlockSize` | `int AllocationBlockSize { get; }` | Patches the FAT chain and directory entry for a file whose clusters have been scattered to non-contiguous locations (e.g. interleaved defragmentation). Unlike `UpdateAllocationAfterMove` which assumes the old and new positions are contiguous runs, this method accepts an explicit list of old cluster numbers and an explicit list of new cluster numbers, frees the old ones, writes a chain linking the new ones in order, and patches the directory entry start-cluster to point at the first new cluster. | -| `ClusterSize` | `int ClusterSize { get; }` | Bytes per cluster. | -| `FatType` | `int FatType { get; }` | FAT type (12, 16, or 32). | -| `FirstDataByte` | `long FirstDataByte { get; }` | Byte offset of the first data cluster in the image. | -| `RelocatableMetadata` | `IReadOnlySet RelocatableMetadata { get; }` | Nothing, for now. On FAT12 and FAT16 there is genuinely nothing to move: the root lives in a fixed area between the FATs and the first data cluster, sized at format time and named by nothing, and the FATs and boot sector are pinned for the same reason. On FAT32 the root is an ordinary chain the BPB names, and `UpdateMetadataAfterMove` repoints it correctly — but this descriptor relinks files in a second pass that replays the moves to work out where each cluster ended up, and that replay does not model a staged metadata hop. Offering the root while the two disagree produces a volume that passes fsck with the wrong bytes in its files, which is worse than leaving the root where it is. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `SupportsScatteredRelink` | `bool SupportsScatteredRelink { get; }` | | -| `TotalDataClusters` | `int TotalDataClusters { get; }` | Total data clusters in the image. | -| `ClusterOffset` | `long ClusterOffset(int cluster)` | Converts a cluster number to a byte offset. | -| `GetChain` | `List GetChain(byte[] data, int startCluster)` | Walks the FAT chain for a given file and returns its clusters as a list. | -| `Init` | `void Init(Stream image)` | Stream-based initialisation. Reads only the first 512 bytes (BPB) — used by the streaming code paths so multi-GB images don't have to be loaded into memory. | -| `Init` | `void Init(byte[] image)` | Initialises the mover by parsing BPB fields from `image`. Must be called before any move operations. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OffsetCluster` | `int OffsetCluster(long offset)` | Converts a byte offset to a cluster number. | -| `RepatchDotEntries` | `void RepatchDotEntries(Stream image, IReadOnlyDictionary remap)` | After relocated subdirectories have had their cluster chains relinked, repatches the '.' (self) and '..' (parent) directory entries so they point at the directories' NEW start clusters. `remap` maps each moved directory's OLD first cluster to its NEW first cluster. Walks the live directory tree (using the already-corrected FAT chains and parent dirents), reading one cluster at a time. For a non-root directory the first 32-byte entry is '.' and the second is '..'; their start-cluster fields are rewritten in place when their current value is a key in `remap`. The root directory has no '.'/'..' to fix. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldClusters, IReadOnlyList newClusters)` | | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldClusters, IReadOnlyList newClusters, IReadOnlySet clustersLiveElsewhere)` | As above, but told which clusters other files have already been relinked onto. A defragmentation relinks one owner at a time, and an owner's old clusters are frequently where another owner has just landed; freeing them blindly cuts that owner's chain and truncates its content. | -| `UpdateAllocationScattered` | `void UpdateAllocationScattered(Stream image, string fileName, IReadOnlyList oldBlockOffsets, IReadOnlyList newBlockOffsets, IReadOnlySet blocksLiveElsewhere)` | The interface's shape of the relink below: the shared executor speaks in byte offsets because it does not know a format's allocation unit, so the offsets are turned into cluster numbers and handed to the same code the FAT descriptor's own two-phase pass uses. | -| `UpdateMetadataAfterMove` | `void UpdateMetadataAfterMove(Stream image, string metadataName, long oldOffset, long newOffset, long length, IReadOnlyList> liveRanges = null)` | | - -#### `FatChainStream` - -Read-only `Stream` that walks a FAT cluster chain on demand, pulling one cluster at a time into a small buffer. Memory cost is bounded by the cluster size (max 64 KB on standard FAT geometries) — the whole entry is never materialised at once. - -Inherits `Stream`. Implements `IAsyncDisposable`, `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `CanRead` | `override bool CanRead { get; }` | | -| `CanSeek` | `override bool CanSeek { get; }` | | -| `CanWrite` | `override bool CanWrite { get; }` | | -| `Length` | `override long Length { get; }` | | -| `Position` | `override long Position { get; set; }` | | -| `Dispose` | `protected override void Dispose(bool disposing)` | | -| `Flush` | `override void Flush()` | | -| `Open` | `static FatChainStream Open(FatReader reader, FatEntry entry)` | Opens a forward-only stream walking the FAT cluster chain for `entry` against the BPB-derived geometry of `reader`. | -| `Read` | `override int Read(byte[] buffer, int offset, int count)` | | -| `Seek` | `override long Seek(long offset, SeekOrigin origin)` | | -| `SetLength` | `override void SetLength(long value)` | | -| `Write` | `override void Write(byte[] buffer, int offset, int count)` | | - -#### `FatEntry` - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatEntry` | `FatEntry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `FatExtentMap` - -Walks a FAT12/16/32 image and yields the actual on-disk byte layout — reserved region (boot + FATs + root dir on FAT12/16), every cluster-chain segment per file, and free clusters. Used by the defrag window to render the real fragmented layout before defragmentation runs. Streaming: only the BPB + the first FAT copy + (FAT12/16) fixed root dir are kept in memory; subdirectory clusters are read from disk one at a time. A 100 GB FAT32 image needs roughly 100 MB of RAM (the FAT itself) rather than 100 GB. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | Single-pass FAT walker. Parses the boot sector, then for each directory entry walks the cluster chain, emitting one `DefragBlockInfo` per contiguous run. Reserved region (boot sector, FAT1, FAT2, root dir on FAT12/16) becomes a single `MetadataReserved` extent. Free clusters are emitted in chunks. | - -#### `FatFormatDescriptor` - -References: `https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc` — Microsoft "FAT32 File System Specification" (FATGEN 1.03), the canonical FAT12/16/32 spec`https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system` — Wikipedia's detailed on-disk reference incl. vendor variants`https://github.com/torvalds/linux/tree/master/fs/fat` — mainline kernel implementation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemBlockMover`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatFormatDescriptor` | `FatFormatDescriptor()` | | -| `CanonicalSizes` | `IReadOnlyList CanonicalSizes { get; }` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Tunable knobs the Convert Archive dialog / CLI exposes for FAT creation: FAT variant, image size, volume label, cluster size, root-entry count, long-filename and TFAT/FAT+ toggles. The richer upstream schema covers every BPB field the writer actually honours, including the legacy DMF 16-entry root and the Windows-style force-LFN-for-every-entry switch. Forced variants validate against the cluster-count minimum (FAT16 ≥ 4085, FAT32 ≥ 65525) and throw if the chosen geometry can't satisfy them. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | | -| `CreateFromStreams` | `void CreateFromStreams(Stream output, IEnumerable inputs, FormatCreateOptions options)` | Two-pass streaming Create: pre-known per-input sizes drive the FAT geometry choice in pass 1, then pass 2 streams each input's bytes from its `OpenStream` factory straight into the pre-allocated cluster run. Peak memory is bounded by the cluster size + a 64 KB copy buffer — independent of total file size. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | | -| `DefragmentInPlace` | `void DefragmentInPlace(Stream archive, DefragOptions options)` | Lays the volume out again in place, with no rebuild behind it. | -| `Defragment` | `void Defragment(Stream archive)` | Rebuilds `archive` in place so every file occupies a contiguous cluster run. Outer byte size is preserved — writes to the same stream at the same length. Equivalent to `Defragment` with `ConsolidateAtStart`. | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Mode-aware FAT defragmentor. Supports both a planner-driven in-place path (using `DefragPlanner` + `FatBlockMover`) and the legacy rebuild path (using `DefragRebuilder`). The planner-driven path is used for `ConsolidateAtStart`, `ConsolidateAtEnd`, `FillHolesLazy`, and `CarveHole`. Falls back to the rebuild path on error. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | Walks the boot sector + FAT chains and emits the actual on-disk layout as `DefragBlockInfo`s — one per cluster-chain run per file, plus the reserved region (boot/FAT/root dir) and the free-cluster set. Used by the defragment window's block-map preview to show the real fragmented layout before defrag runs. | -| `ExtractEntryToMemory` | `byte[] ExtractEntryToMemory(Stream archive, string entryName, string password)` | Native in-memory single-entry extraction. Buffers the bounded `OpenEntry` stream into a fresh byte array — never reads past the entry's logical size. | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `OpenEntry` | `Stream OpenEntry(Stream archive, string entryName, string password)` | Opens a single FAT entry as a forward-only stream that walks its cluster chain one cluster at a time, wrapped in a `BoundedEntryStream` sized to the entry's logical size. Reads past `entry.Size` return 0 — the cluster-tail slack is physically unreachable through this view. | -| `Remove` | `void Remove(Stream archive, string[] entryNames)` | Removes files from an existing FAT image with full secure wipe (cluster bytes, cluster-tip slack, directory entries, FAT chain entries). No forensic recovery of the removed content is possible from the resulting bytes. | -| `Shrink` | `void Shrink(Stream input, Stream output)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zeros all unused space in the FAT image: free clusters, cluster-tip slack, and optionally deleted directory entries. Uses the generic `UnusedSpaceWiper` driven by the FAT extent map plus a directory-entry-based file-size lookup for cluster-tip precision. | - -#### `FatModifier` - -Genuine in-place add for FAT12/16/32 images — the inverse of `FatRemover`. Allocates free clusters from the FAT, writes the file data into them (zeroing the trailing cluster-tip slack), links the cluster chain in every FAT copy, and inserts a directory entry (VFAT/LFN + 8.3, encoded by `BuildDirentSlots` so the bytes are identical to a freshly-built image) into the first free run of root-directory slots. Existing files, their data clusters and the boot sector stay byte-identical at their original offsets; the image keeps its length. Replace-by-name: an existing entry of the same name is removed first (`Remove`) so the new bytes win. Cases the in-place path does not handle — nested sub-directory targets, a full root directory, or insufficient free clusters — throw so the caller can fall back to the verified rebuild. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AddFile` | `static void AddFile(byte[] image, string name, byte[] data, DateTime? modTime = null, bool forceLfn = false)` | Adds (or replaces by name) `name` in the root directory of the in-memory FAT image. Throws `NotSupportedException` for nested paths and `IOException` when the volume or root directory is full — the signal for the caller to use the rebuild path. | - -#### `FatReader` - -Reads FAT12/FAT16/FAT32 filesystem images. Enumerates files and directories, supports extraction. Handles boot sector parsing, FAT chain following, and directory entry reading with LFN (Long File Name) support. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatReader` | `FatReader(Stream stream, bool leaveOpen = false)` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `FatType` | `int FatType { get; }` | | -| `Dispose` | `void Dispose()` | | -| `Extract` | `byte[] Extract(FatEntry entry)` | | - -#### `FatRemover` - -Secure-remove implementation for FAT12/16/32 images. Resolves a path that may include subdirectory components (separated by `/`), finds the leaf entry — matching either its short 8.3 name or its long filename — zeros every cluster the file occupies (including trailing cluster-tip slack past `i_size`), zeros the on-disk directory entry bytes (LFN slots plus the short entry), and frees its clusters in every FAT copy. After the operation no bytes of the filename or content remain recoverable from the image. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Remove` | `static void Remove(byte[] image, string filePath)` | Removes `filePath` from the in-memory FAT image. The path may name a file directly in the root directory (e.g. `"README.TXT"`) or in a nested subdirectory (e.g. `"Documents/Pictures/Desktop.ini"`). Matching is case-insensitive and supports both 8.3 short names and VFAT long filenames. Throws `FileNotFoundException` if no entry matches along the path. The image is modified in place. | - -#### `FatShrinkHelper` - -Shrinks a FAT filesystem image by defragmenting (consolidate at start) and then truncating trailing free space. Updates the BPB total-sectors field and shrinks the FAT to match the reduced cluster count. - -| Member | Signature | Summary | -| --- | --- | --- | -| `AnalyzeClusterSizes` | `static ClusterHintResult AnalyzeClusterSizes(Stream image)` | Analyzes a FAT image and computes slack waste at various cluster sizes. Returns a recommendation for the cluster size that minimizes slack. | -| `Shrink` | `static ShrinkResult Shrink(Stream image)` | Defragments (consolidate at start) then truncates trailing free space from a FAT image. Updates the BPB total_sectors and FAT size fields to reflect the new geometry. | - -#### `FatShrinkHelper.ClusterHintResult` - -Result of a cluster-size analysis: per-cluster-size slack stats plus a recommendation. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ClusterHintResult` | `ClusterHintResult(int CurrentClusterSize, double CurrentSlackPercent, int RecommendedClusterSize, double RecommendedSlackPercent, IReadOnlyList AllStats)` | Result of a cluster-size analysis: per-cluster-size slack stats plus a recommendation. | -| `AllStats` | `IReadOnlyList AllStats { get; init; }` | | -| `CurrentClusterSize` | `int CurrentClusterSize { get; init; }` | | -| `CurrentSlackPercent` | `double CurrentSlackPercent { get; init; }` | | -| `RecommendedClusterSize` | `int RecommendedClusterSize { get; init; }` | | -| `RecommendedSlackPercent` | `double RecommendedSlackPercent { get; init; }` | | - -#### `FatShrinkHelper.ClusterSizeStats` - -Per-cluster-size slack computation. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ClusterSizeStats` | `ClusterSizeStats(int ClusterSize, long TotalSlack, long TotalAllocated, double SlackPercent)` | Per-cluster-size slack computation. | -| `ClusterSize` | `int ClusterSize { get; init; }` | | -| `SlackPercent` | `double SlackPercent { get; init; }` | | -| `TotalAllocated` | `long TotalAllocated { get; init; }` | | -| `TotalSlack` | `long TotalSlack { get; init; }` | | - -#### `FatShrinkHelper.ShrinkResult` - -Result of a FAT shrink operation: original and new sizes, plus whether the image was actually reduced. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `ShrinkResult` | `ShrinkResult(long OriginalSize, long NewSize, bool WasReduced)` | Result of a FAT shrink operation: original and new sizes, plus whether the image was actually reduced. | -| `NewSize` | `long NewSize { get; init; }` | | -| `OriginalSize` | `long OriginalSize { get; init; }` | | -| `WasReduced` | `bool WasReduced { get; init; }` | | - -#### `FatWriter` - -Builds FAT12 / FAT16 / FAT32 filesystem images from scratch per the Microsoft FAT specification (FATGEN103, EFI FAT32). Auto-selects FAT type based on cluster count. Emits VFAT / LFN (Long File Name) directory entries transparently when the input filename does not fit in 8.3 (mixed-case, non-ASCII, longer than 8 + 3 chars, or with multiple dots) — DOS-era readers see only the short name, modern readers see the long one. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FatWriter` | `FatWriter()` | | -| `AddFile` | `void AddFile(string name, byte[] data, DateTime? modTime = null)` | Adds a file to the image. Long names (mixed case, > 8.3, non-ASCII, multiple dots) are written as VFAT/LFN entries with an auto-generated 8.3 short-name alias. Plain 8.3 names are written as a single dirent. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream, DateTime? modTime = null)` | Adds a streaming file: its `size` is known up front (so the writer can plan the cluster geometry), but its bytes are fetched on demand from `openStream` during the second-pass write — never buffered in memory by the writer. | -| `BuildAutoSized` | `byte[] BuildAutoSized(int bytesPerSector = 512, int requestedClusterSize = 0, string volumeLabel = null, int forcedFatType = 0, bool enableLfn = true, bool transactionFat = false, int requestedRootEntries = 0, bool forceLfn = false, bool minimal = false)` | Builds the FAT image using the smallest sector count that fits all file data and directory entries. Automatically selects FAT32 (≥ 200 000 sectors) when the file count or total data would overflow the fixed root directory of a FAT12/FAT16 image. Prefer this over `Build` when the caller does not know the file count ahead of time (e.g. from a directory walk). | -| `BuildFromFiles` | `static byte[] BuildFromFiles(IEnumerable> files)` | Convenience: builds a FAT image from a list of files, auto-sizing to fit. Used by virtual-disk writers (QCOW2, VHD, VMDK, VDI) to embed a filesystem inside a disk container so that Create() produces a usable volume. | -| `BuildToStreaming` | `void BuildToStreaming(Stream output, int bytesPerSector = 512, int requestedClusterSize = 0, string volumeLabel = null, int forcedFatType = 0, bool enableLfn = true, bool transactionFat = false, int requestedRootEntries = 0, bool forceLfn = false, int requestedTotalSectors = 0)` | Two-pass streaming Build: pass 1 computes layout from `AddStreamingFile` sizes, pass 2 writes boot/FAT/root metadata then streams each entry's bytes from its `Func` factory straight into its allocated cluster run via 64 KB chunks. Peak memory cost is bounded by (cluster_size + dirent_blob + 64 KB) — independent of total image size or per-file size. | -| `BuildTo` | `void BuildTo(Stream output, int totalSectors = 2880, int bytesPerSector = 512, int requestedClusterSize = 0, string volumeLabel = null, int forcedFatType = 0, bool enableLfn = true, bool transactionFat = false, int requestedRootEntries = 0, bool forceLfn = false)` | Streams a FAT image to `output` without ever materialising the whole volume in memory, enabling images of any size (e.g. multi-TB FAT32). Requires a writable, seekable stream: free space is left as sparse zeros via `SetLength`, so only metadata + actual file data is physically written. Produces byte-for-byte identical output to `Build` (verified by parity tests) for any configuration both can express. Peak memory is bounded by O(sector + 64 KB FAT chunk + largest file + largest dirent blob) — independent of total image size. | -| `Build` | `byte[] Build(int totalSectors = 2880, int bytesPerSector = 512, int requestedClusterSize = 0, string volumeLabel = null, int forcedFatType = 0, bool enableLfn = true, bool transactionFat = false, int requestedRootEntries = 0, bool forceLfn = false, int requestedFatSize = 0)` | Builds the FAT filesystem image. | -| `PickClusterForFixedImage` | `int PickClusterForFixedImage(int totalSectors, int bytesPerSector, int forcedFatType, int requestedRootEntries, bool enableLfn)` | Picks the cluster size (bytes) that minimises slack + FAT-table overhead without escalating to a higher FAT variant than strictly necessary. Delegates to `FilesystemLayoutOptimizer` for the generic optimisation logic; FAT-specific tier and cost knowledge lives here. | -| `SetVolumeSerial` | `void SetVolumeSerial(uint serial)` | Pins the volume serial instead of letting one be drawn. | - -### Namespace `FileSystem.Gfs2` - -[`Gfs2BlockMover`](#gfs2blockmover) · [`Gfs2Entry`](#gfs2entry) · [`Gfs2ExtentMap`](#gfs2extentmap) · [`Gfs2FormatDescriptor`](#gfs2formatdescriptor) · [`Gfs2Reader`](#gfs2reader) · [`Gfs2Writer`](#gfs2writer) - -#### `Gfs2BlockMover` - -Moves a file's blocks inside a GFS2 volume, repoints the tree pointers that name them, and moves the allocation with them. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Gfs2BlockMover` | `Gfs2BlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Block size in bytes, as the superblock records it. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file may occupy: past the structures and the group bitmaps. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the run it is given and nothing else, so an owner scattered over several runs is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads the geometry and walks the resource groups. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length, bool releaseOldSpace)` | | - -#### `Gfs2Entry` - -One entry in a GFS2 image. Read-only: we surface the superblock, root/master directory inode pointers, and (optionally) any directory entries we manage to walk from the root inode's leaf blocks. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Gfs2Entry` | `Gfs2Entry()` | | -| `IsDirectory` | `bool IsDirectory { get; init; }` | | -| `LastModified` | `DateTime? LastModified { get; init; }` | | -| `Name` | `string Name { get; init; }` | | -| `Size` | `long Size { get; init; }` | | - -#### `Gfs2ExtentMap` - -Reads a GFS2 volume's resource-group bitmaps and reports which blocks are in use. GFS2 accounts for allocation two bits per block: 00 is free, and every other state (data, unlinked, dinode) means the block is live. What the bitmaps leave clear is exactly the free space — including the blocks a removed file used to occupy, which still hold its bytes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `Gfs2FormatDescriptor` - -GFS2 (Global File System 2) descriptor — Red Hat's cluster filesystem, mainline Linux since 2.6.19. We parse the superblock at offset 65536, surface block size + lock proto/table + UUID + master/root inode pointers, and walk the root inode's inline directory entries (single-leaf, di_height==0). For regular files with inline data (height==0) we extract the bytes. On-disk layout reverse-validated against real `mkfs.gfs2` output (gfs2-utils 3.5.1): the `gfs2_meta_header` is 24 bytes, the sb carries a reserved `__pad2` inum between master and root, and the `gfs2_dirent` header is 40 bytes. See `Gfs2ExternalConformanceTests` for the mkfs.gfs2 / fsck.gfs2 gate. Creation (`Create`, `Gfs2Writer`) emits a fresh, empty standalone (lock_nolock, single-journal) volume — superblock, the fixed first resource group plus a second data resource group with a correct (multi-block) allocation bitmap, the master directory and its system inodes (jindex, per_node, inum, statfs, rindex, quota), a formatted 8 MB journal of clean unmount log headers, and the root directory — all sized so real `fsck.gfs2 -n` passes clean (exit 0). Supported size range 16–256 MB (single data resource group); the volume is empty, since populating it with files is out of scope. Out of scope (multi-week effort each): writing files/directories, ExHash multi-leaf directories, multi-level block indirection (di_height > 0), devices > 256 MB (which gfs2-utils splits into several evenly-spaced resource groups), journal replay, cluster lock manager state, extended attributes. Magic: `mh_magic = 0x01161970` (BE u32) at the start of the superblock meta header. On disk at byte offset 65536 this serialises as `01 16 19 70`. Confidence 0.85 — well-known constant at a fixed offset, but GFS2 shares this magic with GFS1 at slightly different layouts, so we keep a small margin below the 0.9-0.95 reserved for formats with a structurally unique header. References: Linux kernel `fs/gfs2/` — `include/uapi/linux/gfs2_ondisk.h`Red Hat Cluster Suite / Resilient Storage Add-On documentation - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Gfs2FormatDescriptor` | `Gfs2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Knobs the empty-volume writer honours. `ImageSize` drives the writer's total size (clamped to the single-data-resource-group range 16–256 MB); `LockTable` is written into `sb_locktable` and read back as `Gfs2Reader.LockTable`. The 4 KB block size and the `lock_nolock` protocol are fixed by the standalone layout. | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Creates a fresh, empty standalone (lock_nolock, single-journal) GFS2 volume that real `fsck.gfs2` accepts clean. The volume size defaults to 32 MB and may be overridden with the `size` format option (bytes, clamped to 16–256 MB; `K`/`M` suffixes accepted). | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Rewrites the volume with every file laid out contiguously from the start of the data area. Each entry is spilled to scratch and the writer pulls it back while laying out the metadata tree, so the rebuild is not bounded by what a byte[] can hold. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zero-fills every block the resource-group bitmaps report as free — which is where a removed file's bytes stay until something else claims them. | - -#### `Gfs2Reader` - -Read-only GFS2 (Global File System 2) image walker. Mainline Linux since 2.6.19; Red Hat cluster filesystem. Big-endian on-disk. What we parse: Superblock at byte offset 65536 (= sector 128 × 512 B). Magic `mh_magic = 0x01161970` at the start of the gfs2_meta_header.Block size from `sb_bsize`, root + master inum from `sb_root_dir` / `sb_master_dir`.Root inode (`gfs2_dinode`) and any `gfs2_dirent` records living inline in the inode block (single-leaf directories). What we deliberately skip (multi-week effort each): ExHash directories (multi-level leaf blocks)Multi-level block indirection (di_height > 0)Journal recovery, cluster lock manager stateExtended attributes References: Linux kernel `fs/gfs2/` — primary on-disk definition`include/uapi/linux/gfs2_ondisk.h` — magic constants & struct layoutRed Hat Cluster Suite / Resilient Storage Add-On docs - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Gfs2Reader` | `Gfs2Reader(Stream stream)` | | -| `FormatFs` | `const uint FormatFs` | Filesystem format version expected in sb_fs_format (GFS2_FORMAT_FS). | -| `FormatMultihost` | `const uint FormatMultihost` | Multi-host format version expected in sb_multihost_format (GFS2_FORMAT_MULTI). | -| `MetaHeaderSize` | `const int MetaHeaderSize` | Size of `struct gfs2_meta_header` on disk: 24 bytes — `mh_magic`(4) + `mh_type`(4) + `__pad0`(8) + `mh_format`(4) + `mh_jid`(4). Real `mkfs.gfs2` output uses the 24-byte header; every metadata struct (sb, dinode, leaf, rgrp, log header) embeds it at offset 0. | -| `MetaMagic` | `const uint MetaMagic` | GFS2 metadata magic — `mh_magic` at start of every metadata block. | -| `MetaTypeDinode` | `const uint MetaTypeDinode` | gfs2_meta_header.mh_type for a dinode. | -| `MetaTypeSuperblock` | `const uint MetaTypeSuperblock` | gfs2_meta_header.mh_type for the superblock. | -| `SbByteOffset` | `const long SbByteOffset` | Superblock byte offset within the device (sector 128 × 512 B). | -| `BlockSizeShift` | `uint BlockSizeShift { get; }` | | -| `BlockSize` | `uint BlockSize { get; }` | | -| `Entries` | `IReadOnlyList Entries { get; }` | | -| `Length` | `long Length { get; }` | Total size of the backing image in bytes. | -| `LockProto` | `string LockProto { get; }` | | -| `LockTable` | `string LockTable { get; }` | | -| `MasterFormalIno` | `ulong MasterFormalIno { get; }` | | -| `MasterInodeBlock` | `ulong MasterInodeBlock { get; }` | | -| `RootFormalIno` | `ulong RootFormalIno { get; }` | | -| `RootInodeBlock` | `ulong RootInodeBlock { get; }` | | -| `SuperblockRaw` | `byte[] SuperblockRaw { get; }` | Raw superblock bytes (1024 bytes captured from offset 65536), for diagnostics. | -| `SuperblockValid` | `bool SuperblockValid { get; }` | | -| `UuidHex` | `string UuidHex { get; }` | | -| `Dispose` | `void Dispose()` | | -| `EnumerateDataExtents` | `IEnumerable> EnumerateDataExtents(Gfs2Entry entry)` | Where on disk `entry`'s bytes actually sit, as runs of whole blocks, along with the byte offset of the first pointer that names each run. | -| `ExtractTo` | `long ExtractTo(Gfs2Entry entry, Stream destination)` | Writes `entry`'s content into `destination`. A body up to `blocksize - 232` is stuffed in the dinode; a longer one hangs off a metadata tree whose depth di_height gives — the dinode's own pointer area at the top, then `di_height - 1` levels of indirect blocks. Returns the number of bytes written. | -| `Extract` | `byte[] Extract(Gfs2Entry entry)` | Reads a regular file's content. Only valid below the array limit. | - -#### `Gfs2Writer` - -Clean-room GFS2 (Global File System 2) image writer producing a minimal, empty, standalone (`lock_nolock`, single-journal) volume that real `fsck.gfs2` (gfs2-utils) accepts without errors. The output mirrors the on-disk structures defined in the public Linux kernel header `include/uapi/linux/gfs2_ondisk.h` and the layout produced by `mkfs.gfs2`, reverse-validated byte-for-byte against a real reference image. Big-endian throughout, 4096-byte blocks.What we emit (everything `fsck.gfs2` requires for a clean volume):Superblock at byte 65536 (block 16).A single resource group whose inline bitmap covers every data block and correctly marks each used metadata block.Master directory dinode and the system inodes hung off it: `jindex`, `per_node`, `inum`, `statfs`, `rindex`, `quota`.A formatted 8 MB journal (`journal0`) whose 2048 blocks each carry a clean unmount log header (correct `lh_hash` CRC32 and `lh_crc` CRC32C).`per_node` system inodes `inum_range0`, `statfs_change0`, `quota_change0` (the latter a 1 MB file of empty quota-change blocks).The root directory dinode with `.` and `..`.Block-accounting fields (`rg_free`, `rg_dinodes`, the master `statfs`, the `inum` next-formal-number) are all computed from the real layout so `check_statfs` passes. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Gfs2Writer` | `Gfs2Writer(long sizeBytes = 33554432, byte[] uuid = null, DateTime? timestamp = null, string lockTable = null)` | Creates a writer for an image of the given total size in bytes. The size is rounded down to a whole number of 4096-byte blocks; the minimum that yields a clean volume (journal + system inodes + slack) is 32 MB. | -| `AddFile` | `void AddFile(string name, byte[] data)` | Adds a regular file to the root directory. Bodies up to `BlockSize - 232` are stuffed in the dinode; longer ones get a metadata tree of indirect blocks. | -| `AddStreamingFile` | `void AddStreamingFile(string name, long size, Func openStream)` | Adds a file whose bytes are pulled from `openStream` as the volume is written. | -| `Build` | `byte[] Build()` | Builds the image and returns the raw bytes. | -| `Build` | `void Build(Stream output)` | Builds the image and writes it to `output`. | -| `EstimateSize` | `static long EstimateSize(IEnumerable fileSizes)` | Smallest volume that holds `fileSizes`: the fixed metadata layout, every file's dinode, its data blocks and the indirect blocks above them, plus room for the resource-group bitmaps. Rounded up to a megabyte. | - -### Namespace `FileSystem.Hammer` - -[`HammerBlockMover`](#hammerblockmover) · [`HammerExtentMap`](#hammerextentmap) · [`HammerFormatDescriptor`](#hammerformatdescriptor) · [`HammerReader`](#hammerreader) · [`HammerReader.DataExtent`](#hammerreaderdataextent) · [`HammerReader.FileEntry`](#hammerreaderfileentry) · [`HammerVolumeOndisk`](#hammervolumeondisk) · [`HammerWriter`](#hammerwriter) - -#### `HammerBlockMover` - -Moves a file's data records inside a HAMMER volume and repoints the B-tree elements that name them. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HammerBlockMover` | `HammerBlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | Sixty-four bytes. A record's zone offset is byte-exact, but keeping the destinations on the element grid keeps a record from straddling the sixteen-byte structures the format aligns on. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a record may occupy: past the volume header and reserves. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the run it is given and nothing else, so an owner scattered over several runs is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A run may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads where the buffer area starts and how far the records reach. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `HammerExtentMap` - -Reads a HAMMER volume's freemap and reports which bytes are in use. HAMMER allocates in 8 MB big-blocks: a layer-2 entry per big-block records which zone owns it and how far into it the allocator has appended. A big-block no zone owns is free outright, and the tail of one past its append point is free as well — which is where a removed file's bytes stay. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Enumerate` | `static IEnumerable Enumerate(Stream image)` | | - -#### `HammerFormatDescriptor` - -Read-only descriptor for HAMMER (DragonFly BSD original) filesystem images. Surfaces the volume header at offset 0 plus a structured metadata bundle and the raw image. Walking the HAMMER B-tree (zone blockmap → cluster → inode → records) is explicitly out of scope (multi-week effort). Magic: 8-byte uint64 `vol_signature = 0xC8414D4DC5523031` ("HAMMER01") at offset 0, serialised LE on disk as `31 30 52 C5 4D 4D 41 C8`. Confidence 0.85: an 8-byte magic value at offset 0 is high-confidence but HAMMER lacks an additional sanity check at this stage of detection (the `vol_fstype` UUID at offset 64 is not validated against a well-known constant). References: `https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/vfs/hammer/hammer_disk.h``https://www.dragonflybsd.org/hammer/` - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`, `IWipeEmpty`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `HammerFormatDescriptor` | `HammerFormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Sole tunable the HAMMER writer honours: the filesystem label (`newfs_hammer -L`), written into the volume header and the PFS#0 data and surfaced back as `vol_label`. Volume size is intentionally not exposed — the UNDO-FIFO floor pins it at ~1 GB regardless. An empty label falls back to the writer default ("hammer"). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Produces a fresh, mountable single-volume HAMMER image from `inputs`. HAMMER's UNDO FIFO floor forces a volume size of ~1 GB minimum; see `HammerWriter`. Each input becomes an inode + directory-entry + data record in the global B-Tree. The DragonFly kernel mounts the image and reads every file's contents byte-exact (validated via `mount_hammer` + `cksum`, including multi-block files spanning the large- and small-data zones); the image also passes `hammer show` and `hammer checkmap`. | -| `Defragment` | `void Defragment(Stream archive)` | | -| `Defragment` | `void Defragment(Stream archive, DefragOptions options)` | Lays the volume out again. A file's bytes live in data records whose B-tree elements carry the offset they start at, so a move is the copy, that field, and the checksum over the node the element lives in — cheaper than reading every file out and writing a fresh volume, which is what the inherited default did for the one mode it offered. | -| `EnumerateExtents` | `IEnumerable EnumerateExtents(Stream image)` | | -| `Extract` | `void Extract(Stream stream, string outputDir, string password, string[] files)` | | -| `List` | `List List(Stream stream, string password)` | | -| `WipeUnusedSpace` | `long WipeUnusedSpace(Stream image, bool wipeClusterTips = true, bool wipeDeletedEntries = true)` | Zero-fills everything the freemap leaves unallocated: free big-blocks outright, and the tail of a partly-used one past its append point. | - -#### `HammerReader` - -Walks a HAMMER (DragonFly BSD, HAMMER1) volume's global B-Tree and yields the regular files it contains as `path -> bytes`. This is the read side of full file support: it parses the volume header, resolves zone offsets through the freemap (zone-4 two-layer blockmap), recursively descends the B-Tree from `vol0_btree_root`, and reassembles inodes, directory entries and data records into a directory tree. On-disk references (`sys/vfs/hammer/hammer_disk.h`):B-Tree node `hammer_node_ondisk`: `crc(4)@0`, `signature(4)@4`, `parent(8)@8`, `count(4)@16`, `type(1)@20`, then 63 elements of 64 bytes starting at @64.Element base `hammer_base_elm`: `obj_id(8)@0`, `key(8)@8`, `create_tid(8)@16`, `delete_tid(8)@24`, `rec_type(2)@32`, `obj_type(1)@34`, `btype(1)@35`, `localization(4)@36`.Internal element adds `subtree_offset(8)@40`; leaf element adds `create_ts(4)@40`, `delete_ts(4)@44`, `data_offset(8)@48`, `data_len(4)@56`, `data_crc(4)@60`.rec_type `INODE=0x0001`, `DATA=0x0010`, `DIRENTRY=0x0011`; obj_type `DIRECTORY=1`, `REGFILE=2`.Directory-entry data `hammer_direntry_data`: `obj_id(8)@0`, `localization(4)@8`, `reserved01(4)@12`, `name[]@16` (length = `data_len - 16`).Inode data `hammer_inode_data`: `obj_type(1)@64`, `size(8)@80`. - -Implements `IDisposable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FreemapLayer1Offset` | `long FreemapLayer1Offset { get; }` | File offset of the freemap's layer-1 array. | -| `Length` | `long Length { get; }` | Total size of the backing image in bytes. | -| `Valid` | `bool Valid { get; }` | True if the image carries a valid HAMMER volume header. | -| `VolumeBufferStart` | `long VolumeBufferStart { get; }` | Where the volume's buffer area starts; zone-2 offsets are relative to it. | -| `Dispose` | `void Dispose()` | | -| `EnumerateDataExtents` | `IReadOnlyList EnumerateDataExtents()` | Where on disk each file's data records actually sit, along with the byte offset of the B-tree element that names each of them and of the node that element lives in. | -| `Open` | `static HammerReader Open(Stream stream)` | Opens a HAMMER volume, pulling blocks on demand. Never throws on a malformed header; check `Valid`. | -| `Open` | `static HammerReader Open(byte[] image)` | Opens a HAMMER image. Never throws on a malformed header; check `Valid`. | -| `ReadFiles` | `IReadOnlyList ReadFiles()` | Walks the B-Tree and returns every regular file with its full path relative to the filesystem root (e.g. `"sub/inner.txt"`). Directories are implied by the paths; empty directories are not returned (they carry no file payload). | - -#### `HammerReader.DataExtent` - -One data record: its bytes, and where the B-tree records them. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `DataExtent` | `DataExtent(string Path, long Offset, long Length, long ElementOffset, long NodeOffset)` | One data record: its bytes, and where the B-tree records them. | -| `ElementOffset` | `long ElementOffset { get; init; }` | | -| `Length` | `long Length { get; init; }` | | -| `NodeOffset` | `long NodeOffset { get; init; }` | | -| `Offset` | `long Offset { get; init; }` | | -| `Path` | `string Path { get; init; }` | | - -#### `HammerReader.FileEntry` - -A regular file recovered from the B-Tree: full POSIX path and exact bytes. - -Implements `IEquatable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `FileEntry` | `FileEntry(string Path, byte[] Content)` | A regular file recovered from the B-Tree: full POSIX path and exact bytes. | -| `Content` | `byte[] Content { get; init; }` | | -| `Path` | `string Path { get; init; }` | | - -#### `HammerVolumeOndisk` - -Parses the HAMMER (DragonFly BSD original) volume header at byte offset 0 of each volume. Read-only; we never walk the B-tree, only surface the header fields and the `vol0_blockmap` array's byte slice. Layout per `sys/vfs/hammer/hammer_disk.h`: Verified by: `https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/vfs/hammer/hammer_disk.h` — `HAMMER_FSBUF_VOLUME` + struct definitionDragonFly Wiki `https://www.dragonflybsd.org/hammer/` - -| Member | Signature | Summary | -| --- | --- | --- | -| `HammerVolumeOndisk` | `HammerVolumeOndisk()` | | -| `HeaderCaptureSize` | `const int HeaderCaptureSize` | Header capture size we surface as `volume_header.bin` (1898 bytes covers the static fields). | -| `MagicBytesLE` | `static readonly byte[] MagicBytesLE` | First 8 bytes at offset 0, in disk order (LE serialisation of `VolumeSignature`). | -| `VolumeSignature` | `const ulong VolumeSignature` | HAMMER volume magic: `0xC8414D4DC5523031` ("HAMMER01" — first byte '1' = 0x31 because the 64-bit constant lives little-endian on disk). | -| `HeaderRaw` | `byte[] HeaderRaw { get; }` | | -| `Valid` | `bool Valid { get; }` | True iff `VolumeSignature` matched at offset 0. | -| `Vol0BtreeRoot` | `long Vol0BtreeRoot { get; }` | | -| `Vol0NextTid` | `long Vol0NextTid { get; }` | | -| `Vol0StatBigblocks` | `long Vol0StatBigblocks { get; }` | | -| `Vol0StatFreeBigblocks` | `long Vol0StatFreeBigblocks { get; }` | | -| `Vol0StatInodes` | `long Vol0StatInodes { get; }` | | -| `VolBotBeg` | `long VolBotBeg { get; }` | | -| `VolBufBeg` | `long VolBufBeg { get; }` | | -| `VolBufEnd` | `long VolBufEnd { get; }` | | -| `VolCount` | `int VolCount { get; }` | | -| `VolCrc` | `uint VolCrc { get; }` | | -| `VolFlags` | `uint VolFlags { get; }` | | -| `VolFsTypeHex` | `string VolFsTypeHex { get; }` | | -| `VolFsidHex` | `string VolFsidHex { get; }` | | -| `VolLabel` | `string VolLabel { get; }` | | -| `VolMemBeg` | `long VolMemBeg { get; }` | | -| `VolNo` | `int VolNo { get; }` | | -| `VolRootVol` | `uint VolRootVol { get; }` | | -| `VolSignature` | `ulong VolSignature { get; }` | | -| `VolVersion` | `uint VolVersion { get; }` | | -| `TryParse` | `static HammerVolumeOndisk TryParse(ReadOnlySpan image)` | Best-effort parse. Never throws. | - -#### `HammerWriter` - -Writes a single-volume HAMMER (DragonFly BSD, HAMMER1) filesystem image that DragonFly recognises and mounts. The output is a faithful port of `newfs_hammer(8)` (`sbin/newfs_hammer/newfs_hammer.c`) together with the on-disk helpers in `sbin/hammer/ondisk.c` and `sbin/hammer/blockmap.c`: it lays down the volume header, the freemap (zone-4 two-layer blockmap), the UNDO/REDO FIFO (zone-3), and a minimal root B-Tree (zone-8) holding the root directory's inode and PFS#0 records. Geometry mirrors newfs exactly: the volume is split into a 256 KB header junk area (`vol_bot_beg`), a boot area, a memory log, then the zone-2 buffer area. Every metadata block carries the version-gated CRC (see `HammerCrc`).HAMMER's UNDO FIFO has a hard minimum of `HAMMER_MIN_UNDO_BIGBLOCKS (64) * HAMMER_BIGBLOCK_SIZE (8 MB) = 512 MB`, so the smallest volume that `newfs_hammer`/this writer can format is on the order of ~1 GB. The output stream is grown to that size (sparse on filesystems that support holes).Files passed to `AddFile` are materialised as real records readable by the DragonFly kernel: each gets a regular-file inode record, a directory-entry record under the root directory (keyed by the ALG1 directory namehash) and one or more zone-11 small-data records (payload split into 16 KB blocks, each rounded up to a power-of-two block). All records, plus the root inode and PFS#0 record, live in a single sorted leaf B-Tree node — which caps the image at `HAMMER_BTREE_LEAF_ELMS (63)` elements (~20 files). Files are placed flat in the root directory (no sub-directory nesting). - -| Member | Signature | Summary | -| --- | --- | --- | -| `HammerWriter` | `HammerWriter()` | | -| `Label` | `string Label { get; set; }` | Filesystem label (max 63 chars, ASCII). Mirrors `newfs_hammer -L`. | -| `VolumeSize` | `long VolumeSize { get; set; }` | Total volume size in bytes. Forced up to the HAMMER minimum (~1 GB) so the UNDO FIFO and freemap fit. Aligned down to `HAMMER_BUFSIZE` internally. | -| `AddFile` | `void AddFile(string name, byte[] content)` | Adds a regular file to the root directory. The payload is materialised as a kernel-readable inode + directory entry + small-data records when the image is written. | -| `ComputeAutoSize` | `long ComputeAutoSize()` | Smallest volume that holds the added files: the ~1 GB the UNDO FIFO and freemap need, plus the payload and its B-Tree, rounded to a big-block. | -| `WriteTo` | `void WriteTo(Stream output)` | Formats the HAMMER volume and writes it to `output`. | - -### Namespace `FileSystem.Hammer2` - -[`Hammer2BlockMover`](#hammer2blockmover) · [`Hammer2FormatDescriptor`](#hammer2formatdescriptor) · [`Hammer2Reader`](#hammer2reader) · [`Hammer2Reader.FileRef`](#hammer2readerfileref) · [`Hammer2VolumeData`](#hammer2volumedata) · [`Hammer2Writer`](#hammer2writer) - -#### `Hammer2BlockMover` - -Moves a file's blocks inside a HAMMER2 volume, repoints the blockref that named each, and takes the chain of checks above it again. - -Implements `IFilesystemBlockMover`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hammer2BlockMover` | `Hammer2BlockMover()` | | -| `BlockSize` | `int BlockSize { get; }` | The largest block any file uses. A blockref names its block with a radix, so a destination has to be aligned to the block it holds. | -| `FirstDataByte` | `long FirstDataByte { get; }` | First byte a file's block may occupy: past the volume headers. | -| `RepointsRunsIndependently` | `bool RepointsRunsIndependently { get; }` | Each call repoints the blockref naming the block it is given, so a file in several blocks is simply several calls. | -| `SupportsHeldRuns` | `bool SupportsHeldRuns { get; }` | A block may be held outside the volume while the rest of the layout moves, which is what lets a full volume be rearranged at all. | -| `Init` | `void Init(Stream image)` | Reads the blockref tree once and notes the chain above each block. | -| `MoveExtent` | `void MoveExtent(Stream image, long srcOffset, long dstOffset, long length, bool zeroSource = false)` | | -| `SettleVolumeHeaders` | `void SettleVolumeHeaders(Stream image)` | Stamps the volume headers again, which carry CRCs over their own sectors. | -| `UpdateAllocationAfterMove` | `void UpdateAllocationAfterMove(Stream image, string fileName, long oldOffset, long newOffset, long length)` | | - -#### `Hammer2FormatDescriptor` - -Read-only descriptor for HAMMER2 (DragonFly BSD newer) filesystem images. Surfaces the volume-data sector at offset 0 plus a structured metadata bundle and the raw image. Walking the HAMMER2 cluster B-tree (radix-tree chains, blockrefs, indirect blocks) is explicitly out of scope (multi-week effort). Magic: 8-byte uint64 at offset 0 = `HAMMER2_VOLUME_ID_HBO` (`0x48414d3205172011`) or `HAMMER2_VOLUME_ID_ABO` (`0x11201705324d4148`). The descriptor's `MagicSignatures` list covers the HBO form (LE serialisation: `11 20 17 05 32 4D 41 48`); the ABO form is recognised by the parser but is rare in practice (only arises when a HAMMER2 image is cross-mounted on opposite-endian hardware). Confidence 0.85: an 8-byte magic at offset 0 is high-confidence but the detector does no secondary sanity check (e.g. volume size plausibility, fstype UUID match). References: `https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/vfs/hammer2/hammer2_disk.h``https://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/sys/vfs/hammer2/DESIGN` - -Implements `IArchiveCreatable`, `IArchiveDefragmentable`, `IArchiveFormatOperations`, `IArchiveModifiable`, `IArchiveShrinkable`, `IFilesystemExtentMap`, `IFormatDescriptor`, `IFormatOptionsSchema`, `ILayoutOptimizable`. - -| Member | Signature | Summary | -| --- | --- | --- | -| `Hammer2FormatDescriptor` | `Hammer2FormatDescriptor()` | | -| `Capabilities` | `FormatCapabilities Capabilities { get; }` | | -| `Category` | `FormatCategory Category { get; }` | | -| `CompoundExtensions` | `IReadOnlyList CompoundExtensions { get; }` | | -| `DefaultExtension` | `string DefaultExtension { get; }` | | -| `Description` | `string Description { get; }` | | -| `DisplayName` | `string DisplayName { get; }` | | -| `Extensions` | `IReadOnlyList Extensions { get; }` | | -| `Family` | `AlgorithmFamily Family { get; }` | | -| `Id` | `string Id { get; }` | | -| `MagicSignatures` | `IReadOnlyList MagicSignatures { get; }` | | -| `Methods` | `IReadOnlyList Methods { get; }` | | -| `OptionsSchema` | `IReadOnlyList OptionsSchema { get; }` | Sole tunable the HAMMER2 writer honours: the PFS label (`newfs_hammer2 -L`) given to the populated PFS that holds the user files. Volume size is intentionally not exposed — the boot/aux/topology floor pins the minimum regardless. An empty label falls back to the writer default ("DATA"). | -| `TarCompressionFormatId` | `string TarCompressionFormatId { get; }` | | -| `Add` | `void Add(Stream archive, IReadOnlyList inputs)` | Genuine in-place (copy-on-write) add/replace of files in the labelled PFS root: new file inodes + data blocks and the rebuilt labelled-PFS → super-root → volume-header chain are appended past the topology high-water, leaving every existing file's data byte-identical at its original offset. Falls back to the verified rebuild path when the change can't be expressed as a single inline/one-indirect blockset (nested-indirect roots, nested paths). See `Hammer2InPlaceModifier`. | -| `Create` | `void Create(Stream output, IReadOnlyList inputs, FormatCreateOptions options)` | Produces a fresh, mountable single-volume HAMMER2 image from `inputs`. The output mirrors `newfs_hammer2`: a volume header, the super-root inode, and the "LOCAL" + labelled PFS inodes. The labelled PFS root is populated with the input files — each a regular-file inode plus a directory entry (see `Hammer2Writer`). The DragonFly kernel mounts the labelled PFS and reads every file's contents byte-exact (validated via `mount_hammer2 …@