| Crates.io | oxiarc-lzhuf |
| lib.rs | oxiarc-lzhuf |
| version | 0.1.0 |
| created_at | 2026-01-12 08:08:27.86877+00 |
| updated_at | 2026-01-12 08:08:27.86877+00 |
| description | Pure Rust LZH (LZSS + Huffman) compression for OxiArc |
| homepage | |
| repository | https://github.com/cool-japan/oxiarc |
| max_upload_size | |
| id | 2037235 |
| size | 69,515 |
Pure Rust implementation of LZH (LZSS + Huffman) compression.
LZH is the compression algorithm used in LHA/LZH archives. It was particularly popular in Japan during the BBS era and is still used in some embedded systems and legacy applications.
This crate implements the core compression algorithm, separate from the archive container format (handled by oxiarc-archive).
use oxiarc_lzhuf::{LzhMethod, LzhEncoder, LzhDecoder, encode_lzh, decode_lzh};
// One-shot compression
let original = b"Hello, World! Hello, World!";
let compressed = encode_lzh(original, LzhMethod::Lh5)?;
// One-shot decompression
let decompressed = decode_lzh(&compressed, LzhMethod::Lh5, original.len())?;
assert_eq!(&decompressed, original);
| Method | Window | Max Length | Huffman | Description |
|---|---|---|---|---|
| lh0 | - | - | None | Stored (no compression) |
| lh4 | 4 KB | 256 | Static | Legacy, rarely used |
| lh5 | 8 KB | 256 | Static | Most common method |
| lh6 | 32 KB | 256 | Static | Better compression |
| lh7 | 64 KB | 256 | Static | Best compression |
LZSS is a variant of LZ77 that only outputs a (length, distance) pair when it saves space:
For each position:
If match found AND match_len >= threshold:
Output: FLAG(1) + LENGTH + DISTANCE
Else:
Output: FLAG(0) + LITERAL_BYTE
Parameters by method:
LZH uses two separate Huffman trees:
CODES Tree (Literals + Lengths):
OFFSETS Tree (Distances):
+------------------+
| CODES tree | (Huffman tree for literals/lengths)
+------------------+
| OFFSETS tree | (Huffman tree for distances)
+------------------+
| Compressed data | (Huffman-coded LZSS tokens)
+------------------+
use oxiarc_lzhuf::LzhMethod;
let method = LzhMethod::Lh5;
println!("Window size: {} bytes", method.window_size());
println!("Position bits: {}", method.position_bits());
use oxiarc_lzhuf::LzhEncoder;
let encoder = LzhEncoder::new(LzhMethod::Lh5);
let compressed = encoder.encode(data)?;
use oxiarc_lzhuf::LzhDecoder;
let mut decoder = LzhDecoder::new(LzhMethod::Lh5, uncompressed_size);
let decompressed = decoder.decode(&compressed)?;
use oxiarc_lzhuf::{LzssEncoder, LzssDecoder, LzssToken};
// Low-level LZSS encoding
let mut encoder = LzssEncoder::new(LzhMethod::Lh5);
let tokens: Vec<LzssToken> = encoder.encode(data);
for token in &tokens {
match token {
LzssToken::Literal(byte) => println!("Literal: {:02x}", byte),
LzssToken::Match { length, distance } => {
println!("Match: len={}, dist={}", length, distance);
}
}
}
use oxiarc_lzhuf::LzhHuffmanTree;
let tree = LzhHuffmanTree::from_code_lengths(&lengths)?;
let symbol = tree.decode(&mut bit_reader)?;
| Module | Description |
|---|---|
methods |
Method definitions (lh0-lh7) |
lzss |
LZSS encoder/decoder |
huffman |
LZH Huffman tree operations |
encode |
High-level encoder |
decode |
High-level decoder |
This implementation is compatible with:
LZH was created by Haruyasu Yoshizaki in 1988 for the LHA archiver. It became the dominant archive format in Japan, particularly on:
The format declined in the 2000s as ZIP became universal, but remains important for:
MIT OR Apache-2.0