use std::ffi::c_void;
use openjpeg_sys as opj;
use crate::DecodeError;
struct Slice<'a> {
offset: usize,
buf: &'a [u8],
}
impl<'a> Slice<'a> {
fn new(buf: &'a [u8]) -> Self {
Self { offset: 0, buf }
}
fn remaining(&self) -> usize {
self.buf.len() - self.offset
}
fn seek(&mut self, new_offset: usize) -> usize {
self.offset = self.buf.len().min(new_offset);
self.offset
}
fn consume(&mut self, nb_bytes: usize) -> usize {
let new_offset = self.offset.saturating_add(nb_bytes);
self.seek(new_offset)
}
fn read_into(&mut self, out_buffer: &mut [u8]) -> Option<usize> {
let remaining = self.remaining();
if remaining == 0 {
return None;
}
let nb_bytes_read = std::cmp::min(remaining, out_buffer.len());
let offset = self.offset;
let end_off = self.consume(nb_bytes_read);
out_buffer[0..nb_bytes_read].copy_from_slice(&self.buf[offset..end_off]);
Some(nb_bytes_read)
}
}
extern "C" fn buf_read_stream_read_fn(
p_buffer: *mut c_void,
nb_bytes: usize,
p_data: *mut c_void,
) -> usize {
if p_buffer.is_null() || nb_bytes == 0 {
return usize::MAX;
}
let slice = unsafe { &mut *(p_data as *mut Slice) };
let out_buf = unsafe { std::slice::from_raw_parts_mut(p_buffer as *mut u8, nb_bytes) };
slice.read_into(out_buf).unwrap_or(usize::MAX)
}
extern "C" fn buf_read_stream_skip_fn(nb_bytes: i64, p_data: *mut c_void) -> i64 {
let slice = unsafe { &mut *(p_data as *mut Slice) };
slice.consume(nb_bytes as usize) as i64
}
extern "C" fn buf_read_stream_seek_fn(nb_bytes: i64, p_data: *mut c_void) -> i32 {
let slice = unsafe { &mut *(p_data as *mut Slice) };
let seek_offset = nb_bytes as usize;
let new_offset = slice.seek(seek_offset);
i32::from(seek_offset == new_offset)
}
extern "C" fn buf_read_stream_free_fn(p_data: *mut c_void) {
let ptr = p_data as *mut Slice;
drop(unsafe { Box::from_raw(ptr) })
}
pub(crate) struct Stream(*mut opj::opj_stream_t);
impl Drop for Stream {
fn drop(&mut self) {
unsafe {
opj::opj_stream_destroy(self.0);
}
}
}
impl Stream {
pub(crate) fn from_bytes(buf: &[u8]) -> Result<Self, DecodeError> {
let len = buf.len();
let data = Box::new(Slice::new(buf));
unsafe {
let stream = opj::opj_stream_default_create(1);
opj::opj_stream_set_read_function(stream, Some(buf_read_stream_read_fn));
opj::opj_stream_set_skip_function(stream, Some(buf_read_stream_skip_fn));
opj::opj_stream_set_seek_function(stream, Some(buf_read_stream_seek_fn));
opj::opj_stream_set_user_data_length(stream, len as u64);
opj::opj_stream_set_user_data(
stream,
Box::into_raw(data) as *mut c_void,
Some(buf_read_stream_free_fn),
);
Ok(Self(stream))
}
}
pub(crate) fn as_ptr(&self) -> *mut opj::opj_stream_t {
self.0
}
}