Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zip/src/crc32.rs
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
}