Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  c.rs   Sprache: unbekannt

 
//! Implementation for C backends.
use std::cmp;
use std::fmt;
use std::marker;
use std::os::raw::{c_int, c_uint};
use std::ptr;

use super::*;
use crate::mem;

#[derive(Default)]
pub struct ErrorMessage(Option<&'static str>);

impl ErrorMessage {
    pub fn get(&self) -> Option<&str> {
        self.0
    }
}

pub struct StreamWrapper {
    // SAFETY: The field `inner` must always be accessed as a raw pointer,
    // since it points to a cyclic structure, and it must never be copied
    // by Rust.
    pub inner: *mut mz_stream,
}

impl fmt::Debug for StreamWrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "StreamWrapper")
    }
}

impl Default for StreamWrapper {
    fn default() -> StreamWrapper {
        // SAFETY: The field `state` will be initialized across the FFI to
        // point to the opaque type `mz_internal_state`, which will contain a copy
        // of `inner`. This cyclic structure breaks the uniqueness invariant of
        // &mut mz_stream, so we must use a raw pointer instead of Box<mz_stream>.
        StreamWrapper {
            inner: Box::into_raw(Box::new(mz_stream {
                next_in: ptr::null_mut(),
                avail_in: 0,
                total_in: 0,
                next_out: ptr::null_mut(),
                avail_out: 0,
                total_out: 0,
                msg: ptr::null_mut(),
                adler: 0,
                data_type: 0,
                reserved: 0,
                opaque: ptr::null_mut(),
                state: ptr::null_mut(),
                #[cfg(all(
                    feature = "any_zlib",
                    not(any(feature = "cloudflare-zlib-sys", feature = "libz-rs-sys"))
                ))]
                zalloc: allocator::zalloc,
                #[cfg(all(
                    feature = "any_zlib",
                    not(any(feature = "cloudflare-zlib-sys", feature = "libz-rs-sys"))
                ))]
                zfree: allocator::zfree,

                #[cfg(all(feature = "any_zlib", feature = "cloudflare-zlib-sys"))]
                zalloc: Some(allocator::zalloc),
                #[cfg(all(feature = "any_zlib", feature = "cloudflare-zlib-sys"))]
                zfree: Some(allocator::zfree),

                // for zlib-rs, it is most efficient to have it provide the allocator.
                // The libz-rs-sys dependency is configured to use the rust system allocator
                #[cfg(all(feature = "any_zlib", feature = "libz-rs-sys"))]
                zalloc: None,
                #[cfg(all(feature = "any_zlib", feature = "libz-rs-sys"))]
                zfree: None,
            })),
        }
    }
}

impl Drop for StreamWrapper {
    fn drop(&mut self) {
        // SAFETY: At this point, every other allocation for struct has been freed by
        // `inflateEnd` or `deflateEnd`, and no copies of `inner` are retained by `C`,
        // so it is safe to drop the struct as long as the user respects the invariant that
        // `inner` must never be copied by Rust.
        drop(unsafe { Box::from_raw(self.inner) });
    }
}

#[cfg(all(feature = "any_zlib", not(feature = "libz-rs-sys")))]
mod allocator {
    use super::*;

    use std::alloc::{self, Layout};
    use std::convert::TryFrom;
    use std::os::raw::c_void;

    const ALIGN: usize = std::mem::align_of::<usize>();

    fn align_up(size: usize, align: usize) -> usize {
        (size + align - 1) & !(align - 1)
    }

    pub extern "C" fn zalloc(_ptr: *mut c_void, items: uInt, item_size: uInt) -> *mut c_void {
        // We need to multiply `items` and `item_size` to get the actual desired
        // allocation size. Since `zfree` doesn't receive a size argument we
        // also need to allocate space for a `usize` as a header so we can store
        // how large the allocation is to deallocate later.
        let size = match items
            .checked_mul(item_size)
            .and_then(|i| usize::try_from(i).ok())
            .map(|size| align_up(size, ALIGN))
            .and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
        {
            Some(i) => i,
            None => return ptr::null_mut(),
        };

        // Make sure the `size` isn't too big to fail `Layout`'s restrictions
        let layout = match Layout::from_size_align(size, ALIGN) {
            Ok(layout) => layout,
            Err(_) => return ptr::null_mut(),
        };

        unsafe {
            // Allocate the data, and if successful store the size we allocated
            // at the beginning and then return an offset pointer.
            let ptr = alloc::alloc(layout) as *mut usize;
            if ptr.is_null() {
                return ptr as *mut c_void;
            }
            *ptr = size;
            ptr.add(1) as *mut c_void
        }
    }

    pub extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
        unsafe {
            // Move our address being freed back one pointer, read the size we
            // stored in `zalloc`, and then free it using the standard Rust
            // allocator.
            let ptr = (address as *mut usize).offset(-1);
            let size = *ptr;
            let layout = Layout::from_size_align_unchecked(size, ALIGN);
            alloc::dealloc(ptr as *mut u8, layout)
        }
    }
}

unsafe impl<D: Direction> Send for Stream<D> {}
unsafe impl<D: Direction> Sync for Stream<D> {}

/// Trait used to call the right destroy/end function on the inner
/// stream object on drop.
pub trait Direction {
    unsafe fn destroy(stream: *mut mz_stream) -> c_int;
}

#[derive(Debug)]
pub enum DirCompress {}
#[derive(Debug)]
pub enum DirDecompress {}

#[derive(Debug)]
pub struct Stream<D: Direction> {
    pub stream_wrapper: StreamWrapper,
    pub total_in: u64,
    pub total_out: u64,
    pub _marker: marker::PhantomData<D>,
}

impl<D: Direction> Stream<D> {
    pub fn msg(&self) -> ErrorMessage {
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
        // since it points to a cyclic structure. No copies of `inner` can be
        // retained for longer than the lifetime of `self`.
        let msg = unsafe { (*self.stream_wrapper.inner).msg };
        ErrorMessage(if msg.is_null() {
            None
        } else {
            let s = unsafe { std::ffi::CStr::from_ptr(msg) };
            std::str::from_utf8(s.to_bytes()).ok()
        })
    }
}

impl<D: Direction> Drop for Stream<D> {
    fn drop(&mut self) {
        unsafe {
            let _ = D::destroy(self.stream_wrapper.inner);
        }
    }
}

impl Direction for DirCompress {
    unsafe fn destroy(stream: *mut mz_stream) -> c_int {
        mz_deflateEnd(stream)
    }
}
impl Direction for DirDecompress {
    unsafe fn destroy(stream: *mut mz_stream) -> c_int {
        mz_inflateEnd(stream)
    }
}

#[derive(Debug)]
pub struct Inflate {
    pub inner: Stream<DirDecompress>,
}

impl InflateBackend for Inflate {
    fn make(zlib_header: bool, window_bits: u8) -> Self {
        unsafe {
            let state = StreamWrapper::default();
            let ret = mz_inflateInit2(
                state.inner,
                if zlib_header {
                    window_bits as c_int
                } else {
                    -(window_bits as c_int)
                },
            );
            assert_eq!(ret, 0);
            Inflate {
                inner: Stream {
                    stream_wrapper: state,
                    total_in: 0,
                    total_out: 0,
                    _marker: marker::PhantomData,
                },
            }
        }
    }

    fn decompress(
        &mut self,
        input: &[u8],
        output: &mut [u8],
        flush: FlushDecompress,
    ) -> Result<Status, DecompressError> {
        let raw = self.inner.stream_wrapper.inner;
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
        // since it points to a cyclic structure. No copies of `inner` can be
        // retained for longer than the lifetime of `self`.
        unsafe {
            (*raw).msg = ptr::null_mut();
            (*raw).next_in = input.as_ptr() as *mut u8;
            (*raw).avail_in = cmp::min(input.len(), c_uint::MAX as usize) as c_uint;
            (*raw).next_out = output.as_mut_ptr();
            (*raw).avail_out = cmp::min(output.len(), c_uint::MAX as usize) as c_uint;

            let rc = mz_inflate(raw, flush as c_int);

            // Unfortunately the total counters provided by zlib might be only
            // 32 bits wide and overflow while processing large amounts of data.
            self.inner.total_in += ((*raw).next_in as usize - input.as_ptr() as usize) as u64;
            self.inner.total_out += ((*raw).next_out as usize - output.as_ptr() as usize) as u64;

            // reset these pointers so we don't accidentally read them later
            (*raw).next_in = ptr::null_mut();
            (*raw).avail_in = 0;
            (*raw).next_out = ptr::null_mut();
            (*raw).avail_out = 0;

            match rc {
                MZ_DATA_ERROR | MZ_STREAM_ERROR => mem::decompress_failed(self.inner.msg()),
                MZ_OK => Ok(Status::Ok),
                MZ_BUF_ERROR => Ok(Status::BufError),
                MZ_STREAM_END => Ok(Status::StreamEnd),
                MZ_NEED_DICT => mem::decompress_need_dict((*raw).adler as u32),
                c => panic!("unknown return code: {}", c),
            }
        }
    }

    fn reset(&mut self, zlib_header: bool) {
        let bits = if zlib_header {
            MZ_DEFAULT_WINDOW_BITS
        } else {
            -MZ_DEFAULT_WINDOW_BITS
        };
        unsafe {
            inflateReset2(self.inner.stream_wrapper.inner, bits);
        }
        self.inner.total_out = 0;
        self.inner.total_in = 0;
    }
}

impl Backend for Inflate {
    #[inline]
    fn total_in(&self) -> u64 {
        self.inner.total_in
    }

    #[inline]
    fn total_out(&self) -> u64 {
        self.inner.total_out
    }
}

#[derive(Debug)]
pub struct Deflate {
    pub inner: Stream<DirCompress>,
}

impl DeflateBackend for Deflate {
    fn make(level: Compression, zlib_header: bool, window_bits: u8) -> Self {
        unsafe {
            let state = StreamWrapper::default();
            let ret = mz_deflateInit2(
                state.inner,
                level.0 as c_int,
                MZ_DEFLATED,
                if zlib_header {
                    window_bits as c_int
                } else {
                    -(window_bits as c_int)
                },
                8,
                MZ_DEFAULT_STRATEGY,
            );
            assert_eq!(ret, 0);
            Deflate {
                inner: Stream {
                    stream_wrapper: state,
                    total_in: 0,
                    total_out: 0,
                    _marker: marker::PhantomData,
                },
            }
        }
    }
    fn compress(
        &mut self,
        input: &[u8],
        output: &mut [u8],
        flush: FlushCompress,
    ) -> Result<Status, CompressError> {
        let raw = self.inner.stream_wrapper.inner;
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
        // since it points to a cyclic structure. No copies of `inner` can be
        // retained for longer than the lifetime of `self`.
        unsafe {
            (*raw).msg = ptr::null_mut();
            (*raw).next_in = input.as_ptr() as *mut _;
            (*raw).avail_in = cmp::min(input.len(), c_uint::MAX as usize) as c_uint;
            (*raw).next_out = output.as_mut_ptr();
            (*raw).avail_out = cmp::min(output.len(), c_uint::MAX as usize) as c_uint;

            let rc = mz_deflate(raw, flush as c_int);

            // Unfortunately the total counters provided by zlib might be only
            // 32 bits wide and overflow while processing large amounts of data.

            self.inner.total_in += ((*raw).next_in as usize - input.as_ptr() as usize) as u64;
            self.inner.total_out += ((*raw).next_out as usize - output.as_ptr() as usize) as u64;
            // reset these pointers so we don't accidentally read them later
            (*raw).next_in = ptr::null_mut();
            (*raw).avail_in = 0;
            (*raw).next_out = ptr::null_mut();
            (*raw).avail_out = 0;

            match rc {
                MZ_OK => Ok(Status::Ok),
                MZ_BUF_ERROR => Ok(Status::BufError),
                MZ_STREAM_END => Ok(Status::StreamEnd),
                MZ_STREAM_ERROR => mem::compress_failed(self.inner.msg()),
                c => panic!("unknown return code: {}", c),
            }
        }
    }

    fn reset(&mut self) {
        self.inner.total_in = 0;
        self.inner.total_out = 0;
        let rc = unsafe { mz_deflateReset(self.inner.stream_wrapper.inner) };
        assert_eq!(rc, MZ_OK);
    }
}

impl Backend for Deflate {
    #[inline]
    fn total_in(&self) -> u64 {
        self.inner.total_in
    }

    #[inline]
    fn total_out(&self) -> u64 {
        self.inner.total_out
    }
}

pub use self::c_backend::*;

/// For backwards compatibility, we provide symbols as `mz_` to mimic the miniz API
#[allow(bad_style)]
#[allow(unused_imports)]
mod c_backend {
    use std::mem;
    use std::os::raw::{c_char, c_int};

    #[cfg(feature = "zlib-ng")]
    use libz_ng_sys as libz;

    #[cfg(all(not(feature = "zlib-ng"), feature = "zlib-rs"))]
    use libz_rs_sys as libz;

    #[cfg(all(not(feature = "zlib-ng"), feature = "cloudflare_zlib"))]
    use cloudflare_zlib_sys as libz;

    #[cfg(all(
        not(feature = "cloudflare_zlib"),
        not(feature = "zlib-ng"),
        not(feature = "zlib-rs")
    ))]
    use libz_sys as libz;

    pub use libz::deflate as mz_deflate;
    pub use libz::deflateEnd as mz_deflateEnd;
    pub use libz::deflateReset as mz_deflateReset;
    pub use libz::inflate as mz_inflate;
    pub use libz::inflateEnd as mz_inflateEnd;
    pub use libz::z_stream as mz_stream;
    pub use libz::*;

    pub use libz::Z_BLOCK as MZ_BLOCK;
    pub use libz::Z_BUF_ERROR as MZ_BUF_ERROR;
    pub use libz::Z_DATA_ERROR as MZ_DATA_ERROR;
    pub use libz::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY;
    pub use libz::Z_DEFLATED as MZ_DEFLATED;
    pub use libz::Z_FINISH as MZ_FINISH;
    pub use libz::Z_FULL_FLUSH as MZ_FULL_FLUSH;
    pub use libz::Z_NEED_DICT as MZ_NEED_DICT;
    pub use libz::Z_NO_FLUSH as MZ_NO_FLUSH;
    pub use libz::Z_OK as MZ_OK;
    pub use libz::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH;
    pub use libz::Z_STREAM_END as MZ_STREAM_END;
    pub use libz::Z_STREAM_ERROR as MZ_STREAM_ERROR;
    pub use libz::Z_SYNC_FLUSH as MZ_SYNC_FLUSH;

    pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;

    #[cfg(feature = "zlib-ng")]
    const ZLIB_VERSION: &'static str = "2.1.0.devel\0";
    #[cfg(all(not(feature = "zlib-ng"), feature = "zlib-rs"))]
    const ZLIB_VERSION: &'static str = "0.1.0\0";
    #[cfg(not(any(feature = "zlib-ng", feature = "zlib-rs")))]
    const ZLIB_VERSION: &'static str = "1.2.8\0";

    pub unsafe extern "C" fn mz_deflateInit2(
        stream: *mut mz_stream,
        level: c_int,
        method: c_int,
        window_bits: c_int,
        mem_level: c_int,
        strategy: c_int,
    ) -> c_int {
        libz::deflateInit2_(
            stream,
            level,
            method,
            window_bits,
            mem_level,
            strategy,
            ZLIB_VERSION.as_ptr() as *const c_char,
            mem::size_of::<mz_stream>() as c_int,
        )
    }
    pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int {
        libz::inflateInit2_(
            stream,
            window_bits,
            ZLIB_VERSION.as_ptr() as *const c_char,
            mem::size_of::<mz_stream>() as c_int,
        )
    }
}

[ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge