use std::io::{self, ErrorKind};
#[cfg(feature = "crc-validation")]
use crc::{CRC_32_MPEG_2, Crc};
#[cfg(feature = "crc-validation")]
pub const MPEG_2: Crc<u32> = Crc::<u32>::new(&CRC_32_MPEG_2);
#[cfg(feature = "crc-validation")]
pub fn validate_crc(data: &[u8], expected_crc: u32) -> bool {
let calculated_crc = MPEG_2.checksum(data);
calculated_crc == expected_crc
}
#[cfg(not(feature = "crc-validation"))]
pub fn validate_crc(_data: &[u8], _expected_crc: u32) -> bool {
false }
#[cfg(feature = "crc-validation")]
pub fn calculate_crc(data: &[u8]) -> Option<u32> {
Some(MPEG_2.checksum(data))
}
#[cfg(not(feature = "crc-validation"))]
pub fn calculate_crc(_data: &[u8]) -> Option<u32> {
None
}
pub fn validate_message_crc(buffer: &[u8]) -> Result<bool, io::Error> {
if buffer.len() < 4 {
return Err(io::Error::new(
ErrorKind::InvalidData,
"Buffer too short to contain CRC-32 field",
));
}
let crc_bytes = &buffer[buffer.len() - 4..];
let stored_crc = u32::from_be_bytes([crc_bytes[0], crc_bytes[1], crc_bytes[2], crc_bytes[3]]);
let data = &buffer[0..buffer.len() - 4];
Ok(validate_crc(data, stored_crc))
}
pub trait CrcValidatable {
fn validate_crc(&self, original_buffer: &[u8]) -> Result<bool, io::Error>;
fn get_crc(&self) -> u32;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "crc-validation")]
fn test_crc_calculation() {
let test_data = b"Hello, SCTE-35!";
let crc = calculate_crc(test_data);
assert!(crc.is_some());
let calculated = crc.unwrap();
assert!(validate_crc(test_data, calculated));
}
#[test]
#[cfg(not(feature = "crc-validation"))]
fn test_crc_disabled() {
let test_data = b"Hello, SCTE-35!";
let crc = calculate_crc(test_data);
assert!(crc.is_none());
assert!(!validate_crc(test_data, 0));
}
#[test]
fn test_message_crc_validation_short_buffer() {
let short_buffer = vec![0x01, 0x02]; let result = validate_message_crc(&short_buffer);
assert!(result.is_err());
}
#[test]
#[cfg(feature = "crc-validation")]
fn test_message_crc_validation() {
let mut test_data = vec![0xFC, 0x30, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00];
if let Some(calculated_crc) = calculate_crc(&test_data) {
test_data.extend_from_slice(&calculated_crc.to_be_bytes());
let result = validate_message_crc(&test_data);
assert!(result.is_ok());
assert!(result.unwrap());
}
}
}