Line | Count | Source |
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`. |
21 | 88.6k | pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { |
22 | 88.6k | Crc32Reader { |
23 | 88.6k | inner, |
24 | 88.6k | hasher: Hasher::new(), |
25 | 88.6k | check: checksum, |
26 | 88.6k | ae2_encrypted, |
27 | 88.6k | } |
28 | 88.6k | } <zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>>>::new Line | Count | Source | 21 | 2.40k | pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { | 22 | 2.40k | Crc32Reader { | 23 | 2.40k | inner, | 24 | 2.40k | hasher: Hasher::new(), | 25 | 2.40k | check: checksum, | 26 | 2.40k | ae2_encrypted, | 27 | 2.40k | } | 28 | 2.40k | } |
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>>>::new Line | Count | Source | 21 | 18.4k | pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { | 22 | 18.4k | Crc32Reader { | 23 | 18.4k | inner, | 24 | 18.4k | hasher: Hasher::new(), | 25 | 18.4k | check: checksum, | 26 | 18.4k | ae2_encrypted, | 27 | 18.4k | } | 28 | 18.4k | } |
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>>>::new Line | Count | Source | 21 | 51.7k | pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { | 22 | 51.7k | Crc32Reader { | 23 | 51.7k | inner, | 24 | 51.7k | hasher: Hasher::new(), | 25 | 51.7k | check: checksum, | 26 | 51.7k | ae2_encrypted, | 27 | 51.7k | } | 28 | 51.7k | } |
<zip::crc32::Crc32Reader<zip::read::CryptoReader>>::new Line | Count | Source | 21 | 16.0k | pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { | 22 | 16.0k | Crc32Reader { | 23 | 16.0k | inner, | 24 | 16.0k | hasher: Hasher::new(), | 25 | 16.0k | check: checksum, | 26 | 16.0k | ae2_encrypted, | 27 | 16.0k | } | 28 | 16.0k | } |
|
29 | | |
30 | 221k | fn check_matches(&self) -> bool { |
31 | 221k | self.check == self.hasher.clone().finalize() |
32 | 221k | } <zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>>>::check_matches Line | Count | Source | 30 | 4.71k | fn check_matches(&self) -> bool { | 31 | 4.71k | self.check == self.hasher.clone().finalize() | 32 | 4.71k | } |
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>>>::check_matches Line | Count | Source | 30 | 72.9k | fn check_matches(&self) -> bool { | 31 | 72.9k | self.check == self.hasher.clone().finalize() | 32 | 72.9k | } |
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>>>::check_matches Line | Count | Source | 30 | 121k | fn check_matches(&self) -> bool { | 31 | 121k | self.check == self.hasher.clone().finalize() | 32 | 121k | } |
<zip::crc32::Crc32Reader<zip::read::CryptoReader>>::check_matches Line | Count | Source | 30 | 22.9k | fn check_matches(&self) -> bool { | 31 | 22.9k | self.check == self.hasher.clone().finalize() | 32 | 22.9k | } |
|
33 | | |
34 | 0 | pub fn into_inner(self) -> R { |
35 | 0 | self.inner |
36 | 0 | } Unexecuted instantiation: <zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>>>::into_inner Unexecuted instantiation: <zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>>>::into_inner Unexecuted instantiation: <zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>>>::into_inner Unexecuted instantiation: <zip::crc32::Crc32Reader<zip::read::CryptoReader>>::into_inner |
37 | | } |
38 | | |
39 | | impl<R: Read> Read for Crc32Reader<R> { |
40 | 221k | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
41 | 221k | let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; |
42 | | |
43 | 221k | let count = match self.inner.read(buf) { |
44 | 4.29k | Ok(0) if invalid_check => { |
45 | 4.29k | return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) |
46 | | } |
47 | 173k | Ok(n) => n, |
48 | 44.4k | Err(e) => return Err(e), |
49 | | }; |
50 | 173k | self.hasher.update(&buf[0..count]); |
51 | 173k | Ok(count) |
52 | 221k | } <zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>> as std::io::Read>::read Line | Count | Source | 40 | 4.71k | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | 41 | 4.71k | let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; | 42 | | | 43 | 4.71k | let count = match self.inner.read(buf) { | 44 | 0 | Ok(0) if invalid_check => { | 45 | 0 | return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) | 46 | | } | 47 | 3.35k | Ok(n) => n, | 48 | 1.36k | Err(e) => return Err(e), | 49 | | }; | 50 | 3.35k | self.hasher.update(&buf[0..count]); | 51 | 3.35k | Ok(count) | 52 | 4.71k | } |
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>> as std::io::Read>::read Line | Count | Source | 40 | 72.9k | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | 41 | 72.9k | let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; | 42 | | | 43 | 72.9k | let count = match self.inner.read(buf) { | 44 | 2.47k | Ok(0) if invalid_check => { | 45 | 2.47k | return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) | 46 | | } | 47 | 67.1k | Ok(n) => n, | 48 | 3.29k | Err(e) => return Err(e), | 49 | | }; | 50 | 67.1k | self.hasher.update(&buf[0..count]); | 51 | 67.1k | Ok(count) | 52 | 72.9k | } |
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>> as std::io::Read>::read Line | Count | Source | 40 | 121k | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | 41 | 121k | let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; | 42 | | | 43 | 121k | let count = match self.inner.read(buf) { | 44 | 0 | Ok(0) if invalid_check => { | 45 | 0 | return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) | 46 | | } | 47 | 81.6k | Ok(n) => n, | 48 | 39.7k | Err(e) => return Err(e), | 49 | | }; | 50 | 81.6k | self.hasher.update(&buf[0..count]); | 51 | 81.6k | Ok(count) | 52 | 121k | } |
<zip::crc32::Crc32Reader<zip::read::CryptoReader> as std::io::Read>::read Line | Count | Source | 40 | 22.9k | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | 41 | 22.9k | let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; | 42 | | | 43 | 22.9k | let count = match self.inner.read(buf) { | 44 | 1.82k | Ok(0) if invalid_check => { | 45 | 1.82k | return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) | 46 | | } | 47 | 21.0k | Ok(n) => n, | 48 | 0 | Err(e) => return Err(e), | 49 | | }; | 50 | 21.0k | self.hasher.update(&buf[0..count]); | 51 | 21.0k | Ok(count) | 52 | 22.9k | } |
|
53 | | } |
54 | | |
55 | | #[cfg(test)] |
56 | | mod 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 | | } |