use std::io::{Read, Write};
use ppmd_rust::{Ppmd8Decoder, Ppmd8Encoder, RestoreMethod};
fn pseudo_text(size: usize) -> Vec<u8> {
let mut state: u64 = 0x2545_F491_4F6C_DD1D;
let mut next = move || {
state ^= state << 13;
state ^= state >> 7;
state ^= state << 17;
state
};
let vocabulary: Vec<String> = (0..60_000)
.map(|_| {
let length = 3 + (next() % 7) as usize;
(0..length)
.map(|_| (b'a' + (next() % 26) as u8) as char)
.collect()
})
.collect();
let mut text = Vec::with_capacity(size + 16);
while text.len() < size {
let word = &vocabulary[(next() % vocabulary.len() as u64) as usize];
text.extend_from_slice(word.as_bytes());
text.push(b' ');
}
text
}
#[test]
fn ghsa_rqc2_j9v2_j22v_ppmd8_cut_off_out_of_bounds() {
const ORDER: u32 = 16;
const MEMORY_SIZE: u32 = 1 << 20;
let text = pseudo_text(512 << 10);
let mut compressed = Vec::new();
{
let mut encoder =
Ppmd8Encoder::new(&mut compressed, ORDER, MEMORY_SIZE, RestoreMethod::Restart).unwrap();
encoder.write_all(&text).unwrap();
encoder.finish(true).unwrap();
}
let mut decoder = Ppmd8Decoder::new(
compressed.as_slice(),
ORDER,
MEMORY_SIZE,
RestoreMethod::CutOff,
)
.unwrap();
let mut decompressed = Vec::new();
let _ = decoder.read_to_end(&mut decompressed);
}
#[test]
fn ppmd8_cut_off_round_trip() {
const ORDER: u32 = 16;
const MEMORY_SIZE: u32 = 1 << 20;
let text = pseudo_text(4 * 1024 * 1024);
let mut compressed = Vec::new();
{
let mut encoder =
Ppmd8Encoder::new(&mut compressed, ORDER, MEMORY_SIZE, RestoreMethod::CutOff).unwrap();
encoder.write_all(&text).unwrap();
encoder.finish(true).unwrap();
}
let mut decompressed = Vec::new();
{
let mut decoder = Ppmd8Decoder::new(
compressed.as_slice(),
ORDER,
MEMORY_SIZE,
RestoreMethod::CutOff,
)
.unwrap();
decoder.read_to_end(&mut decompressed).unwrap();
}
assert_eq!(decompressed, text);
}