Coverage Report

Created: 2025-11-09 06:34

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
102k
    pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22
102k
        Crc32Reader {
23
102k
            inner,
24
102k
            hasher: Hasher::new(),
25
102k
            check: checksum,
26
102k
            ae2_encrypted,
27
102k
        }
28
102k
    }
<zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>>>::new
Line
Count
Source
21
1.67k
    pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22
1.67k
        Crc32Reader {
23
1.67k
            inner,
24
1.67k
            hasher: Hasher::new(),
25
1.67k
            check: checksum,
26
1.67k
            ae2_encrypted,
27
1.67k
        }
28
1.67k
    }
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>>>::new
Line
Count
Source
21
38.7k
    pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22
38.7k
        Crc32Reader {
23
38.7k
            inner,
24
38.7k
            hasher: Hasher::new(),
25
38.7k
            check: checksum,
26
38.7k
            ae2_encrypted,
27
38.7k
        }
28
38.7k
    }
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>>>::new
Line
Count
Source
21
41.7k
    pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22
41.7k
        Crc32Reader {
23
41.7k
            inner,
24
41.7k
            hasher: Hasher::new(),
25
41.7k
            check: checksum,
26
41.7k
            ae2_encrypted,
27
41.7k
        }
28
41.7k
    }
<zip::crc32::Crc32Reader<zip::read::CryptoReader>>::new
Line
Count
Source
21
19.9k
    pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
22
19.9k
        Crc32Reader {
23
19.9k
            inner,
24
19.9k
            hasher: Hasher::new(),
25
19.9k
            check: checksum,
26
19.9k
            ae2_encrypted,
27
19.9k
        }
28
19.9k
    }
29
30
199k
    fn check_matches(&self) -> bool {
31
199k
        self.check == self.hasher.clone().finalize()
32
199k
    }
<zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>>>::check_matches
Line
Count
Source
30
3.43k
    fn check_matches(&self) -> bool {
31
3.43k
        self.check == self.hasher.clone().finalize()
32
3.43k
    }
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>>>::check_matches
Line
Count
Source
30
95.2k
    fn check_matches(&self) -> bool {
31
95.2k
        self.check == self.hasher.clone().finalize()
32
95.2k
    }
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>>>::check_matches
Line
Count
Source
30
76.9k
    fn check_matches(&self) -> bool {
31
76.9k
        self.check == self.hasher.clone().finalize()
32
76.9k
    }
<zip::crc32::Crc32Reader<zip::read::CryptoReader>>::check_matches
Line
Count
Source
30
24.0k
    fn check_matches(&self) -> bool {
31
24.0k
        self.check == self.hasher.clone().finalize()
32
24.0k
    }
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
199k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41
199k
        let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43
199k
        let count = match self.inner.read(buf) {
44
19.5k
            Ok(0) if invalid_check => {
45
19.5k
                return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
46
            }
47
138k
            Ok(n) => n,
48
41.8k
            Err(e) => return Err(e),
49
        };
50
138k
        self.hasher.update(&buf[0..count]);
51
138k
        Ok(count)
52
199k
    }
<zip::crc32::Crc32Reader<bzip2::read::BzDecoder<zip::read::CryptoReader>> as std::io::Read>::read
Line
Count
Source
40
3.43k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41
3.43k
        let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43
3.43k
        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
2.79k
            Ok(n) => n,
48
642
            Err(e) => return Err(e),
49
        };
50
2.79k
        self.hasher.update(&buf[0..count]);
51
2.79k
        Ok(count)
52
3.43k
    }
<zip::crc32::Crc32Reader<flate2::deflate::read::DeflateDecoder<zip::read::CryptoReader>> as std::io::Read>::read
Line
Count
Source
40
95.2k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41
95.2k
        let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43
95.2k
        let count = match self.inner.read(buf) {
44
14.1k
            Ok(0) if invalid_check => {
45
14.1k
                return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
46
            }
47
69.5k
            Ok(n) => n,
48
11.6k
            Err(e) => return Err(e),
49
        };
50
69.5k
        self.hasher.update(&buf[0..count]);
51
69.5k
        Ok(count)
52
95.2k
    }
<zip::crc32::Crc32Reader<zstd::stream::read::Decoder<std::io::buffered::bufreader::BufReader<zip::read::CryptoReader>>> as std::io::Read>::read
Line
Count
Source
40
76.9k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41
76.9k
        let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43
76.9k
        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
47.3k
            Ok(n) => n,
48
29.6k
            Err(e) => return Err(e),
49
        };
50
47.3k
        self.hasher.update(&buf[0..count]);
51
47.3k
        Ok(count)
52
76.9k
    }
<zip::crc32::Crc32Reader<zip::read::CryptoReader> as std::io::Read>::read
Line
Count
Source
40
24.0k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
41
24.0k
        let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted;
42
43
24.0k
        let count = match self.inner.read(buf) {
44
5.45k
            Ok(0) if invalid_check => {
45
5.45k
                return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
46
            }
47
18.5k
            Ok(n) => n,
48
0
            Err(e) => return Err(e),
49
        };
50
18.5k
        self.hasher.update(&buf[0..count]);
51
18.5k
        Ok(count)
52
24.0k
    }
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
}