1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use crate::convert::TryTo;

use libc::c_ulong;
use libz_sys;

use thiserror::Error;

#[derive(Error, Debug)]
pub enum DecompressionError {
    #[error("Received invalid data")]
    Failed,
    #[error("Decompressed data is bigger than expected")]
    TooBig,
    #[error("Decompressed data is smaller than expected")]
    TooSmall,
}

pub fn decompress(data: &[u8], expected_size: usize) -> Result<Vec<u8>, DecompressionError> {
    let mut decompressed = Vec::with_capacity(expected_size);
    unsafe {
        let mut decompressed_len = expected_size.try_to::<c_ulong>();
        match libz_sys::uncompress(decompressed.as_mut_ptr(), &mut decompressed_len, data.as_ptr(), data.len().try_to()) {
            libz_sys::Z_OK => {},
            libz_sys::Z_MEM_ERROR => panic!("Decompression: Out of memory"),
            libz_sys::Z_BUF_ERROR => return Err(DecompressionError::TooBig), // compressed data is too long for buffer
            libz_sys::Z_DATA_ERROR => return Err(DecompressionError::Failed), // corrupted data
            e => panic!("Decompression: unexpected zlib error code {}", e),
        }
        if decompressed_len.try_to::<usize>() != expected_size {
            return Err(DecompressionError::TooSmall);
        }
        decompressed.set_len(expected_size);
    }
    Ok(decompressed)
}

pub fn compress(data: &[u8]) -> Vec<u8> {
    let mut compressed;
    unsafe {
        let mut max_size = libz_sys::compressBound(data.len().try_to());
        compressed = Vec::with_capacity(max_size.try_to());
        match libz_sys::compress(compressed.as_mut_ptr(), &mut max_size, data.as_ptr(), data.len().try_to()) {
            libz_sys::Z_OK => {},
            libz_sys::Z_MEM_ERROR => panic!("Compression: Out of memory"),
            libz_sys::Z_BUF_ERROR => panic!("Compression: Invalid buffer size from compressBound"),
            e => panic!("Compression: Unexpected zlib error code {}", e),
        }
        compressed.set_len(max_size.try_to());
    }
    compressed
}