flate2/ffi/
c.rs

1//! Implementation for C backends.
2use std::cmp;
3use std::fmt;
4use std::marker;
5use std::os::raw::{c_int, c_uint};
6use std::ptr;
7
8use super::*;
9use crate::mem;
10
11#[derive(Clone, Default)]
12pub struct ErrorMessage(Option<&'static str>);
13
14impl ErrorMessage {
15    pub fn get(&self) -> Option<&str> {
16        self.0
17    }
18}
19
20pub struct StreamWrapper {
21    // SAFETY: The field `inner` must always be accessed as a raw pointer,
22    // since it points to a cyclic structure, and it must never be copied
23    // by Rust.
24    pub inner: *mut mz_stream,
25}
26
27impl fmt::Debug for StreamWrapper {
28    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
29        write!(f, "StreamWrapper")
30    }
31}
32
33impl Default for StreamWrapper {
34    fn default() -> StreamWrapper {
35        // SAFETY: The field `state` will be initialized across the FFI to
36        // point to the opaque type `mz_internal_state`, which will contain a copy
37        // of `inner`. This cyclic structure breaks the uniqueness invariant of
38        // &mut mz_stream, so we must use a raw pointer instead of Box<mz_stream>.
39        StreamWrapper {
40            inner: Box::into_raw(Box::new(mz_stream {
41                next_in: ptr::null_mut(),
42                avail_in: 0,
43                total_in: 0,
44                next_out: ptr::null_mut(),
45                avail_out: 0,
46                total_out: 0,
47                msg: ptr::null_mut(),
48                adler: 0,
49                data_type: 0,
50                reserved: 0,
51                opaque: ptr::null_mut(),
52                state: ptr::null_mut(),
53
54                #[cfg(any(
55                    // zlib-ng
56                    feature = "zlib-ng",
57                    // libz-sys
58                    all(not(feature = "cloudflare_zlib"), not(feature = "zlib-ng"), not(feature = "zlib-rs"))
59                ))]
60                zalloc: allocator::zalloc,
61                #[cfg(any(
62                    // zlib-ng
63                    feature = "zlib-ng",
64                    // libz-sys
65                    all(not(feature = "cloudflare_zlib"), not(feature = "zlib-ng"), not(feature = "zlib-rs"))
66                ))]
67                zfree: allocator::zfree,
68
69                #[cfg(
70                    // cloudflare-zlib
71                    all(feature = "cloudflare_zlib", not(feature = "zlib-rs"), not(feature = "zlib-ng")),
72                )]
73                zalloc: Some(allocator::zalloc),
74                #[cfg(
75                    // cloudflare-zlib
76                    all(feature = "cloudflare_zlib", not(feature = "zlib-rs"), not(feature = "zlib-ng")),
77                )]
78                zfree: Some(allocator::zfree),
79
80                // for zlib-rs, it is most efficient to have it provide the allocator.
81                // The libz-rs-sys dependency is configured to use the rust system allocator
82                #[cfg(all(feature = "zlib-rs", not(feature = "zlib-ng")))]
83                zalloc: None,
84                #[cfg(all(feature = "zlib-rs", not(feature = "zlib-ng")))]
85                zfree: None,
86            })),
87        }
88    }
89}
90
91impl Drop for StreamWrapper {
92    fn drop(&mut self) {
93        // SAFETY: At this point, every other allocation for struct has been freed by
94        // `inflateEnd` or `deflateEnd`, and no copies of `inner` are retained by `C`,
95        // so it is safe to drop the struct as long as the user respects the invariant that
96        // `inner` must never be copied by Rust.
97        drop(unsafe { Box::from_raw(self.inner) });
98    }
99}
100
101#[cfg(any(
102    // zlib-ng
103    feature = "zlib-ng",
104    // cloudflare-zlib
105    all(feature = "cloudflare_zlib", not(feature = "zlib-rs"), not(feature = "zlib-ng")),
106    // libz-sys
107    all(not(feature = "cloudflare_zlib"), not(feature = "zlib-ng"), not(feature = "zlib-rs")),
108))]
109mod allocator {
110    use super::*;
111
112    use std::alloc::{self, Layout};
113    use std::convert::TryFrom;
114    use std::os::raw::c_void;
115
116    const ALIGN: usize = std::mem::align_of::<usize>();
117
118    fn align_up(size: usize, align: usize) -> usize {
119        (size + align - 1) & !(align - 1)
120    }
121
122    pub extern "C" fn zalloc(_ptr: *mut c_void, items: uInt, item_size: uInt) -> *mut c_void {
123        // We need to multiply `items` and `item_size` to get the actual desired
124        // allocation size. Since `zfree` doesn't receive a size argument we
125        // also need to allocate space for a `usize` as a header so we can store
126        // how large the allocation is to deallocate later.
127        let size = match items
128            .checked_mul(item_size)
129            .and_then(|i| usize::try_from(i).ok())
130            .map(|size| align_up(size, ALIGN))
131            .and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
132        {
133            Some(i) => i,
134            None => return ptr::null_mut(),
135        };
136
137        // Make sure the `size` isn't too big to fail `Layout`'s restrictions
138        let layout = match Layout::from_size_align(size, ALIGN) {
139            Ok(layout) => layout,
140            Err(_) => return ptr::null_mut(),
141        };
142
143        unsafe {
144            // Allocate the data, and if successful store the size we allocated
145            // at the beginning and then return an offset pointer.
146            let ptr = alloc::alloc(layout) as *mut usize;
147            if ptr.is_null() {
148                return ptr as *mut c_void;
149            }
150            *ptr = size;
151            ptr.add(1) as *mut c_void
152        }
153    }
154
155    pub extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
156        unsafe {
157            // Move our address being freed back one pointer, read the size we
158            // stored in `zalloc`, and then free it using the standard Rust
159            // allocator.
160            let ptr = (address as *mut usize).offset(-1);
161            let size = *ptr;
162            let layout = Layout::from_size_align_unchecked(size, ALIGN);
163            alloc::dealloc(ptr as *mut u8, layout)
164        }
165    }
166}
167
168unsafe impl<D: Direction> Send for Stream<D> {}
169unsafe impl<D: Direction> Sync for Stream<D> {}
170
171/// Trait used to call the right destroy/end function on the inner
172/// stream object on drop.
173pub trait Direction {
174    unsafe fn destroy(stream: *mut mz_stream) -> c_int;
175}
176
177#[derive(Debug)]
178pub enum DirCompress {}
179#[derive(Debug)]
180pub enum DirDecompress {}
181
182#[derive(Debug)]
183pub struct Stream<D: Direction> {
184    pub stream_wrapper: StreamWrapper,
185    pub total_in: u64,
186    pub total_out: u64,
187    pub _marker: marker::PhantomData<D>,
188}
189
190impl<D: Direction> Stream<D> {
191    pub fn msg(&self) -> ErrorMessage {
192        // SAFETY: The field `inner` must always be accessed as a raw pointer,
193        // since it points to a cyclic structure. No copies of `inner` can be
194        // retained for longer than the lifetime of `self`.
195        let msg = unsafe { (*self.stream_wrapper.inner).msg };
196        ErrorMessage(if msg.is_null() {
197            None
198        } else {
199            let s = unsafe { std::ffi::CStr::from_ptr(msg) };
200            std::str::from_utf8(s.to_bytes()).ok()
201        })
202    }
203}
204
205impl<D: Direction> Drop for Stream<D> {
206    fn drop(&mut self) {
207        unsafe {
208            let _ = D::destroy(self.stream_wrapper.inner);
209        }
210    }
211}
212
213impl Direction for DirCompress {
214    unsafe fn destroy(stream: *mut mz_stream) -> c_int {
215        mz_deflateEnd(stream)
216    }
217}
218impl Direction for DirDecompress {
219    unsafe fn destroy(stream: *mut mz_stream) -> c_int {
220        mz_inflateEnd(stream)
221    }
222}
223
224#[derive(Debug)]
225pub struct Inflate {
226    pub inner: Stream<DirDecompress>,
227}
228
229impl InflateBackend for Inflate {
230    fn make(zlib_header: bool, window_bits: u8) -> Self {
231        unsafe {
232            let state = StreamWrapper::default();
233            let ret = mz_inflateInit2(
234                state.inner,
235                if zlib_header {
236                    window_bits as c_int
237                } else {
238                    -(window_bits as c_int)
239                },
240            );
241            assert_eq!(ret, 0);
242            Inflate {
243                inner: Stream {
244                    stream_wrapper: state,
245                    total_in: 0,
246                    total_out: 0,
247                    _marker: marker::PhantomData,
248                },
249            }
250        }
251    }
252
253    fn decompress(
254        &mut self,
255        input: &[u8],
256        output: &mut [u8],
257        flush: FlushDecompress,
258    ) -> Result<Status, DecompressError> {
259        let raw = self.inner.stream_wrapper.inner;
260        // SAFETY: The field `inner` must always be accessed as a raw pointer,
261        // since it points to a cyclic structure. No copies of `inner` can be
262        // retained for longer than the lifetime of `self`.
263        unsafe {
264            (*raw).msg = ptr::null_mut();
265            (*raw).next_in = input.as_ptr() as *mut u8;
266            (*raw).avail_in = cmp::min(input.len(), c_uint::MAX as usize) as c_uint;
267            (*raw).next_out = output.as_mut_ptr();
268            (*raw).avail_out = cmp::min(output.len(), c_uint::MAX as usize) as c_uint;
269
270            let rc = mz_inflate(raw, flush as c_int);
271
272            // Unfortunately the total counters provided by zlib might be only
273            // 32 bits wide and overflow while processing large amounts of data.
274            self.inner.total_in += ((*raw).next_in as usize - input.as_ptr() as usize) as u64;
275            self.inner.total_out += ((*raw).next_out as usize - output.as_ptr() as usize) as u64;
276
277            // reset these pointers so we don't accidentally read them later
278            (*raw).next_in = ptr::null_mut();
279            (*raw).avail_in = 0;
280            (*raw).next_out = ptr::null_mut();
281            (*raw).avail_out = 0;
282
283            match rc {
284                MZ_DATA_ERROR | MZ_STREAM_ERROR | MZ_MEM_ERROR => {
285                    mem::decompress_failed(self.inner.msg())
286                }
287                MZ_OK => Ok(Status::Ok),
288                MZ_BUF_ERROR => Ok(Status::BufError),
289                MZ_STREAM_END => Ok(Status::StreamEnd),
290                MZ_NEED_DICT => mem::decompress_need_dict((*raw).adler as u32),
291                c => panic!("unknown return code: {}", c),
292            }
293        }
294    }
295
296    fn reset(&mut self, zlib_header: bool) {
297        let bits = if zlib_header {
298            MZ_DEFAULT_WINDOW_BITS
299        } else {
300            -MZ_DEFAULT_WINDOW_BITS
301        };
302        unsafe {
303            inflateReset2(self.inner.stream_wrapper.inner, bits);
304        }
305        self.inner.total_out = 0;
306        self.inner.total_in = 0;
307    }
308}
309
310impl Backend for Inflate {
311    #[inline]
312    fn total_in(&self) -> u64 {
313        self.inner.total_in
314    }
315
316    #[inline]
317    fn total_out(&self) -> u64 {
318        self.inner.total_out
319    }
320}
321
322#[derive(Debug)]
323pub struct Deflate {
324    pub inner: Stream<DirCompress>,
325}
326
327impl DeflateBackend for Deflate {
328    fn make(level: Compression, zlib_header: bool, window_bits: u8) -> Self {
329        unsafe {
330            let state = StreamWrapper::default();
331            let ret = mz_deflateInit2(
332                state.inner,
333                level.0 as c_int,
334                MZ_DEFLATED,
335                if zlib_header {
336                    window_bits as c_int
337                } else {
338                    -(window_bits as c_int)
339                },
340                8,
341                MZ_DEFAULT_STRATEGY,
342            );
343            assert_eq!(ret, 0);
344            Deflate {
345                inner: Stream {
346                    stream_wrapper: state,
347                    total_in: 0,
348                    total_out: 0,
349                    _marker: marker::PhantomData,
350                },
351            }
352        }
353    }
354    fn compress(
355        &mut self,
356        input: &[u8],
357        output: &mut [u8],
358        flush: FlushCompress,
359    ) -> Result<Status, CompressError> {
360        let raw = self.inner.stream_wrapper.inner;
361        // SAFETY: The field `inner` must always be accessed as a raw pointer,
362        // since it points to a cyclic structure. No copies of `inner` can be
363        // retained for longer than the lifetime of `self`.
364        unsafe {
365            (*raw).msg = ptr::null_mut();
366            (*raw).next_in = input.as_ptr() as *mut _;
367            (*raw).avail_in = cmp::min(input.len(), c_uint::MAX as usize) as c_uint;
368            (*raw).next_out = output.as_mut_ptr();
369            (*raw).avail_out = cmp::min(output.len(), c_uint::MAX as usize) as c_uint;
370
371            let rc = mz_deflate(raw, flush as c_int);
372
373            // Unfortunately the total counters provided by zlib might be only
374            // 32 bits wide and overflow while processing large amounts of data.
375
376            self.inner.total_in += ((*raw).next_in as usize - input.as_ptr() as usize) as u64;
377            self.inner.total_out += ((*raw).next_out as usize - output.as_ptr() as usize) as u64;
378            // reset these pointers so we don't accidentally read them later
379            (*raw).next_in = ptr::null_mut();
380            (*raw).avail_in = 0;
381            (*raw).next_out = ptr::null_mut();
382            (*raw).avail_out = 0;
383
384            match rc {
385                MZ_OK => Ok(Status::Ok),
386                MZ_BUF_ERROR => Ok(Status::BufError),
387                MZ_STREAM_END => Ok(Status::StreamEnd),
388                MZ_STREAM_ERROR => mem::compress_failed(self.inner.msg()),
389                c => panic!("unknown return code: {}", c),
390            }
391        }
392    }
393
394    fn reset(&mut self) {
395        self.inner.total_in = 0;
396        self.inner.total_out = 0;
397        let rc = unsafe { mz_deflateReset(self.inner.stream_wrapper.inner) };
398        assert_eq!(rc, MZ_OK);
399    }
400}
401
402impl Backend for Deflate {
403    #[inline]
404    fn total_in(&self) -> u64 {
405        self.inner.total_in
406    }
407
408    #[inline]
409    fn total_out(&self) -> u64 {
410        self.inner.total_out
411    }
412}
413
414pub use self::c_backend::*;
415
416/// For backwards compatibility, we provide symbols as `mz_` to mimic the miniz API
417#[allow(bad_style)]
418#[allow(unused_imports)]
419mod c_backend {
420    use std::mem;
421    use std::os::raw::{c_char, c_int};
422
423    #[cfg(feature = "zlib-ng")]
424    use libz_ng_sys as libz;
425
426    #[cfg(all(feature = "zlib-rs", not(feature = "zlib-ng")))]
427    use libz_rs_sys as libz;
428
429    #[cfg(
430        // cloudflare-zlib
431        all(feature = "cloudflare_zlib", not(feature = "zlib-rs"), not(feature = "zlib-ng")),
432    )]
433    use cloudflare_zlib_sys as libz;
434
435    #[cfg(
436        // libz-sys
437        all(not(feature = "cloudflare_zlib"), not(feature = "zlib-ng"), not(feature = "zlib-rs")),
438    )]
439    use libz_sys as libz;
440
441    pub use libz::deflate as mz_deflate;
442    pub use libz::deflateEnd as mz_deflateEnd;
443    pub use libz::deflateReset as mz_deflateReset;
444    pub use libz::inflate as mz_inflate;
445    pub use libz::inflateEnd as mz_inflateEnd;
446    pub use libz::z_stream as mz_stream;
447    pub use libz::*;
448
449    pub use libz::Z_BLOCK as MZ_BLOCK;
450    pub use libz::Z_BUF_ERROR as MZ_BUF_ERROR;
451    pub use libz::Z_DATA_ERROR as MZ_DATA_ERROR;
452    pub use libz::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY;
453    pub use libz::Z_DEFLATED as MZ_DEFLATED;
454    pub use libz::Z_FINISH as MZ_FINISH;
455    pub use libz::Z_FULL_FLUSH as MZ_FULL_FLUSH;
456    pub use libz::Z_MEM_ERROR as MZ_MEM_ERROR;
457    pub use libz::Z_NEED_DICT as MZ_NEED_DICT;
458    pub use libz::Z_NO_FLUSH as MZ_NO_FLUSH;
459    pub use libz::Z_OK as MZ_OK;
460    pub use libz::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH;
461    pub use libz::Z_STREAM_END as MZ_STREAM_END;
462    pub use libz::Z_STREAM_ERROR as MZ_STREAM_ERROR;
463    pub use libz::Z_SYNC_FLUSH as MZ_SYNC_FLUSH;
464
465    pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;
466
467    #[cfg(feature = "zlib-ng")]
468    const ZLIB_VERSION: &'static str = "2.1.0.devel\0";
469    #[cfg(all(not(feature = "zlib-ng"), feature = "zlib-rs"))]
470    const ZLIB_VERSION: &'static str = "1.3.0-zlib-rs-0.4.2\0";
471    #[cfg(not(any(feature = "zlib-ng", feature = "zlib-rs")))]
472    const ZLIB_VERSION: &'static str = "1.2.8\0";
473
474    pub unsafe extern "C" fn mz_deflateInit2(
475        stream: *mut mz_stream,
476        level: c_int,
477        method: c_int,
478        window_bits: c_int,
479        mem_level: c_int,
480        strategy: c_int,
481    ) -> c_int {
482        libz::deflateInit2_(
483            stream,
484            level,
485            method,
486            window_bits,
487            mem_level,
488            strategy,
489            ZLIB_VERSION.as_ptr() as *const c_char,
490            mem::size_of::<mz_stream>() as c_int,
491        )
492    }
493    pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int {
494        libz::inflateInit2_(
495            stream,
496            window_bits,
497            ZLIB_VERSION.as_ptr() as *const c_char,
498            mem::size_of::<mz_stream>() as c_int,
499        )
500    }
501}