xfh

Recover files compressed with historical Amiga XPK tools.

xfh.cli

Command-line interface.

main

def main(argv: list[str] | None = None) -> int

Run the CLI and return its process status.

xfh.limits

Resource limits applied before allocating decompressed output.

Limits Objects

@dataclass(frozen=True, slots=True)
class Limits()

Limits used to bound work on untrusted compressed input.

xfh.__main__

Module entry point for python -m xfh.

xfh.models

Immutable metadata returned by the public API.

FileFormat Objects

class FileFormat(str, Enum)

Known XPK stream container variants.

ChunkInfo Objects

@dataclass(frozen=True, slots=True)
class ChunkInfo()

Metadata for one encoded stream chunk.

FileInfo Objects

@dataclass(frozen=True, slots=True)
class FileInfo()

Parsed stream metadata.

RecoveryIssue Objects

@dataclass(frozen=True, slots=True)
class RecoveryIssue()

One reason why salvage output is incomplete.

RecoveryResult Objects

@dataclass(frozen=True, slots=True)
class RecoveryResult()

Partial or complete output from explicit salvage mode.

xfh.codecs.ilzr

XPK ILZR decompression.

Derived from Ancient’s ILZRDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_ilzr

@register("ILZR")
def decompress_ilzr(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode incremental Lempel-Ziv-Renau data.

xfh.codecs.fast

XPK FAST decompression.

decompress_fast

@register("FAST")
def decompress_fast(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one FAST chunk.

xfh.codecs.lzw_variants

CyberYAFA XPK LZW2, LZW3, LZW4, and LZW5 decompression.

Despite their names, these formats are control-bit LZ variants rather than dictionary-based LZW streams.

Derived from Ancient’s LZW2Decompressor, LZW4Decompressor, and LZW5Decompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_lzw2

@register("LZW2")
def decompress_lzw2(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an LZW2 stream.

decompress_lzw3

@register("LZW3")
def decompress_lzw3(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an LZW3 stream, whose packed representation matches LZW2.

decompress_lzw4

@register("LZW4")
def decompress_lzw4(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an LZW4 stream.

decompress_lzw5

@register("LZW5")
def decompress_lzw5(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an LZW5 stream.

xfh.codecs.rdcn

XPK RDCN decompression.

Derived from Ancient’s RDCNDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_rdcn

@register("RDCN")
def decompress_rdcn(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode Ross Data Compression chunks.

xfh.codecs.standard

XPK wrappers around standardized compression streams.

decompress_bzp2

@register("BZP2")
def decompress_bzp2(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an XPK-wrapped bzip2 stream.

decompress_gzip

@register("GZIP")
def decompress_gzip(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode GZIP’s zlib-format payload.

xfh.codecs.zeno

XPK ZENO decompression.

Derived from Ancient’s ZENODecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_zeno

@register("ZENO")
def decompress_zeno(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode ZENO’s variable-width dictionary stream.

xfh.codecs.impl

XPK File Imploder decompression.

decompress_impl

@register("IMPL")
def decompress_impl(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an XPK-wrapped File Imploder stream.

xfh.codecs.sqsh

XPK SQSH decompression.

decompress_sqsh

@register("SQSH")
def decompress_sqsh(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an SQSH sample-prediction and LZ stream.

xfh.codecs.pwpk

XPK PowerPacker (PWPK) decompression.

decompress_pwpk

@register("PWPK")
def decompress_pwpk(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode a PowerPacker chunk.

xfh.codecs.smpl

XPK SMPL decompression.

decompress_smpl

@register("SMPL")
def decompress_smpl(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode a static Huffman stream followed by byte delta prediction.

xfh.codecs._prefix

Small prefix-code helpers shared by XPK codecs.

PrefixDecoder Objects

class PrefixDecoder()

Decode explicit most-significant-bit-first prefix codes.

decode

def decode(bits: object) -> int

Decode one value from an object exposing read(count).

variable_length

def variable_length(bits: object, specifications: tuple[int, ...],
                    index: int) -> int

Decode an indexed variable-length integer with cumulative bases.

xfh.codecs._streams

Bounded byte and bit streams used by historical XPK codecs.

The stream behavior is derived from Ancient, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

CoupledInput Objects

class CoupledInput()

Forward word reads and backward byte reads sharing one payload.

ByteInput Objects

class ByteInput()

A bounded forward byte stream.

BitReader Objects

class BitReader()

Read most- or least-significant bits from fixed-width words.

copy_forward

def copy_forward(output: bytearray, distance: int, count: int,
                 output_size: int) -> None

Copy an overlapping LZ match within a bounded output buffer.

xfh.codecs.crm

Crunch-Mania XPK codecs.

xfh.codecs.dlta

XPK DLTA decompression.

decompress_dlta

@register("DLTA")
def decompress_dlta(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode DLTA’s byte-delta transform.

xfh.codecs.mash

XPK MASH decompression.

decompress_mash

@register("MASH")
def decompress_mash(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode a MASH mixed literal and LZ stream.

xfh.codecs.wrappers

Nested and transform XPK codecs.

Derived from Ancient’s CYB2Decoder and SDHCDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_cyb2

@register("CYB2")
def decompress_cyb2(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode a CYB2 wrapper around another XPK codec payload.

decompress_sdhc

@register("SDHC")
def decompress_sdhc(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode SDHC’s optional nested stream and sample delta transform.

xfh.codecs.nuke

XPK NUKE decompression.

Derived from Ancient’s NUKEDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_nuke

@register("NUKE")
def decompress_nuke(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one NUKE chunk.

decompress_duke

@register("DUKE")
def decompress_duke(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode NUKE data followed by DUKE’s byte-delta transform.

xfh.codecs.shri

XPK SHRI decompression.

Derived from Ancient’s SHRXDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

ShriState Objects

@dataclass(slots=True)
class ShriState()

Adaptive model carried by SHRI version 2 continuation chunks.

decompress_shri_chunk

def decompress_shri_chunk(payload: bytes,
                          output_size: int,
                          previous: bytes,
                          state: ShriState | None,
                          *,
                          shr3: bool = False) -> tuple[bytes, ShriState]

Decode one SHRI chunk and return its continuation model.

decompress_shri

@register("SHRI")
def decompress_shri(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one independently initialized SHRI chunk.

decompress_shr3

@register("SHR3")
def decompress_shr3(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one independently initialized SHR3 chunk.

xfh.codecs.rle

XPK byte-run codecs.

Derived from Ancient’s CBR0, FRLE, and RLEN decompressors, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_cbr0

@register("CBR1")
@register("CBR0")
def decompress_cbr0(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode Commodore ByteRun-style CBR0/CBR1 data.

decompress_rlen

@register("RLEN")
def decompress_rlen(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode XPK RLEN data.

decompress_frle

@register("FRLE")
def decompress_frle(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode cache-oriented XPK FRLE data.

xfh.codecs.artm

XPK ARTM arithmetic decompression.

Derived from Ancient’s ARTMDecompressor and RangeDecoder, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_artm

@register("ARTM")
def decompress_artm(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode ARTM’s adaptive arithmetic stream.

xfh.codecs.rake

XPK RAKE decompression.

Derived from Ancient’s RAKEDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_rake

@register("FRHT")
@register("RAKE")
def decompress_rake(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one RAKE/FRHT chunk.

xfh.codecs.fbr2

XPK FBR2 decompression.

Derived from Ancient’s FBR2Decompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_fbr2

@register("FBR2")
def decompress_fbr2(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode CyberYAFA FBR2 byte runs.

xfh.codecs.none

The XPK NONE storage codec.

decompress_none

@register("NONE")
def decompress_none(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Return a raw NONE chunk after validating its declared size.

xfh.codecs.lz_small

Small historical XPK LZ codecs.

Derived from Ancient’s LZBSDecompressor, SLZ3Decompressor, and TDCSDecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_lzbs

@register("LZBS")
def decompress_lzbs(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode the CyberYAFA LZBS format.

decompress_slz3

@register("SLZ3")
def decompress_slz3(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode the CyberYAFA SLZ3 format.

decompress_tdcs

@register("TDCS")
def decompress_tdcs(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode TDCS LZ77 data.

xfh.codecs.lhlb

XPK LHLB decompression.

Derived from Ancient’s LHDecompressor and DynamicHuffmanDecoder, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_lhlb

@register("LHLB")
def decompress_lhlb(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode the lh.library-compatible LHLB format.

xfh.codecs.acca

XPK ACCA decompression.

Derived from Ancient’s ACCADecompressor, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_acca

@register("ACCA")
def decompress_acca(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode Andre’s code compression algorithm.

xfh.codecs.hfmn

XPK HFMN decompression.

decompress_hfmn

@register("HFMN")
def decompress_hfmn(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode an HFMN dynamic Huffman stream.

xfh.codecs.blzw

XPK BLZW decompression.

Derived from Ancient’s BLZWDecompressor and LZWDecoder, Copyright (c) 2017-2025 Teemu Suutari, under the BSD 2-Clause License.

decompress_blzw

@register("BLZW")
def decompress_blzw(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode Bryan Ford’s XPK BLZW format.

xfh.codecs.huff

XPK HUFF decompression.

decompress_huff

@register("HUFF")
def decompress_huff(payload: bytes,
                    output_size: int,
                    previous: bytes = b"") -> bytes

Decode one HUFF chunk.

xfh.codecs

XPK codec registry.

register

def register(codec: str) -> Callable[[Decoder], Decoder]

Register a decoder by its four-character XPK identifier.

decode

def decode(codec: str,
           payload: bytes,
           output_size: int,
           previous: bytes = b"") -> bytes

Decode one packed XPK chunk.

supported_codecs

def supported_codecs() -> frozenset[str]

Return codec identifiers implemented by this build.

xfh.errors

Public exception hierarchy.

XfhError Objects

class XfhError(Exception)

Base class for expected recovery failures.

InvalidFormatError Objects

class InvalidFormatError(XfhError)

The input is not a recognized XPK stream.

CorruptDataError Objects

class CorruptDataError(XfhError)

The stream is recognized but fails structural or checksum validation.

UnsupportedCodecError Objects

class UnsupportedCodecError(XfhError)

The stream uses a codec or mode which is not implemented.

PasswordRequiredError Objects

class PasswordRequiredError(XfhError)

The input is encrypted and needs a password.

ResourceLimitError Objects

class ResourceLimitError(XfhError)

The stream exceeds a configured recovery safety limit.

xfh.api

Public recovery API.

detect

def detect(data: bytes | bytearray | memoryview) -> FileFormat

Detect an XPK container variant.

inspect

def inspect(data: bytes | bytearray | memoryview,
            *,
            limits: Limits = DEFAULT_LIMITS) -> FileInfo

Parse and validate stream metadata without decompressing it.

decompress

def decompress(data: bytes | bytearray | memoryview,
               *,
               password: str | bytes | None = None,
               limits: Limits = DEFAULT_LIMITS) -> bytes

Strictly decompress one complete stream.

salvage

def salvage(data: bytes | bytearray | memoryview,
            *,
            limits: Limits = DEFAULT_LIMITS) -> RecoveryResult

Recover verified chunks until the first decoding failure.

decompress_file

def decompress_file(source: str | os.PathLike[str],
                    destination: str | os.PathLike[str],
                    *,
                    overwrite: bool = False,
                    password: str | bytes | None = None,
                    limits: Limits = DEFAULT_LIMITS) -> FileInfo

Decompress to an atomic destination path.

xfh.container

Strict parsers for historical XPK stream containers.

ParsedChunk Objects

@dataclass(frozen=True, slots=True)
class ParsedChunk()

Internal chunk metadata and its encoded bytes.

ParsedFile Objects

@dataclass(frozen=True, slots=True)
class ParsedFile()

Internal parsed stream.

detect_format

def detect_format(data: bytes) -> FileFormat

Detect a supported container without parsing it.

parse

def parse(data: bytes, limits: Limits) -> ParsedFile

Parse and validate one complete stream.