• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /// Signals if `inner` stores aes encrypted data.
14     /// AE-2 encrypted data doesn't use crc and sets the value to 0.
15     ae2_encrypted: bool,
16 }
17 
18 impl<R> Crc32Reader<R> {
19     /// Get a new Crc32Reader which checks the inner reader against checksum.
20     /// The check is disabled if `ae2_encrypted == true`.
new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R>21     pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22         Crc32Reader {
23             inner,
24             hasher: Hasher::new(),
25             check: checksum,
26             ae2_encrypted,
27         }
28     }
29 
check_matches(&self) -> bool30     fn check_matches(&self) -> bool {
31         self.check == self.hasher.clone().finalize()
32     }
33 
into_inner(self) -> R34     pub fn into_inner(self) -> R {
35         self.inner
36     }
37 }
38 
39 impl<R: Read> Read for Crc32Reader<R> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>40     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41         let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42 
43         let count = match self.inner.read(buf) {
44             Ok(0) if invalid_check => {
45                 return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
46             }
47             Ok(n) => n,
48             Err(e) => return Err(e),
49         };
50         self.hasher.update(&buf[0..count]);
51         Ok(count)
52     }
53 }
54 
55 #[cfg(test)]
56 mod test {
57     use super::*;
58     use std::io::Read;
59 
60     #[test]
test_empty_reader()61     fn test_empty_reader() {
62         let data: &[u8] = b"";
63         let mut buf = [0; 1];
64 
65         let mut reader = Crc32Reader::new(data, 0, false);
66         assert_eq!(reader.read(&mut buf).unwrap(), 0);
67 
68         let mut reader = Crc32Reader::new(data, 1, false);
69         assert!(reader
70             .read(&mut buf)
71             .unwrap_err()
72             .to_string()
73             .contains("Invalid checksum"));
74     }
75 
76     #[test]
test_byte_by_byte()77     fn test_byte_by_byte() {
78         let data: &[u8] = b"1234";
79         let mut buf = [0; 1];
80 
81         let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false);
82         assert_eq!(reader.read(&mut buf).unwrap(), 1);
83         assert_eq!(reader.read(&mut buf).unwrap(), 1);
84         assert_eq!(reader.read(&mut buf).unwrap(), 1);
85         assert_eq!(reader.read(&mut buf).unwrap(), 1);
86         assert_eq!(reader.read(&mut buf).unwrap(), 0);
87         // Can keep reading 0 bytes after the end
88         assert_eq!(reader.read(&mut buf).unwrap(), 0);
89     }
90 
91     #[test]
test_zero_read()92     fn test_zero_read() {
93         let data: &[u8] = b"1234";
94         let mut buf = [0; 5];
95 
96         let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false);
97         assert_eq!(reader.read(&mut buf[..0]).unwrap(), 0);
98         assert_eq!(reader.read(&mut buf).unwrap(), 4);
99     }
100 }
101