99 lines
2.8 KiB
Rust
99 lines
2.8 KiB
Rust
//! Helper module to compute a CRC32 checksum
|
|
|
|
use std::io;
|
|
use std::io::prelude::*;
|
|
|
|
use crc32fast::Hasher;
|
|
|
|
/// Reader that validates the CRC32 when it reaches the EOF.
|
|
pub struct Crc32Reader<R> {
|
|
inner: R,
|
|
hasher: Hasher,
|
|
check: u32,
|
|
/// Signals if `inner` stores aes encrypted data.
|
|
/// AE-2 encrypted data doesn't use crc and sets the value to 0.
|
|
ae2_encrypted: bool,
|
|
}
|
|
|
|
impl<R> Crc32Reader<R> {
|
|
/// Get a new Crc32Reader which checks the inner reader against checksum.
|
|
/// The check is disabled if `ae2_encrypted == true`.
|
|
pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
|
|
Crc32Reader {
|
|
inner,
|
|
hasher: Hasher::new(),
|
|
check: checksum,
|
|
ae2_encrypted,
|
|
}
|
|
}
|
|
|
|
fn check_matches(&self) -> bool {
|
|
self.check == self.hasher.clone().finalize()
|
|
}
|
|
|
|
pub fn into_inner(self) -> R {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl<R: Read> Read for Crc32Reader<R> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
|
|
|
|
let count = match self.inner.read(buf) {
|
|
Ok(0) if invalid_check => {
|
|
return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
|
|
}
|
|
Ok(n) => n,
|
|
Err(e) => return Err(e),
|
|
};
|
|
self.hasher.update(&buf[0..count]);
|
|
Ok(count)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_empty_reader() {
|
|
let data: &[u8] = b"";
|
|
let mut buf = [0; 1];
|
|
|
|
let mut reader = Crc32Reader::new(data, 0, false);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
|
|
let mut reader = Crc32Reader::new(data, 1, false);
|
|
assert!(reader
|
|
.read(&mut buf)
|
|
.unwrap_err()
|
|
.to_string()
|
|
.contains("Invalid checksum"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_byte_by_byte() {
|
|
let data: &[u8] = b"1234";
|
|
let mut buf = [0; 1];
|
|
|
|
let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
// Can keep reading 0 bytes after the end
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_zero_read() {
|
|
let data: &[u8] = b"1234";
|
|
let mut buf = [0; 5];
|
|
|
|
let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false);
|
|
assert_eq!(reader.read(&mut buf[..0]).unwrap(), 0);
|
|
assert_eq!(reader.read(&mut buf).unwrap(), 4);
|
|
}
|
|
}
|