rns_net/common/
compressor.rs1use 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}