use std::cell::RefCell;
use linflate::{InflateError, OVERWRITE_HEADROOM};
thread_local! {
static PROBE_BUF: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
}
const PROBE_THRESHOLD: usize = 4096;
const PROBE_LIMIT: usize = 32768;
const FORWARD_SEARCH_LIMIT: usize = 64 * 1024;
pub const LZ77_WINDOW: usize = 32 * 1024;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpecBoundary {
pub offset: usize,
}
fn find_next_stored_block_end(data: &[u8], start_offset: usize) -> Option<usize> {
let end = (start_offset + FORWARD_SEARCH_LIMIT).min(data.len().saturating_sub(8));
for i in start_offset..end {
if i + 4 > data.len() {
break;
}
let len_val = u16::from_le_bytes([data[i], data[i + 1]]);
let nlen_val = u16::from_le_bytes([data[i + 2], data[i + 3]]);
if len_val != !nlen_val || len_val == 0 {
continue;
}
let next_block = i + 4 + len_val as usize;
if next_block + 8 >= data.len() {
continue;
}
if probe_decode(&data[next_block..]) {
return Some(next_block);
}
}
None
}
pub fn find_next_block(data: &[u8], start_offset: usize) -> Option<SpecBoundary> {
if let Some(next_block) = find_next_stored_block_end(data, start_offset) {
if probe_decode(&data[next_block..]) {
return Some(SpecBoundary { offset: next_block });
}
}
let end = (start_offset + FORWARD_SEARCH_LIMIT).min(data.len().saturating_sub(8));
let mut offset = start_offset;
while offset < end {
if probe_decode(&data[offset..]) {
return Some(SpecBoundary { offset });
}
offset += 64;
}
None
}
pub(crate) fn probe_decode(data: &[u8]) -> bool {
if data.len() < 8 {
return false;
}
let buf_size = PROBE_LIMIT + OVERWRITE_HEADROOM;
PROBE_BUF.with(|b| {
let mut out_buf = b.borrow_mut();
if out_buf.len() < buf_size {
out_buf.resize(buf_size, 0);
}
match linflate::inflate_segment(data, &mut out_buf[..buf_size]) {
Ok(written) => written >= PROBE_THRESHOLD,
Err(InflateError::OutputOverflow) => true,
Err(_) => false,
}
})
}
pub fn split_boundaries_parallel(data: &[u8], n_splits: usize) -> Vec<SpecBoundary> {
if n_splits <= 1 || data.len() < PROBE_THRESHOLD * 2 {
return Vec::new();
}
let found: Vec<Option<SpecBoundary>> = gatling::gatling_forkjoin::gatling_for_each(n_splits - 1, 0, |k| {
let i = k + 1;
let nominal = data.len() * i / n_splits;
find_next_block(data, nominal)
});
let mut result: Vec<SpecBoundary> = found.into_iter().flatten().collect();
result.sort_by_key(|b| b.offset);
result.dedup_by_key(|b| b.offset);
let mut deduped: Vec<SpecBoundary> = Vec::new();
for b in result {
if deduped.last().map_or(true, |last| b.offset - last.offset > PROBE_THRESHOLD) {
deduped.push(b);
}
}
deduped
}
pub fn decode_with_window(
compressed: &[u8],
prefix_window: &[u8],
) -> Result<Vec<u8>, &'static str> {
let prefix_len = prefix_window.len();
let estimate = prefix_len + (compressed.len() * 4).max(256 * 1024) + OVERWRITE_HEADROOM;
let mut out_buf: Vec<u8> = Vec::with_capacity(estimate);
#[allow(clippy::uninit_vec)]
unsafe {
out_buf.set_len(estimate)
};
out_buf[..prefix_len].copy_from_slice(prefix_window);
match linflate::inflate_segment_with_prefix(compressed, &mut out_buf, prefix_len) {
Ok(new_bytes) => {
out_buf.truncate(prefix_len + new_bytes);
out_buf.drain(..prefix_len);
Ok(out_buf)
}
Err(InflateError::OutputOverflow) => {
let bigger = prefix_len + (compressed.len() * 1024).max(4 * 1024 * 1024) + OVERWRITE_HEADROOM;
let mut out_buf2: Vec<u8> = Vec::with_capacity(bigger);
#[allow(clippy::uninit_vec)]
unsafe {
out_buf2.set_len(bigger)
};
out_buf2[..prefix_len].copy_from_slice(prefix_window);
match linflate::inflate_segment_with_prefix(compressed, &mut out_buf2, prefix_len) {
Ok(new_bytes) => {
out_buf2.truncate(prefix_len + new_bytes);
out_buf2.drain(..prefix_len);
Ok(out_buf2)
}
Err(_) => Err("speculative segment decode failed"),
}
}
Err(_) => Err("speculative segment decode failed"),
}
}
pub fn speculative_decode(data: &[u8], n_workers: usize) -> Option<Vec<u8>> {
let splits = split_boundaries_parallel(data, n_workers);
if splits.is_empty() {
return None;
}
let mut ranges: Vec<(usize, usize)> = Vec::with_capacity(splits.len() + 1);
ranges.push((0, splits[0].offset));
for w in splits.windows(2) {
ranges.push((w[0].offset, w[1].offset));
}
ranges.push((splits.last().unwrap().offset, data.len()));
let zeroed_window = vec![0u8; LZ77_WINDOW];
let results: Vec<Option<Vec<u8>>> = gatling::gatling_forkjoin::gatling_for_each(ranges.len(), 0, |i| {
let (start, end) = ranges[i];
let segment = &data[start..end];
let window = if i == 0 { &[] as &[u8] } else { &zeroed_window };
decode_with_window(segment, window).ok()
});
let mut segments: Vec<Vec<u8>> = Vec::with_capacity(results.len());
for r in results {
segments.push(r?);
}
for i in 1..segments.len() {
let prev_len = segments[i - 1].len();
let window_start = prev_len.saturating_sub(LZ77_WINDOW);
let window = segments[i - 1][window_start..].to_vec();
let (seg_start, seg_end) = ranges[i];
let compressed = &data[seg_start..seg_end];
let fixup_len = LZ77_WINDOW.min(segments[i].len());
if fixup_len == 0 {
continue;
}
match decode_with_window_limited(compressed, &window, fixup_len) {
Ok(corrected) => {
let copy_len = corrected.len().min(segments[i].len());
segments[i][..copy_len].copy_from_slice(&corrected[..copy_len]);
}
Err(_) => return None,
}
}
let total_len: usize = segments.iter().map(|s| s.len()).sum();
let mut output = Vec::with_capacity(total_len);
for seg in segments {
output.extend_from_slice(&seg);
}
Some(output)
}
fn decode_with_window_limited(
compressed: &[u8],
prefix_window: &[u8],
limit: usize,
) -> Result<Vec<u8>, &'static str> {
let prefix_len = prefix_window.len();
let buf_size = prefix_len + limit + OVERWRITE_HEADROOM;
let mut out_buf = vec![0u8; buf_size];
out_buf[..prefix_len].copy_from_slice(prefix_window);
match linflate::inflate_segment_with_prefix_limited(
compressed, &mut out_buf, prefix_len, limit,
) {
Ok(new_bytes) => {
let end = prefix_len + new_bytes.min(limit);
Ok(out_buf[prefix_len..end].to_vec())
}
Err(_) => Err("fixup decode failed"),
}
}
fn is_gzip_member_start(raw: &[u8], cand: usize) -> bool {
if cand + 10 >= raw.len() {
return false;
}
if raw[cand] != 0x1f || raw[cand + 1] != 0x8b || raw[cand + 2] != 0x08 {
return false;
}
if raw[cand + 3] & 0xE0 != 0 {
return false;
}
let xfl = raw[cand + 8];
if xfl != 0 && xfl != 2 && xfl != 4 {
return false;
}
let os = raw[cand + 9];
if os > 13 && os != 255 {
return false;
}
use std::io::Read;
let mut dec = flate2::read::GzDecoder::new(&raw[cand..]);
let mut scratch = [0u8; 512];
dec.read(&mut scratch).is_ok()
}
pub fn find_gzip_members(raw: &[u8]) -> Vec<usize> {
let mut members = Vec::new();
if raw.len() < 18 {
return members;
}
members.push(0);
let mut search_from = 10usize;
for cand in memchr::memchr_iter(0x1f, raw) {
if cand < search_from {
continue;
}
if !is_gzip_member_start(raw, cand) {
continue;
}
members.push(cand);
search_from = cand + 10;
}
members
}
pub fn find_gzip_members_parallel(raw: &[u8], n_workers: usize) -> Vec<usize> {
let n = n_workers.max(1);
if n <= 1 || raw.len() < 4 * 1024 * 1024 {
return find_gzip_members(raw);
}
if raw.len() < 18 {
return Vec::new();
}
let len = raw.len();
let per_range: Vec<Vec<usize>> = gatling::gatling_forkjoin::gatling_for_each(n, n, |k| {
let lo = (len * k / n).max(10);
let hi = len * (k + 1) / n;
let mut hits = Vec::new();
if lo >= hi {
return hits;
}
for rel in memchr::memchr_iter(0x1f, &raw[lo..hi]) {
let cand = lo + rel;
if is_gzip_member_start(raw, cand) {
hits.push(cand);
}
}
hits
});
let mut members: Vec<usize> = Vec::with_capacity(per_range.iter().map(|v| v.len()).sum::<usize>() + 1);
members.push(0);
for v in per_range {
members.extend(v);
}
members.sort_unstable();
members.dedup();
members
}
pub fn decode_concatenated_members(raw: &[u8], _n_workers: usize) -> Option<Vec<u8>> {
let members = find_gzip_members(raw);
if members.len() < 2 {
return None;
}
eprintln!("lgz: found {} concatenated gzip members — parallel decode", members.len());
let ranges: Vec<(usize, usize)> = members
.windows(2)
.map(|w| (w[0], w[1]))
.chain(std::iter::once((*members.last().unwrap(), raw.len())))
.collect();
let results: Vec<Result<Vec<u8>, &'static str>> = gatling::gatling_forkjoin::gatling_for_each(ranges.len(), 0, |i| {
let (start, end) = ranges[i];
let member = &raw[start..end];
let mut decoder = flate2::read::GzDecoder::new(member);
let mut output = Vec::new();
use std::io::Read;
decoder.read_to_end(&mut output)
.map_err(|_| "member decode failed")?;
Ok(output)
});
let mut output = Vec::new();
for r in results {
match r {
Ok(data) => output.extend_from_slice(&data),
Err(_) => return None,
}
}
Some(output)
}
pub fn decode_members_parallel(raw: &[u8], n_workers: usize) -> Option<Vec<Vec<u8>>> {
let members = find_gzip_members(raw);
if members.len() < 2 {
return None;
}
let ranges: Vec<(usize, usize)> = members
.windows(2)
.map(|w| (w[0], w[1]))
.chain(std::iter::once((*members.last().unwrap(), raw.len())))
.collect();
let results: Vec<Option<Vec<u8>>> =
gatling::gatling_forkjoin::gatling_for_each(ranges.len(), n_workers, |i| {
let (start, end) = ranges[i];
let member = &raw[start..end];
let mut decoder = flate2::read::GzDecoder::new(member);
let mut output = Vec::new();
use std::io::Read;
decoder.read_to_end(&mut output).ok().map(|_| output)
});
let mut decoded: Vec<Vec<u8>> = Vec::with_capacity(results.len());
for r in results {
decoded.push(r?);
}
Some(decoded)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode_members_parallel_matches_concat() {
fn gz(data: &[u8]) -> Vec<u8> {
use flate2::{write::GzEncoder, Compression};
use std::io::Write;
let mut e = GzEncoder::new(Vec::new(), Compression::default());
e.write_all(data).unwrap();
e.finish().unwrap()
}
let a = vec![0xABu8; 40_000];
let b: Vec<u8> = (0..50_000u32).map(|i| (i % 251) as u8).collect();
let mut raw = gz(&a);
raw.extend_from_slice(&gz(&b));
let members = decode_members_parallel(&raw, 0).expect("two members");
assert_eq!(members.len(), 2);
let mut got = Vec::new();
for m in &members {
got.extend_from_slice(m);
}
let mut want = a.clone();
want.extend_from_slice(&b);
assert_eq!(got, want);
let concat = decode_concatenated_members(&raw, 0).unwrap();
assert_eq!(got, concat);
}
#[test]
fn incidental_gzip_magic_not_treated_as_member() {
use flate2::{write::GzEncoder, Compression};
use std::io::Write;
let fake_header = [0x1f, 0x8b, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x03];
let mut payload = vec![0xA5u8; 5000];
payload.extend_from_slice(&fake_header);
payload.extend_from_slice(&[0x77u8; 5000]);
let raw = {
let mut e = GzEncoder::new(Vec::new(), Compression::none());
e.write_all(&payload).unwrap();
e.finish().unwrap()
};
let hit = memchr::memmem::find(&raw[10..], &fake_header);
assert!(hit.is_some(), "test setup: fake header must survive into stream");
let members = find_gzip_members(&raw);
assert_eq!(members, vec![0], "incidental 1f 8b 08 must not be a member start");
assert!(decode_concatenated_members(&raw, 0).is_none());
let got = crate::decompress_gz(&raw).expect("single-stream decode");
assert_eq!(got, payload, "must roundtrip to the original bytes, not garbage");
}
#[test]
fn probe_valid_deflate_at_start() {
let original = vec![0x42u8; 100_000];
let compressed = miniz_oxide::deflate::compress_to_vec(&original, 6);
assert!(probe_decode(&compressed));
}
#[test]
fn probe_invalid_data_fails() {
let garbage: Vec<u8> = (0u32..2000).map(|i| ((i.wrapping_mul(2654435761)) >> 16) as u8).collect();
assert!(!probe_decode(&garbage));
}
#[test]
fn find_boundary_at_known_position() {
let block_a = miniz_oxide::deflate::compress_to_vec(&vec![0xAA; 50_000], 6);
let stored_len: u16 = 100;
let mut stored_block = vec![0x00u8]; stored_block.extend_from_slice(&stored_len.to_le_bytes());
stored_block.extend_from_slice(&(!stored_len).to_le_bytes());
stored_block.extend_from_slice(&vec![0x55u8; stored_len as usize]);
let block_b = miniz_oxide::deflate::compress_to_vec(&vec![0xBB; 50_000], 6);
let mut combined = block_a.clone();
combined.extend_from_slice(&stored_block);
let expected_split = combined.len(); combined.extend_from_slice(&block_b);
let search_from = block_a.len().saturating_sub(16);
let boundary = find_next_block(&combined, search_from);
assert!(boundary.is_some(), "should find boundary after stored block");
let b = boundary.unwrap();
assert_eq!(b.offset, expected_split,
"boundary {} should be at {}", b.offset, expected_split);
}
#[test]
fn decode_with_empty_window() {
let original = b"The quick brown fox jumps over the lazy dog.".repeat(100);
let compressed = miniz_oxide::deflate::compress_to_vec(&original, 6);
let result = decode_with_window(&compressed, &[]).unwrap();
assert_eq!(result, original);
}
#[test]
fn speculative_split_finds_boundaries() {
let block_a = miniz_oxide::deflate::compress_to_vec(&vec![0xAA; 500_000], 6);
let block_b = miniz_oxide::deflate::compress_to_vec(&vec![0xBB; 500_000], 6);
let mut combined = block_a.clone();
combined.extend_from_slice(&block_b);
eprintln!("Combined: {} bytes (a={}, b={})", combined.len(), block_a.len(), block_b.len());
let splits = split_boundaries_parallel(&combined, 4);
eprintln!("Found {} speculative splits in {} bytes", splits.len(), combined.len());
if combined.len() > PROBE_THRESHOLD * 4 {
assert!(!splits.is_empty(), "should find at least one spec boundary");
}
}
}