lz4_java_wrc/
compression.rs

1use crate::common::Lz4Error;
2
3/// Used to provide implementation for the LZ4 compression/decompression methods
4pub trait Compression {
5    /// Compress the data.
6    ///
7    /// # Arguments
8    ///
9    /// - input data to compress
10    /// - output buffer to write to. It must be allocated with at least [`Self::get_maximum_compressed_buffer_len()`] bytes.
11    ///
12    /// # Result
13    ///
14    /// The number of bytes written into the output
15    fn compress(&self, input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error>;
16
17    /// Decompress the data.
18    ///
19    /// # Arguments
20    ///
21    /// - input data to compress
22    /// - output buffer to write to. It must be allocated with the number of bytes specified in the header.
23    ///
24    /// # Result
25    ///
26    /// The number of bytes written into the output
27    fn decompress(&self, input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error>;
28
29    /// Find the maximum size of the output buffer when compressing.
30    fn get_maximum_compressed_buffer_len(&self, decompressed_len: usize) -> usize;
31}
32
33// Context
34
35/// Use a given context to switch between LZ4 libraries.
36///
37/// By default only lz4_flex is available. The other ones can be enabled by changing the feature flags.
38///
39/// For most users, [`Context::default()`] is a good option.
40#[derive(Debug, Copy, Clone)]
41pub enum Context {
42    #[cfg(feature = "lz4_flex")]
43    /// Use the lz4_flex library to perform lz4 compression/decompression
44    Lz4Flex,
45    #[cfg(feature = "lz4-sys")]
46    /// Use the lz4-sys library to perform lz4 compression/decompression
47    Lz4Sys,
48}
49
50impl Default for Context {
51    fn default() -> Self {
52        match 0 {
53            #[cfg(feature = "lz4_flex")]
54            x if x == Self::Lz4Flex as usize => Self::Lz4Flex,
55            #[cfg(feature = "lz4-sys")]
56            x if x == Self::Lz4Sys as usize => Self::Lz4Sys,
57            _ => panic!("No feature activated"),
58        }
59    }
60}
61
62impl Compression for Context {
63    fn compress(&self, input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
64        match self {
65            #[cfg(feature = "lz4_flex")]
66            Self::Lz4Flex => lz4_flex::compress(input, output),
67            #[cfg(feature = "lz4-sys")]
68            Self::Lz4Sys => lz4_sys::compress(input, output),
69        }
70    }
71    fn decompress(&self, input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
72        match self {
73            #[cfg(feature = "lz4_flex")]
74            Self::Lz4Flex => lz4_flex::decompress(input, output),
75            #[cfg(feature = "lz4-sys")]
76            Self::Lz4Sys => lz4_sys::decompress(input, output),
77        }
78    }
79    fn get_maximum_compressed_buffer_len(&self, decompressed_len: usize) -> usize {
80        match self {
81            #[cfg(feature = "lz4_flex")]
82            Self::Lz4Flex => lz4_flex::get_maximum_compressed_buffer_len(decompressed_len),
83            #[cfg(feature = "lz4-sys")]
84            Self::Lz4Sys => lz4_sys::get_maximum_compressed_buffer_len(decompressed_len),
85        }
86    }
87}
88
89#[cfg(feature = "lz4_flex")]
90mod lz4_flex {
91    use lz4_flex::block::{compress_into, decompress_into, get_maximum_output_size};
92
93    use crate::common::Lz4Error;
94
95    pub(crate) fn compress(input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
96        Ok(compress_into(input, output)?)
97    }
98    pub(crate) fn decompress(input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
99        Ok(decompress_into(input, output)?)
100    }
101    pub(crate) fn get_maximum_compressed_buffer_len(decompressed_len: usize) -> usize {
102        get_maximum_output_size(decompressed_len)
103    }
104}
105
106#[cfg(feature = "lz4-sys")]
107mod lz4_sys {
108    use libc::{c_char, c_int};
109    use lz4_sys::{LZ4_compressBound, LZ4_compress_default, LZ4_decompress_safe};
110
111    use crate::common::Lz4Error;
112
113    pub(crate) fn compress(input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
114        let written_bytes = unsafe {
115            LZ4_compress_default(
116                input.as_ptr() as *const c_char,
117                output.as_ptr() as *mut c_char,
118                input.len() as c_int,
119                output.len() as c_int,
120            )
121        };
122        if written_bytes < 0 {
123            Err(Lz4Error::Lz4SysCompressError)
124        } else {
125            Ok(written_bytes as usize)
126        }
127    }
128    pub(crate) fn decompress(input: &[u8], output: &mut [u8]) -> Result<usize, Lz4Error> {
129        let written_bytes = unsafe {
130            LZ4_decompress_safe(
131                input.as_ptr() as *const c_char,
132                output.as_mut_ptr() as *mut c_char,
133                input.len() as c_int,
134                output.len() as c_int,
135            )
136        };
137        if written_bytes < 0 {
138            Err(Lz4Error::Lz4SysDecompressError)
139        } else {
140            Ok(written_bytes as usize)
141        }
142    }
143    pub(crate) fn get_maximum_compressed_buffer_len(decompressed_len: usize) -> usize {
144        unsafe { LZ4_compressBound(decompressed_len as c_int) as usize }
145    }
146}