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