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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
use std::marker::PhantomData;
/// Module that contains most of the functions exported to C.
use std::{ptr, slice};

pub use tinfl::{
    tinfl_decompress, tinfl_decompress_mem_to_heap, tinfl_decompress_mem_to_mem, tinfl_decompressor,
};

use libc::*;
pub use tdef::{
    tdefl_allocate, tdefl_compress, tdefl_compress_buffer, tdefl_compress_mem_to_heap,
    tdefl_compress_mem_to_mem, tdefl_compress_mem_to_output,
    tdefl_create_comp_flags_from_zip_params, tdefl_deallocate, tdefl_get_adler32,
    tdefl_get_prev_return_status, tdefl_init,
};

use lib_oxide::{InternalState, StateType, StateTypeEnum, StreamOxide, MZ_ADLER32_INIT};

use miniz_oxide::{mz_adler32_oxide, MZError};

#[allow(bad_style)]
#[repr(C)]
#[derive(PartialEq, Eq)]
pub enum CAPIReturnStatus {
    MZ_PARAM_ERROR = -10000,
    MZ_VERSION_ERROR = -6,
    MZ_BUF_ERROR = -5,
    MZ_MEM_ERROR = -4,
    MZ_DATA_ERROR = -3,
    MZ_STREAM_ERROR = -2,
    MZ_ERRNO = -1,
    MZ_OK = 0,
    MZ_STREAM_END = 1,
    MZ_NEED_DICT = 2,
}

/// Deflate flush modes.
#[allow(bad_style)]
#[repr(C)]
#[derive(PartialEq, Eq)]
pub enum CAPIFlush {
    MZ_NO_FLUSH = 0,
    MZ_PARTIAL_FLUSH = 1,
    MZ_SYNC_FLUSH = 2,
    MZ_FULL_FLUSH = 3,
    MZ_FINISH = 4,
    MZ_BLOCK = 5,
}

#[allow(bad_style)]
#[repr(C)]
#[derive(PartialEq, Eq)]
pub enum CAPICompressionStrategy {
    MZ_DEFAULT_STRATEGY = 0,
    MZ_FILTERED = 1,
    MZ_HUFFMAN_ONLY = 2,
    MZ_RLE = 3,
    MZ_FIXED = 4
}

pub const MZ_CRC32_INIT: c_ulong = 0;

pub fn mz_crc32_oxide(crc32: c_uint, data: &[u8]) -> c_uint {
    let mut digest = crc32fast::Hasher::new_with_initial(crc32);
    digest.update(data);
    digest.finalize()
}

/// Signature of function used to allocate the compressor/decompressor structs.
#[allow(bad_style)]
pub type mz_alloc_func = unsafe extern "C" fn(*mut c_void, size_t, size_t) -> *mut c_void;
/// Signature of function used to free the compressor/decompressor structs.
#[allow(bad_style)]
pub type mz_free_func = unsafe extern "C" fn(*mut c_void, *mut c_void);

/// Inner stream state containing pointers to the used buffers and internal state.
#[repr(C)]
#[allow(bad_style)]
#[derive(Debug)]
pub struct mz_stream {
    /// Pointer to the current start of the input buffer.
    pub next_in: *const u8,
    /// Length of the input buffer.
    pub avail_in: c_uint,
    /// The total number of input bytes consumed so far.
    pub total_in: c_ulong,

    /// Pointer to the current start of the output buffer.
    pub next_out: *mut u8,
    /// Space in the output buffer.
    pub avail_out: c_uint,
    /// The total number of bytes output so far.
    pub total_out: c_ulong,

    pub msg: *const c_char,
    /// Compressor or decompressor, if it exists.
    /// This is boxed to work with the current C API.
    pub state: Option<Box<InternalState>>,

    /// Allocation function to use for allocating the internal compressor/decompressor.
    /// Uses `mz_default_alloc_func` if set to `None`.
    pub zalloc: Option<mz_alloc_func>,
    /// Free function to use for allocating the internal compressor/decompressor.
    /// Uses `mz_default_free_func` if `None`.
    pub zfree: Option<mz_free_func>,
    /// Extra data to provide the allocation/deallocation functions.
    /// (Not used for the default ones)
    pub opaque: *mut c_void,

    /// Whether the stream contains a compressor or decompressor.
    pub data_type: StateTypeEnum,
    /// Adler32 checksum of the data that has been compressed or uncompressed.
    pub adler: c_ulong,
    /// Reserved
    pub reserved: c_ulong,
}

impl Default for mz_stream {
    fn default() -> mz_stream {
        mz_stream {
            next_in: ptr::null(),
            avail_in: 0,
            total_in: 0,

            next_out: ptr::null_mut(),
            avail_out: 0,
            total_out: 0,

            msg: ptr::null(),
            state: None,

            zalloc: None,
            zfree: None,
            opaque: ptr::null_mut(),

            data_type: StateTypeEnum::None,
            adler: 0,
            reserved: 0,
        }
    }
}

impl<'io, ST: StateType> StreamOxide<'io, ST> {
    pub fn into_mz_stream(mut self) -> mz_stream {
        mz_stream {
            next_in: self
                .next_in
                .map_or(ptr::null(), |in_slice| in_slice.as_ptr()),
            avail_in: self.next_in.map_or(0, |in_slice| in_slice.len() as c_uint),
            total_in: self.total_in,

            next_out: self
                .next_out
                .as_mut()
                .map_or(ptr::null_mut(), |out_slice| out_slice.as_mut_ptr()),
            avail_out: self
                .next_out
                .as_mut()
                .map_or(0, |out_slice| out_slice.len() as c_uint),
            total_out: self.total_out,

            msg: ptr::null(),

            zalloc: None,
            zfree: None,
            opaque: ptr::null_mut(),
            state: self.state.take(),

            data_type: ST::STATE_TYPE,
            adler: self.adler as c_ulong,
            reserved: 0,
        }
    }

    /// Create a new StreamOxide wrapper from a [mz_stream] object.
    /// Custom allocation functions are not supported, supplying an mz_stream with allocation
    /// function will cause creation to fail.
    ///
    /// Unsafe as the mz_stream object is not guaranteed to be valid. It is up to the
    /// caller to ensure it is.
    pub unsafe fn new(stream: &mut mz_stream) -> Self {
        Self::try_new(stream).expect(
            "Failed to create StreamOxide, wrong state type or tried to specify allocators.",
        )
    }

    /// Try to create a new StreamOxide wrapper from a [mz_stream] object.
    /// Custom allocation functions are not supported, supplying an mz_stream with allocation
    /// functions will cause creation to fail.
    ///
    /// Unsafe as the mz_stream object is not guaranteed to be valid. It is up to the
    /// caller to ensure it is.
    pub unsafe fn try_new(stream: &mut mz_stream) -> Result<Self, MZError> {
        // Make sure we don't make an inflate stream from a deflate stream and vice versa.
        if stream.data_type != ST::STATE_TYPE || stream.zalloc.is_some() || stream.zfree.is_some() {
            return Err(MZError::Param);
        }

        let in_slice = stream
            .next_in
            .as_ref()
            .map(|ptr| slice::from_raw_parts(ptr, stream.avail_in as usize));

        let out_slice = stream
            .next_out
            .as_mut()
            .map(|ptr| slice::from_raw_parts_mut(ptr, stream.avail_out as usize));

        Ok(StreamOxide {
            next_in: in_slice,
            total_in: stream.total_in,
            next_out: out_slice,
            total_out: stream.total_out,
            state: stream.state.take(),
            adler: stream.adler as u32,
            state_type: PhantomData,
        })
    }
}

#[cfg(not(no_c_export))]
unmangle!(
    /// Default allocation function using `malloc`.
    pub unsafe extern "C" fn miniz_def_alloc_func(
        _opaque: *mut c_void,
        items: size_t,
        size: size_t,
    ) -> *mut c_void {
        libc::malloc(items * size)
    }

    /// Default free function using `free`.
    pub unsafe extern "C" fn miniz_def_free_func(_opaque: *mut c_void, address: *mut c_void) {
        libc::free(address)
    }

    pub unsafe extern "C" fn miniz_def_realloc_func(
        _opaque: *mut c_void,
        address: *mut c_void,
        items: size_t,
        size: size_t,
    ) -> *mut c_void {
        libc::realloc(address, items * size)
    }

    /// Calculate adler32 checksum of the provided buffer with the initial adler32 checksum of `adler`.
    /// If c_ulong is wider than 32 bits, only the lower 32 bits will be used.
    ///
    /// Returns MZ_ADLER32_INIT if ptr is `ptr::null`.
    pub unsafe extern "C" fn mz_adler32(adler: c_ulong, ptr: *const u8, buf_len: usize) -> c_ulong {
        ptr.as_ref().map_or(MZ_ADLER32_INIT as c_ulong, |r| {
            let data = slice::from_raw_parts(r, buf_len);
            mz_adler32_oxide(adler as u32, data) as c_ulong
        })
    }

    /// Calculate crc-32 of the provided buffer with the initial CRC32 checksum of `crc`.
    /// If c_ulong is wider than 32 bits, only the lower 32 bits will be used.
    ///
    /// Returns MZ_CRC32_INIT if ptr is `ptr::null`.
    pub unsafe extern "C" fn mz_crc32(crc: c_ulong, ptr: *const u8, buf_len: size_t) -> c_ulong {
        ptr.as_ref().map_or(MZ_CRC32_INIT, |r| {
            let data = slice::from_raw_parts(r, buf_len);
            mz_crc32_oxide(crc as u32, data) as c_ulong
        })
    }
);