1//! Helper module to compute a CRC32 checksum
2
3use std::io;
4use std::io::prelude::*;
5
6use crc32fast::Hasher;
7
8/// Reader that validates the CRC32 when it reaches the EOF.
9pub 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
18impl<R> Crc32Reader<R> {
19 /// Get a new Crc32Reader which checks the inner reader against checksum.
20 /// The check is disabled if `ae2_encrypted == true`.
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
30 fn check_matches(&self) -> bool {
31 self.check == self.hasher.clone().finalize()
32 }
33
34 pub fn into_inner(self) -> R {
35 self.inner
36 }
37}
38
39impl<R: Read> Read for Crc32Reader<R> {
40 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41 let invalid_check: bool = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43 let count: usize = match self.inner.read(buf) {
44 Ok(0) if invalid_check => {
45 return Err(io::Error::new(kind:io::ErrorKind::Other, error:"Invalid checksum"))
46 }
47 Ok(n: usize) => n,
48 Err(e: Error) => return Err(e),
49 };
50 self.hasher.update(&buf[0..count]);
51 Ok(count)
52 }
53}
54
55#[cfg(test)]
56mod test {
57 use super::*;
58 use std::io::Read;
59
60 #[test]
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]
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]
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