lzexe 0.1.1

LZEXE 0.90/0.91/0.91e decompressor for DOS EXE files
Documentation
  • Coverage
  • 100%
    3 out of 3 items documented3 out of 3 items with examples
  • Size
  • Source code size: 89.08 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 286.84 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 28s Average build duration of successful builds.
  • all releases: 17s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • rahulsundaram/lzexe
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • rahulsundaram

lzexe

A pure-Rust decompressor for DOS EXE files packed with LZEXE — the packer written by Fabrice Bellard in 1989/1990 that shipped with many early DOS games (id Software, Apogee, Softdisk, and others). LZEXE uses the LZSS (Lempel-Ziv-Storer-Szymanski) algorithm internally; this crate is unrelated to LZW.

Supports LZEXE 0.90, 0.91, and 0.91e.

Library usage

let compressed = std::fs::read("program.exe").unwrap();

// Transparently handles both compressed and uncompressed EXEs.
// Returns Ok(input.to_vec()) for uncompressed files — no allocation
// until the LZEXE signature is confirmed.
let data = lzexe::decompress(&compressed).unwrap();

Check without decompressing:

if lzexe::is_compressed(&bytes) {
    println!("Packed with LZEXE");
}

unlzexe CLI

A drop-in replacement for the classic DOS UNLZEXE utility:

unlzexe input.exe [output.exe]

If output.exe is omitted the decompressed file is written to the same directory as the input with the same name. Exit codes: 0 = success, 1 = error, 2 = input is not LZEXE-compressed.

Install from crates.io:

cargo install lzexe

Output format

The returned Vec<u8> is a valid MZ EXE with a reconstructed header followed by the decompressed load image. Absolute file offsets in the output match those of the original uncompressed binary, so asset extractors that rely on fixed offsets work without modification.

All EXE header fields are recovered from the packed file's info block and the packer's header transformation formulas (see lzexe.pas):

Field Recovery method
IP, CS, SP, SS Stored verbatim in the LZEXE info block at CS:0
minalloc compressed_minalloc − (decalage + dcmpsizepar + 9)
maxalloc Same subtraction; 0xFFFF if the compressed value was clamped
Relocation table Delta-decoded from the packed reloc stream at CS:0x158 (v0.91) or CS:0x19D (v0.90)

No dependencies

Zero runtime dependencies. no_std-compatible (requires alloc).

Testing

The integration tests use the official LZEXE 0.91 binaries (LZEXE.EXE and UPACKEXE.EXE) as fixtures — both are self-compressed with LZEXE 0.91 and distributed by Bellard under the MIT license. Golden output files are committed alongside them for byte-exact regression testing.

Additional synthetic test vectors from camoto-project/gamecompjs (GPL-3.0) cover all three LZEXE versions: 0.90, 0.91, and 0.91e.

cargo test

Correctness is verified independently of our own output by checking that the decompressed binaries contain version strings that appear verbatim in the Pascal source ("LZEXE.EXE Version 0.91", "UPACKEXE").

References