1 //! Helper module to compute a CRC32 checksum 2 3 use std::io; 4 use std::io::prelude::*; 5 6 use crc32fast::Hasher; 7 8 /// Reader that validates the CRC32 when it reaches the EOF. 9 pub struct Crc32Reader<R> { 10 inner: R, 11 hasher: Hasher, 12 check: u32, 13 } 14 15 impl<R> Crc32Reader<R> { 16 /// Get a new Crc32Reader which check the inner reader against checksum. new(inner: R, checksum: u32) -> Crc32Reader<R>17 pub fn new(inner: R, checksum: u32) -> Crc32Reader<R> { 18 Crc32Reader { 19 inner, 20 hasher: Hasher::new(), 21 check: checksum, 22 } 23 } 24 check_matches(&self) -> bool25 fn check_matches(&self) -> bool { 26 self.check == self.hasher.clone().finalize() 27 } 28 into_inner(self) -> R29 pub fn into_inner(self) -> R { 30 self.inner 31 } 32 } 33 34 impl<R: Read> Read for Crc32Reader<R> { read(&mut self, buf: &mut [u8]) -> io::Result<usize>35 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 36 let count = match self.inner.read(buf) { 37 Ok(0) if !buf.is_empty() && !self.check_matches() => { 38 return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) 39 } 40 Ok(n) => n, 41 Err(e) => return Err(e), 42 }; 43 self.hasher.update(&buf[0..count]); 44 Ok(count) 45 } 46 } 47 48 #[cfg(test)] 49 mod test { 50 use super::*; 51 use std::io::Read; 52 53 #[test] test_empty_reader()54 fn test_empty_reader() { 55 let data: &[u8] = b""; 56 let mut buf = [0; 1]; 57 58 let mut reader = Crc32Reader::new(data, 0); 59 assert_eq!(reader.read(&mut buf).unwrap(), 0); 60 61 let mut reader = Crc32Reader::new(data, 1); 62 assert!(reader 63 .read(&mut buf) 64 .unwrap_err() 65 .to_string() 66 .contains("Invalid checksum")); 67 } 68 69 #[test] test_byte_by_byte()70 fn test_byte_by_byte() { 71 let data: &[u8] = b"1234"; 72 let mut buf = [0; 1]; 73 74 let mut reader = Crc32Reader::new(data, 0x9be3e0a3); 75 assert_eq!(reader.read(&mut buf).unwrap(), 1); 76 assert_eq!(reader.read(&mut buf).unwrap(), 1); 77 assert_eq!(reader.read(&mut buf).unwrap(), 1); 78 assert_eq!(reader.read(&mut buf).unwrap(), 1); 79 assert_eq!(reader.read(&mut buf).unwrap(), 0); 80 // Can keep reading 0 bytes after the end 81 assert_eq!(reader.read(&mut buf).unwrap(), 0); 82 } 83 84 #[test] test_zero_read()85 fn test_zero_read() { 86 let data: &[u8] = b"1234"; 87 let mut buf = [0; 5]; 88 89 let mut reader = Crc32Reader::new(data, 0x9be3e0a3); 90 assert_eq!(reader.read(&mut buf[..0]).unwrap(), 0); 91 assert_eq!(reader.read(&mut buf).unwrap(), 4); 92 } 93 } 94