use super::{Ctx, Desc};
use crate::decompressor::core::data::{Input, Stream, Type, corrupt};
use crate::decompressor::core::zstd::{content_size, split, zstd_dictionary};
use crate::decompressor::error::DecodeError;
pub(crate) const ZSTD: Desc = Desc {
id: 22,
min_version: 3,
regens: &[Type::Serial],
variable_regens: false,
inputs: &[Type::Serial],
variable_inputs: 0,
decode,
};
fn decode(
ctx: &mut Ctx<'_>,
inputs: &[Input<'_>],
regens: &mut [Stream],
) -> Result<(), DecodeError> {
let (width, frame) = split(inputs[0].bytes)?;
let size = content_size(frame)?;
if !size.is_multiple_of(width) {
return Err(corrupt());
}
let width = usize::try_from(width).or(Err(corrupt()))?;
let size = usize::try_from(size).or(Err(corrupt()))?;
let out = regens[0].fixed(width, size / width)?;
out.resize(size, 0);
ctx.state.zstd.decode(frame, out, zstd_dictionary(ctx.dict))
}
#[cfg(test)]
mod tests {
use super::super::State;
use super::*;
use crate::Backend;
fn stream(width: u8, input: &[u8]) -> alloc::vec::Vec<u8> {
let mut encoder = mzstd::Compressor::default();
let mut stream = alloc::vec![width];
stream.extend_from_slice(&encoder.compress(input).unwrap()[4..]);
stream
}
#[test]
fn intermediate_streams_are_serial_bytes() {
let mut state = State::new(Backend::default());
let mut ctx = Ctx::new(&mut state, &[]);
let bytes = stream(1, &[1, 2, 3, 4]);
let mut regens = [Stream::default()];
regens[0].prepare(Type::Serial, 64);
decode(&mut ctx, &[Input::serial(&bytes)], &mut regens).unwrap();
assert_eq!(regens[0].as_input().width, 1);
assert_eq!(regens[0].bytes(), [1, 2, 3, 4]);
let bytes = stream(2, &[1, 2, 3, 4]);
regens[0].prepare(Type::Serial, 64);
assert_eq!(
decode(&mut ctx, &[Input::serial(&bytes)], &mut regens),
Err(corrupt())
);
let bytes = stream(2, &[1, 2, 3]);
regens[0].prepare(Type::Serial, 64);
assert_eq!(
decode(&mut ctx, &[Input::serial(&bytes)], &mut regens),
Err(corrupt())
);
let bytes = stream(1, &[0; 100]);
regens[0].prepare(Type::Serial, 64);
assert_eq!(
decode(&mut ctx, &[Input::serial(&bytes)], &mut regens),
Err(corrupt())
);
}
}