diff --git a/include/cc20.h b/include/cc20.h index c706c49..75be682 100644 --- a/include/cc20.h +++ b/include/cc20.h @@ -41,4 +41,6 @@ int cc20_close_sink(cc20_sink_t* sink, FILE* cc20_wrap_sink(cc20_sink_t* sink); +size_t cc20_write(const void* ptr, size_t size, size_t nmemb, cc20_sink_t* restrict sink); + #endif /* _CC20_H */ diff --git a/src/ffi.rs b/src/ffi.rs index 1b697e1..f452987 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -4,6 +4,7 @@ //! Intended to be linked to the C wrapper object `wrapper.c`. use super::*; use std::ptr; +use std::ffi::c_void; use std::io::{ self, Write, }; @@ -56,6 +57,27 @@ mod interop; mod error; pub use error::*; +#[no_mangle] pub unsafe extern "C" fn cc20_write(ptr: *const c_void, size: usize, nmemb: usize, sink: *mut CSink) -> usize +{ + let mut output: usize = 0; + let _er = no_unwind!(ref { + let sink = nullchk!(ref mut sink); + let bytes = size * nmemb; + let slice = if ptr.is_null() { + return CErr::NullPointer; + } else { + std::slice::from_raw_parts(ptr as *const u8, bytes) + }; + match sink.sink.write(&slice[..]) { + Err(_) => return CErr::IO, + Ok(v) => output = v, + } + CErr::Success + }).unwrap_or(CErr::Panic); + //TODO: Write `er` into an error flag for `sink` (parallel to `ferror`/`feof`). + output +} + #[no_mangle] pub unsafe extern "C" fn cc20_gen_meta(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode, output: *mut CPassthrough) -> i32 { no_unwind!({ diff --git a/src/ffi/error.rs b/src/ffi/error.rs index ac06914..edbceba 100644 --- a/src/ffi/error.rs +++ b/src/ffi/error.rs @@ -1,6 +1,7 @@ //! FFI errors use super::*; + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] #[repr(C)] pub enum CErr @@ -11,6 +12,8 @@ pub enum CErr NullPointer, /// Internal SSL error SslError, + /// I/O error + IO, Panic = -1, } diff --git a/src/ffi/interop.rs b/src/ffi/interop.rs index a84273c..8060908 100644 --- a/src/ffi/interop.rs +++ b/src/ffi/interop.rs @@ -1,7 +1,10 @@ #[macro_export] macro_rules! no_unwind { ($expr:expr) => { - ::std::panic::catch_unwind(move || $expr).ok() + ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(move || $expr)).ok() + }; + (ref $expr:expr) => { + ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $expr)).ok() }; }