miniz_oxide_c_api/
c_export.rs

1use std::marker::PhantomData;
2/// Module that contains most of the functions exported to C.
3use std::{ptr, slice};
4
5pub use crate::tinfl::{
6    tinfl_decompress, tinfl_decompress_mem_to_heap, tinfl_decompress_mem_to_mem,
7    tinfl_decompressor, tinfl_status,
8};
9
10pub use crate::tdef::{
11    tdefl_allocate, tdefl_compress, tdefl_compress_buffer, tdefl_compress_mem_to_heap,
12    tdefl_compress_mem_to_mem, tdefl_compress_mem_to_output,
13    tdefl_create_comp_flags_from_zip_params, tdefl_deallocate, tdefl_flush, tdefl_get_adler32,
14    tdefl_get_prev_return_status, tdefl_init,
15};
16use libc::*;
17
18use crate::lib_oxide::{InternalState, StateType, StateTypeEnum, StreamOxide, MZ_ADLER32_INIT};
19
20use miniz_oxide::{mz_adler32_oxide, MZError};
21
22#[allow(bad_style)]
23mod mz_typedefs {
24    use libc::*;
25
26    pub type mz_uint32 = c_uint;
27    pub type mz_uint = c_uint;
28    pub type mz_bool = c_int;
29}
30pub use mz_typedefs::*;
31
32#[allow(bad_style)]
33#[repr(C)]
34#[derive(PartialEq, Eq)]
35pub enum CAPIReturnStatus {
36    MZ_PARAM_ERROR = -10000,
37    MZ_VERSION_ERROR = -6,
38    MZ_BUF_ERROR = -5,
39    MZ_MEM_ERROR = -4,
40    MZ_DATA_ERROR = -3,
41    MZ_STREAM_ERROR = -2,
42    MZ_ERRNO = -1,
43    MZ_OK = 0,
44    MZ_STREAM_END = 1,
45    MZ_NEED_DICT = 2,
46}
47
48/// Deflate flush modes.
49#[allow(bad_style)]
50#[repr(C)]
51#[derive(PartialEq, Eq)]
52pub enum CAPIFlush {
53    MZ_NO_FLUSH = 0,
54    MZ_PARTIAL_FLUSH = 1,
55    MZ_SYNC_FLUSH = 2,
56    MZ_FULL_FLUSH = 3,
57    MZ_FINISH = 4,
58    MZ_BLOCK = 5,
59}
60
61#[allow(bad_style)]
62#[repr(C)]
63#[derive(PartialEq, Eq)]
64pub enum CAPICompressionStrategy {
65    MZ_DEFAULT_STRATEGY = 0,
66    MZ_FILTERED = 1,
67    MZ_HUFFMAN_ONLY = 2,
68    MZ_RLE = 3,
69    MZ_FIXED = 4,
70}
71
72/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */
73#[allow(bad_style)]
74#[repr(C)]
75#[derive(PartialEq, Eq)]
76pub enum CAPICompressionLevel {
77    MZ_NO_COMPRESSION = 0,
78    MZ_BEST_SPEED = 1,
79    MZ_BEST_COMPRESSION = 9,
80    MZ_UBER_COMPRESSION = 10,
81    MZ_DEFAULT_LEVEL = 6,
82    MZ_DEFAULT_COMPRESSION = -1,
83}
84
85pub const MZ_CRC32_INIT: c_ulong = 0;
86
87pub fn mz_crc32_oxide(crc32: c_uint, data: &[u8]) -> c_uint {
88    let mut digest = crc32fast::Hasher::new_with_initial(crc32);
89    digest.update(data);
90    digest.finalize()
91}
92
93/// Signature of function used to allocate the compressor/decompressor structs.
94#[allow(bad_style)]
95pub type mz_alloc_func = unsafe extern "C" fn(*mut c_void, size_t, size_t) -> *mut c_void;
96/// Signature of function used to free the compressor/decompressor structs.
97#[allow(bad_style)]
98pub type mz_free_func = unsafe extern "C" fn(*mut c_void, *mut c_void);
99
100#[allow(bad_style)]
101pub type mz_realloc_func =
102    unsafe extern "C" fn(*mut c_void, *mut c_void, size_t, size_t) -> *mut c_void;
103
104#[allow(bad_style)]
105pub type mz_alloc_callback =
106    Option<unsafe extern "C" fn(*mut c_void, size_t, size_t) -> *mut c_void>;
107
108#[allow(bad_style)]
109pub type mz_free_callback = Option<unsafe extern "C" fn(*mut c_void, *mut c_void)>;
110
111/// Inner stream state containing pointers to the used buffers and internal state.
112#[repr(C)]
113#[allow(bad_style)]
114#[derive(Debug)]
115pub struct mz_stream {
116    /// Pointer to the current start of the input buffer.
117    pub next_in: *const u8,
118    /// Length of the input buffer.
119    pub avail_in: c_uint,
120    /// The total number of input bytes consumed so far.
121    pub total_in: c_ulong,
122
123    /// Pointer to the current start of the output buffer.
124    pub next_out: *mut u8,
125    /// Space in the output buffer.
126    pub avail_out: c_uint,
127    /// The total number of bytes output so far.
128    pub total_out: c_ulong,
129
130    pub msg: *const c_char,
131    /// Compressor or decompressor, if it exists.
132    /// This is boxed to work with the current C API.
133    pub state: Option<Box<InternalState>>,
134
135    /// Allocation function to use for allocating the internal compressor/decompressor.
136    /// Uses `mz_default_alloc_func` if set to `None`.
137    pub zalloc: mz_alloc_callback,
138    /// Free function to use for allocating the internal compressor/decompressor.
139    /// Uses `mz_default_free_func` if `None`.
140    pub zfree: mz_free_callback,
141    /// Extra data to provide the allocation/deallocation functions.
142    /// (Not used for the default ones)
143    pub opaque: *mut c_void,
144
145    /// Whether the stream contains a compressor or decompressor.
146    pub data_type: StateTypeEnum,
147    /// Adler32 checksum of the data that has been compressed or uncompressed.
148    pub adler: c_ulong,
149    /// Reserved
150    pub reserved: c_ulong,
151}
152
153impl Default for mz_stream {
154    fn default() -> mz_stream {
155        mz_stream {
156            next_in: ptr::null(),
157            avail_in: 0,
158            total_in: 0,
159
160            next_out: ptr::null_mut(),
161            avail_out: 0,
162            total_out: 0,
163
164            msg: ptr::null(),
165            state: None,
166
167            zalloc: None,
168            zfree: None,
169            opaque: ptr::null_mut(),
170
171            data_type: StateTypeEnum::None,
172            adler: 0,
173            reserved: 0,
174        }
175    }
176}
177
178impl<'io, ST: StateType> StreamOxide<'io, ST> {
179    pub fn into_mz_stream(mut self) -> mz_stream {
180        mz_stream {
181            next_in: self
182                .next_in
183                .map_or(ptr::null(), |in_slice| in_slice.as_ptr()),
184            avail_in: self.next_in.map_or(0, |in_slice| in_slice.len() as c_uint),
185            total_in: self.total_in,
186
187            next_out: self
188                .next_out
189                .as_mut()
190                .map_or(ptr::null_mut(), |out_slice| out_slice.as_mut_ptr()),
191            avail_out: self
192                .next_out
193                .as_mut()
194                .map_or(0, |out_slice| out_slice.len() as c_uint),
195            total_out: self.total_out,
196
197            msg: ptr::null(),
198
199            zalloc: None,
200            zfree: None,
201            opaque: ptr::null_mut(),
202            state: self.state.take(),
203
204            data_type: ST::STATE_TYPE,
205            adler: self.adler as c_ulong,
206            reserved: 0,
207        }
208    }
209
210    /// Create a new StreamOxide wrapper from a [mz_stream] object.
211    /// Custom allocation functions are not supported, supplying an mz_stream with allocation
212    /// function will cause creation to fail.
213    ///
214    /// Unsafe as the mz_stream object is not guaranteed to be valid. It is up to the
215    /// caller to ensure it is.
216    pub unsafe fn new(stream: &mut mz_stream) -> Self {
217        Self::try_new(stream).expect(
218            "Failed to create StreamOxide, wrong state type or tried to specify allocators.",
219        )
220    }
221
222    /// Try to create a new StreamOxide wrapper from a [mz_stream] object.
223    /// Custom allocation functions are not supported, supplying an mz_stream with allocation
224    /// functions will cause creation to fail.
225    ///
226    /// Unsafe as the mz_stream object is not guaranteed to be valid. It is up to the
227    /// caller to ensure it is.
228    pub unsafe fn try_new(stream: &mut mz_stream) -> Result<Self, MZError> {
229        // Make sure we don't make an inflate stream from a deflate stream and vice versa.
230        if stream.data_type != ST::STATE_TYPE || stream.zalloc.is_some() || stream.zfree.is_some() {
231            return Err(MZError::Param);
232        }
233
234        let in_slice = stream
235            .next_in
236            .as_ref()
237            .map(|ptr| slice::from_raw_parts(ptr, stream.avail_in as usize));
238
239        let out_slice = stream
240            .next_out
241            .as_mut()
242            .map(|ptr| slice::from_raw_parts_mut(ptr, stream.avail_out as usize));
243
244        Ok(StreamOxide {
245            next_in: in_slice,
246            total_in: stream.total_in,
247            next_out: out_slice,
248            total_out: stream.total_out,
249            state: stream.state.take(),
250            adler: stream.adler as u32,
251            state_type: PhantomData,
252        })
253    }
254}
255
256unmangle!(
257    /// Default allocation function using `malloc`.
258    pub unsafe extern "C" fn miniz_def_alloc_func(
259        _opaque: *mut c_void,
260        items: size_t,
261        size: size_t,
262    ) -> *mut c_void {
263        libc::malloc(items * size)
264    }
265
266    /// Default free function using `free`.
267    pub unsafe extern "C" fn miniz_def_free_func(_opaque: *mut c_void, address: *mut c_void) {
268        libc::free(address)
269    }
270
271    pub unsafe extern "C" fn miniz_def_realloc_func(
272        _opaque: *mut c_void,
273        address: *mut c_void,
274        items: size_t,
275        size: size_t,
276    ) -> *mut c_void {
277        libc::realloc(address, items * size)
278    }
279
280    /// Calculate adler32 checksum of the provided buffer with the initial adler32 checksum of `adler`.
281    /// If c_ulong is wider than 32 bits, only the lower 32 bits will be used.
282    ///
283    /// Returns MZ_ADLER32_INIT if ptr is `ptr::null`.
284    pub unsafe extern "C" fn mz_adler32(adler: c_ulong, ptr: *const u8, buf_len: usize) -> c_ulong {
285        ptr.as_ref().map_or(MZ_ADLER32_INIT as c_ulong, |r| {
286            let data = slice::from_raw_parts(r, buf_len);
287            mz_adler32_oxide(adler as u32, data) as c_ulong
288        })
289    }
290
291    /// Calculate crc-32 of the provided buffer with the initial CRC32 checksum of `crc`.
292    /// If c_ulong is wider than 32 bits, only the lower 32 bits will be used.
293    ///
294    /// Returns MZ_CRC32_INIT if ptr is `ptr::null`.
295    pub unsafe extern "C" fn mz_crc32(crc: c_ulong, ptr: *const u8, buf_len: size_t) -> c_ulong {
296        ptr.as_ref().map_or(MZ_CRC32_INIT, |r| {
297            let data = slice::from_raw_parts(r, buf_len);
298            mz_crc32_oxide(crc as u32, data) as c_ulong
299        })
300    }
301);