Skip to main content

Crate ppmd_turbo

Crate ppmd_turbo 

Source
Expand description

PPMd variant H (7-Zip’s “Ppmd7”) compression and decompression.

ppmd-turbo implements Dmitry Shkarin’s PPMd variant H context model, its sub-allocator and secondary escape estimation, and the two range coders that carry it in the wild:

  • the LZMA-style range coder 7-Zip uses for the PPMD method in .7z (SevenZDecoder, SevenZEncoder), and
  • the carry-less range coder RAR 2.9 through 4.x uses for its PPMd blocks (RarPpmd; RAR5 has no PPMd).

Output is bit-exact with 7-Zip and RARLAB unrar: a 7z stream encoded here is byte-identical to 7-Zip’s for the same parameters, and a RAR stream decodes to exactly what unrar produces. Writing RAR blocks or archives is out of scope by design; CarrylessEncoder and CarrylessDecoder handle raw carry-less streams for round-trip testing only.

§The step API

Every codec is a step machine over slices the caller owns: a call takes input and an output slice and reports a Progress with exact consumed and produced counts and a status. The codecs never keep caller bytes between calls; a non-final call decodes only while a whole symbol’s worth of input (Params::max_input_per_symbol, at most MAX_INPUT_PER_SYMBOL) remains. Model memory is an Arena the caller can reuse across streams. Errors are typed (ErrorKind), Copy, carry the stream Position, and are sticky until a reset. The io module wraps the 7z pair in Read and Write.

use ppmd_turbo::{Params, SevenZDecoder, SevenZEncoder, SevenZStatus};

let data = b"the quick brown fox jumps over the lazy dog";
let params = Params::new(6, 1 << 20)?.reduced_for(data.len() as u64);

let mut encoder = SevenZEncoder::new(params)?;
let mut stream = vec![0u8; 128];
let mut len = encoder.encode(data, &mut stream)?.produced;
while !{
    let fin = encoder.finish(&mut stream[len..], false)?;
    len += fin.produced;
    fin.done
} {}

let mut decoder = SevenZDecoder::new(params, Some(data.len() as u64))?;
let mut out = vec![0u8; data.len()];
let step = decoder.decode(&stream[..len], true, &mut out)?;
assert_eq!(step.status, SevenZStatus::ReachedSize);
assert_eq!(step.consumed, len);
assert_eq!(&out[..], data);

§Features

  • std (default): the io adapters, the io::Error conversion and run-time x86 SIMD detection. Without it the crate builds on core and alloc, choosing SIMD tiers at compile time; this is checked, not promised. Error implements core::error::Error either way.
  • internals: the engine, for the crate’s own fuzz targets, benches and differential tests. Hidden and unstable.

unsafe is permitted where it pays for itself, and only with a // SAFETY: proof on every block, Miri coverage where Miri can run, and a fuzz target over every decoder and encoder entry point.

Re-exports§

pub use carryless::CarrylessDecoder;
pub use carryless::CarrylessEncoder;
pub use rar::RarPpmd;
pub use rar::RarStatus;
pub use rar::Symbol;
pub use sevenz::Finish;
pub use sevenz::SevenZDecoder;
pub use sevenz::SevenZEncoder;
pub use sevenz::SevenZStatus;

Modules§

carryless
Raw carry-less PPMd streams.
iostd
Read and Write over the 7z step codecs, for code built on std::io (a 7z coder chain, command-line tools).
rar
The RAR framing.
sevenz
The 7z framing: the PPMD method (03 04 01) as .7z carries it.

Structs§

Arena
The memory a model’s sub-allocator works in.
Error
An error from a decoder or encoder, with the stream position it was found at.
Params
The model order and arena size of a PPMd variant H stream, checked against the limits variant H accepts.
Position
Where in a stream an error was found.
Progress
What one step call did.

Enums§

ErrorKind
What went wrong.

Constants§

MAX_INPUT_PER_SYMBOL
The most input any decoder in the crate takes for one symbol, at the largest order: 4 * (64 + 2) bytes of the carry-less coder. A caller that always presents at least this many bytes (or the last of its input) never sees NeedInput with input left to give.

Type Aliases§

Result
The result type used throughout the crate.