use crate::error::{Error, Result};
use dvb_common::crc32_mpeg2;
pub const CRC_LEN: usize = 4;
pub fn validate_crc(bytes: &[u8]) -> Result<()> {
if bytes.len() < CRC_LEN {
return Err(Error::BufferTooShort {
need: CRC_LEN,
have: bytes.len(),
what: "T2-MI CRC",
});
}
let (payload, trailer) = bytes.split_at(bytes.len() - CRC_LEN);
let expected = u32::from_be_bytes(trailer.try_into().unwrap());
let computed = crc32_mpeg2::compute(payload);
if computed == expected {
Ok(())
} else {
Err(Error::CrcMismatch { computed, expected })
}
}
#[cfg(test)]
mod tests {
use super::*;
use dvb_common::crc32_mpeg2::compute;
#[test]
fn crc32_of_empty_input_is_initial_state() {
assert_eq!(compute(&[]), 0xFFFF_FFFF);
}
#[test]
fn compute_deterministic_and_not_identity() {
let c = compute(&[0x00]);
assert_eq!(c, compute(&[0x00]));
assert_ne!(c, 0xFFFF_FFFF);
}
#[test]
fn compute_different_inputs_produce_different_results() {
assert_ne!(compute(&[0x00]), compute(&[0x01]));
}
#[test]
fn validate_crc_passes_for_known_packet() {
let data = [0x01, 0x02, 0x03, 0x04];
let c = compute(&data);
let mut buf = Vec::with_capacity(data.len() + CRC_LEN);
buf.extend_from_slice(&data);
buf.extend_from_slice(&c.to_be_bytes());
assert!(validate_crc(&buf).is_ok());
}
#[test]
fn validate_crc_fails_for_corrupted_trailer() {
let data = [0x01, 0x02, 0x03, 0x04];
let c = compute(&data);
let mut buf = Vec::with_capacity(data.len() + CRC_LEN);
buf.extend_from_slice(&data);
buf.extend_from_slice(&c.to_be_bytes());
*buf.last_mut().unwrap() ^= 0xFF;
assert!(validate_crc(&buf).is_err());
}
#[test]
fn validate_crc_fails_for_corrupted_data() {
let data = [0x01, 0x02, 0x03, 0x04];
let c = compute(&data);
let mut buf = Vec::with_capacity(data.len() + CRC_LEN);
buf.extend_from_slice(&data);
buf.extend_from_slice(&c.to_be_bytes());
buf[0] ^= 0xFF;
assert!(validate_crc(&buf).is_err());
}
#[test]
fn validate_crc_rejects_too_short_input() {
assert!(validate_crc(&[0x01, 0x02]).is_err());
}
}