Skip to content

Commit

Permalink
Start reorganizing c api
Browse files Browse the repository at this point in the history
  • Loading branch information
oyvindln committed Jul 25, 2019
1 parent 40d75ea commit 918aa73
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 381 deletions.
262 changes: 262 additions & 0 deletions src/c_export.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/// Module that contains most of the functions exported to C.
use std::{slice, ptr};
use std::marker::PhantomData;

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


pub use tdef::{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_get_prev_return_status, tdefl_init,
tdefl_allocate, tdefl_deallocate, tdefl_get_adler32};
use libc::*;

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

use miniz_oxide::{mz_adler32_oxide, MZError};

pub mod return_status {
use MZError::*;
use miniz_oxide::MZStatus;
use libc::c_int;
pub const MZ_ERRNO: c_int = ErrNo as c_int;
pub const MZ_STREAM_ERROR: c_int = Stream as c_int;
pub const MZ_DATA_ERROR: c_int = Data as c_int;
pub const MZ_BUF_ERROR: c_int = Buf as c_int;
pub const MZ_VERSION_ERROR: c_int = Version as c_int;
pub const MZ_PARAM_ERROR: c_int = Param as c_int;

pub const MZ_OK: c_int = MZStatus::Ok as c_int;
pub const MZ_STREAM_END: c_int = MZStatus::StreamEnd as c_int;
pub const MZ_NEED_DICT: c_int = MZStatus::NeedDict as c_int;
}

/// Deflate flush modes.
pub mod flush_modes {
use libc::c_int;
use miniz_oxide::deflate::core::TDEFLFlush;
pub const MZ_NO_FLUSH: c_int = TDEFLFlush::None as c_int;
// TODO: This is simply sync flush for now, miniz also treats it as such.
pub const MZ_PARTIAL_FLUSH: c_int = 1;
pub const MZ_SYNC_FLUSH: c_int = TDEFLFlush::Sync as c_int;
pub const MZ_FULL_FLUSH: c_int = TDEFLFlush::Full as c_int;
pub const MZ_FINISH: c_int = TDEFLFlush::Finish as c_int;
// TODO: Doesn't seem to be implemented by miniz.
pub const MZ_BLOCK: c_int = 5;
}

pub mod strategy {
use libc::c_int;
use miniz_oxide::deflate::core::CompressionStrategy::*;
pub const MZ_DEFAULT_STRATEGY: c_int = Default as c_int;
pub const MZ_FILTERED: c_int = Filtered as c_int;
pub const MZ_HUFFMAN_ONLY: c_int = HuffmanOnly as c_int;
pub const MZ_RLE: c_int = RLE as c_int;
pub const MZ_FIXED: c_int = Fixed as c_int;
}

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)]
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,

// TODO: Not sure
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,
})
}
}

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
})
}
);
73 changes: 9 additions & 64 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,94 +46,39 @@ mod libc {
}
extern crate miniz_oxide;

use std::{cmp, ptr, slice};
use std::{cmp, ptr};
use std::panic::{catch_unwind, AssertUnwindSafe};

use libc::{c_int, c_uint, c_ulong, c_void, size_t};
use libc::{c_int, c_uint, c_ulong};

use miniz_oxide::{MZError, MZResult};
#[allow(bad_style)]
pub use tdef::tdefl_compressor;

pub use miniz_oxide::mz_adler32_oxide;
use miniz_oxide::deflate::CompressionLevel;
use miniz_oxide::deflate::core::CompressionStrategy;

#[macro_use]
mod unmangle;

pub mod lib_oxide;
use lib_oxide::*;

#[macro_use]
mod unmangle;
mod tinfl;
pub use tinfl::{tinfl_decompress, tinfl_decompress_mem_to_heap,
tinfl_decompress_mem_to_mem, tinfl_decompressor};

mod tdef;
pub use tdef::{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_get_prev_return_status, tdefl_init,
tdefl_allocate, tdefl_deallocate, tdefl_get_adler32};

pub use tdef::flush_modes::*;
pub use tdef::strategy::*;

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()
}
mod c_export;
pub use c_export::*;
#[allow(bad_style)]
pub use tdef::Compressor as tdefl_compressor;
pub use lib_oxide::InflateState as inflate_state;

pub const MZ_DEFLATED: c_int = 8;
pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;

pub const MZ_ADLER32_INIT: c_ulong = 1;
pub const MZ_CRC32_INIT: c_ulong = 0;

fn as_c_return_code(r: MZResult) -> c_int {
match r {
Err(status) => status as c_int,
Ok(status) => status as c_int,
}
}

unmangle!(
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)
}

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)
}

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, |r| {
let data = slice::from_raw_parts(r, buf_len);
mz_adler32_oxide(adler as c_uint, data) as c_ulong
})
}

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 c_uint, data) as c_ulong
})
}
);

macro_rules! oxidize {
($mz_func:ident, $mz_func_oxide:ident; $($arg_name:ident: $type_name:ident),*) => {
unmangle!(
Expand Down
Loading

0 comments on commit 918aa73

Please sign in to comment.