Skip to main content

rns_net/common/
compressor.rs

1use rns_core::buffer::types::{Compressor, DecompressError};
2
3pub struct Bzip2Compressor;
4
5impl Compressor for Bzip2Compressor {
6    fn compress(&self, data: &[u8]) -> Option<Vec<u8>> {
7        use bzip2::read::BzEncoder;
8        use bzip2::Compression;
9        use std::io::Read;
10        let mut encoder = BzEncoder::new(data, Compression::default());
11        let mut compressed = Vec::new();
12        encoder.read_to_end(&mut compressed).ok()?;
13        Some(compressed)
14    }
15
16    fn decompress(&self, data: &[u8]) -> Option<Vec<u8>> {
17        self.decompress_bounded(data, usize::MAX).ok()
18    }
19
20    fn decompress_bounded(
21        &self,
22        data: &[u8],
23        max_output_size: usize,
24    ) -> Result<Vec<u8>, DecompressError> {
25        use bzip2::read::BzDecoder;
26        use std::io::Read;
27        let mut decoder = BzDecoder::new(data);
28        let mut decompressed = Vec::new();
29        let mut buf = [0u8; 8192];
30
31        loop {
32            let remaining = max_output_size.saturating_sub(decompressed.len());
33            if remaining == 0 {
34                let mut extra = [0u8; 1];
35                return match decoder.read(&mut extra) {
36                    Ok(0) => Ok(decompressed),
37                    Ok(_) => Err(DecompressError::TooLarge),
38                    Err(_) => Err(DecompressError::InvalidData),
39                };
40            }
41
42            let read_len = remaining.min(buf.len());
43            match decoder.read(&mut buf[..read_len]) {
44                Ok(0) => return Ok(decompressed),
45                Ok(n) => decompressed.extend_from_slice(&buf[..n]),
46                Err(_) => return Err(DecompressError::InvalidData),
47            }
48        }
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn bzip2_bounded_roundtrip_within_limit() {
58        let compressor = Bzip2Compressor;
59        let input = b"hello hello hello hello";
60        let compressed = compressor.compress(input).unwrap();
61        let decompressed = compressor
62            .decompress_bounded(&compressed, input.len())
63            .unwrap();
64        assert_eq!(decompressed, input);
65    }
66
67    #[test]
68    fn bzip2_bounded_rejects_oversized_output() {
69        let compressor = Bzip2Compressor;
70        let input = vec![b'A'; 4096];
71        let compressed = compressor.compress(&input).unwrap();
72        assert_eq!(
73            compressor.decompress_bounded(&compressed, 64),
74            Err(DecompressError::TooLarge)
75        );
76    }
77}