use std::io::Cursor;
fn main() {
let expected = b"abcdefghXabcdefghYabcd";
let literals = b"abcdefghXY";
let bitstream = [0x14, 0x01, 0x10, 0xe5, 0x08];
println!("=== Testing Frame Header Variants ===\n");
test_frame(
"No FCS, Multi-segment",
0x00,
None,
literals,
&bitstream,
expected,
);
test_frame(
"FCS=22, Single-segment",
0x20,
Some(expected.len() as u64),
literals,
&bitstream,
expected,
);
test_frame(
"FCS=22, Multi-segment",
0x01,
Some(expected.len() as u64),
literals,
&bitstream,
expected,
);
println!("\n=== Testing raw block with same content ===");
test_raw_frame("Raw block", 0x20, Some(expected.len() as u64), expected);
}
fn test_frame(
name: &str,
fhd: u8,
fcs: Option<u64>,
literals: &[u8],
bitstream: &[u8],
expected: &[u8],
) {
println!("Testing: {}", name);
let mut frame = Vec::new();
frame.extend_from_slice(&0xFD2FB528u32.to_le_bytes());
frame.push(fhd);
let single_segment = (fhd & 0x20) != 0;
if !single_segment {
frame.push(0x48);
}
if let Some(size) = fcs {
let fcs_flag = fhd & 0x03;
match fcs_flag {
0 if single_segment => {
frame.push(size as u8);
}
1 => {
frame.extend_from_slice(&(size as u16).to_le_bytes());
}
2 => {
frame.extend_from_slice(&(size as u32).to_le_bytes());
}
3 => {
frame.extend_from_slice(&size.to_le_bytes());
}
_ => {}
}
}
let mut block = Vec::new();
block.push(0x50);
block.extend_from_slice(literals);
block.push(0x02);
block.push(0x00);
block.extend_from_slice(bitstream);
let block_size = block.len() as u32;
let block_header = (block_size << 3) | 0x05; frame.extend_from_slice(&block_header.to_le_bytes()[0..3]);
frame.extend_from_slice(&block);
println!(" Frame: {:02x?}", &frame[..20.min(frame.len())]);
println!(" FHD byte: 0x{:02x}", fhd);
match zstd::decode_all(Cursor::new(&frame)) {
Ok(decoded) if decoded == expected => println!(" Result: OK!"),
Ok(decoded) => {
println!(" Result: MISMATCH");
println!(
" Got {} bytes: {:?}",
decoded.len(),
String::from_utf8_lossy(&decoded)
);
}
Err(e) => println!(" Result: FAILED - {:?}", e),
}
println!();
}
fn test_raw_frame(name: &str, fhd: u8, fcs: Option<u64>, data: &[u8]) {
println!("Testing: {}", name);
let mut frame = Vec::new();
frame.extend_from_slice(&0xFD2FB528u32.to_le_bytes());
frame.push(fhd);
let single_segment = (fhd & 0x20) != 0;
if !single_segment {
frame.push(0x48);
}
if let Some(size) = fcs {
if single_segment {
frame.push(size as u8);
}
}
let block_header = ((data.len() as u32) << 3) | 0x01;
frame.extend_from_slice(&block_header.to_le_bytes()[0..3]);
frame.extend_from_slice(data);
println!(" Frame: {:02x?}", &frame[..20.min(frame.len())]);
match zstd::decode_all(Cursor::new(&frame)) {
Ok(decoded) if decoded == data => println!(" Result: OK!"),
Ok(decoded) => println!(" Result: MISMATCH - got {} bytes", decoded.len()),
Err(e) => println!(" Result: FAILED - {:?}", e),
}
}