use byteorder::{BigEndian, ByteOrder};
pub const CHECKSUM_TYPE_NONE: u32 = 0;
pub const CHECKSUM_TYPE_CRC32: u32 = 2;
pub fn crc32(data: &[u8]) -> u32 {
crc32fast::hash(data)
}
pub fn extract_crc32(checksum_array: &[u8; 128]) -> u32 {
BigEndian::read_u32(&checksum_array[0..4])
}
pub fn create_checksum_array(crc: u32) -> [u8; 128] {
let mut array = [0u8; 128];
BigEndian::write_u32(&mut array[0..4], crc);
array
}
pub fn has_checksum(checksum_type: u32, checksum_array: &[u8; 128]) -> bool {
if checksum_type != CHECKSUM_TYPE_CRC32 {
return false;
}
extract_crc32(checksum_array) != 0
}
pub fn verify_crc32(
checksum_type: u32,
checksum_array: &[u8; 128],
data: &[u8],
) -> Result<(), (u32, u32)> {
if checksum_type != CHECKSUM_TYPE_CRC32 {
return Ok(());
}
let expected = extract_crc32(checksum_array);
if expected == 0 {
return Ok(());
}
let actual = crc32(data);
if expected == actual {
Ok(())
} else {
Err((expected, actual))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc32_known_value() {
let data = b"123456789";
let crc = crc32(data);
assert_eq!(crc, 0xCBF43926);
}
#[test]
fn test_extract_crc32() {
let mut array = [0u8; 128];
array[0] = 0xDE;
array[1] = 0xAD;
array[2] = 0xBE;
array[3] = 0xEF;
assert_eq!(extract_crc32(&array), 0xDEADBEEF);
}
#[test]
fn test_create_checksum_array() {
let array = create_checksum_array(0xDEADBEEF);
assert_eq!(array[0], 0xDE);
assert_eq!(array[1], 0xAD);
assert_eq!(array[2], 0xBE);
assert_eq!(array[3], 0xEF);
for val in &array[4..128] {
assert_eq!(*val, 0);
}
}
#[test]
fn test_verify_crc32_match() {
let data = b"test data";
let crc = crc32(data);
let array = create_checksum_array(crc);
assert!(verify_crc32(CHECKSUM_TYPE_CRC32, &array, data).is_ok());
}
#[test]
fn test_verify_crc32_mismatch() {
let data = b"test data";
let array = create_checksum_array(0x12345678);
let result = verify_crc32(CHECKSUM_TYPE_CRC32, &array, data);
assert!(result.is_err());
}
#[test]
fn test_verify_crc32_zero_skipped() {
let array = [0u8; 128];
assert!(verify_crc32(CHECKSUM_TYPE_CRC32, &array, b"any data").is_ok());
}
#[test]
fn test_verify_crc32_wrong_type_skipped() {
let array = create_checksum_array(0x12345678);
assert!(verify_crc32(CHECKSUM_TYPE_NONE, &array, b"any data").is_ok());
}
#[test]
fn test_has_checksum() {
let array = create_checksum_array(0x12345678);
assert!(has_checksum(CHECKSUM_TYPE_CRC32, &array));
let zero_array = [0u8; 128];
assert!(!has_checksum(CHECKSUM_TYPE_CRC32, &zero_array));
assert!(!has_checksum(CHECKSUM_TYPE_NONE, &array));
}
}