blob: 45b2bfdaf6302f85a9002b7c290a4886f8420885 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::types::*;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_void;
use crate::decoder::GenericIO;
use crate::internal_utils::io::DecoderFileIO;
use crate::internal_utils::io::DecoderRawIO;
use crate::*;
#[repr(C)]
#[derive(Clone)]
pub struct avifROData {
pub data: *const u8,
pub size: usize,
}
impl Default for avifROData {
fn default() -> Self {
avifROData {
data: std::ptr::null(),
size: 0,
}
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct avifRWData {
pub data: *mut u8,
pub size: usize,
}
impl Default for avifRWData {
fn default() -> Self {
avifRWData {
data: std::ptr::null_mut(),
size: 0,
}
}
}
impl From<&Vec<u8>> for avifRWData {
fn from(v: &Vec<u8>) -> Self {
avifRWData {
data: v.as_ptr() as *mut u8,
size: v.len(),
}
}
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifRWDataRealloc(
raw: *mut avifRWData,
newSize: usize,
) -> avifResult {
unsafe {
if (*raw).size == newSize {
return avifResult::Ok;
}
// Ok to use size as capacity here since we use reserve_exact.
let mut newData: Vec<u8> = Vec::new();
if newData.try_reserve_exact(newSize).is_err() {
return avifResult::OutOfMemory;
}
if !(*raw).data.is_null() {
let oldData = Box::from_raw(std::slice::from_raw_parts_mut((*raw).data, (*raw).size));
let sizeToCopy = std::cmp::min(newSize, oldData.len());
newData.extend_from_slice(&oldData[..sizeToCopy]);
}
newData.resize(newSize, 0);
let mut b = newData.into_boxed_slice();
(*raw).data = b.as_mut_ptr();
std::mem::forget(b);
(*raw).size = newSize;
avifResult::Ok
}
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifRWDataSet(
raw: *mut avifRWData,
data: *const u8,
size: usize,
) -> avifResult {
unsafe {
if size != 0 {
let res = crabby_avifRWDataRealloc(raw, size);
if res != avifResult::Ok {
return res;
}
std::ptr::copy_nonoverlapping(data, (*raw).data, size);
} else {
crabby_avifRWDataFree(raw);
}
avifResult::Ok
}
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifRWDataFree(raw: *mut avifRWData) {
unsafe {
if (*raw).data.is_null() {
return;
}
let _ = Box::from_raw(std::slice::from_raw_parts_mut((*raw).data, (*raw).size));
}
}
pub type avifIODestroyFunc = unsafe extern "C" fn(io: *mut avifIO);
pub type avifIOReadFunc = unsafe extern "C" fn(
io: *mut avifIO,
readFlags: u32,
offset: u64,
size: usize,
out: *mut avifROData,
) -> avifResult;
pub type avifIOWriteFunc = unsafe extern "C" fn(
io: *mut avifIO,
writeFlags: u32,
offset: u64,
data: *const u8,
size: usize,
) -> avifResult;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct avifIO {
destroy: avifIODestroyFunc,
read: avifIOReadFunc,
write: avifIOWriteFunc,
sizeHint: u64,
persistent: avifBool,
data: *mut c_void,
}
pub struct avifIOWrapper {
data: avifROData,
io: avifIO,
}
impl avifIOWrapper {
pub fn create(io: avifIO) -> Self {
Self {
io,
data: Default::default(),
}
}
}
impl crate::decoder::IO for avifIOWrapper {
#[cfg_attr(feature = "disable_cfi", no_sanitize(cfi))]
fn read(&mut self, offset: u64, size: usize) -> AvifResult<&[u8]> {
let res = unsafe {
(self.io.read)(
&mut self.io as *mut avifIO,
0,
offset,
size,
&mut self.data as *mut avifROData,
)
};
if res != avifResult::Ok {
let err: AvifError = res.into();
return Err(err);
}
if self.data.size == 0 {
Ok(&[])
} else if self.data.data.is_null() {
Err(AvifError::UnknownError(
"data pointer was null but size was not zero".into(),
))
} else {
Ok(unsafe { std::slice::from_raw_parts(self.data.data, self.data.size) })
}
}
fn size_hint(&self) -> u64 {
self.io.sizeHint
}
fn persistent(&self) -> bool {
self.io.persistent != 0
}
}
pub struct avifCIOWrapper {
io: GenericIO,
buf: Vec<u8>,
}
#[no_mangle]
unsafe extern "C" fn cioDestroy(_io: *mut avifIO) {}
#[no_mangle]
unsafe extern "C" fn cioRead(
io: *mut avifIO,
_readFlags: u32,
offset: u64,
size: usize,
out: *mut avifROData,
) -> avifResult {
unsafe {
if io.is_null() {
return avifResult::IoError;
}
let cio = (*io).data as *mut avifCIOWrapper;
match (*cio).io.read(offset, size) {
Ok(data) => {
(*cio).buf.clear();
if (*cio).buf.try_reserve_exact(data.len()).is_err() {
return avifResult::OutOfMemory;
}
(*cio).buf.extend_from_slice(data);
}
Err(_) => return avifResult::IoError,
}
(*out).data = (*cio).buf.as_ptr();
(*out).size = (*cio).buf.len();
avifResult::Ok
}
}
#[no_mangle]
unsafe extern "C" fn cioWrite(
_io: *mut avifIO,
_writeFlags: u32,
_offset: u64,
_data: *const u8,
_size: usize,
) -> avifResult {
avifResult::Ok
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifIOCreateMemoryReader(
data: *const u8,
size: usize,
) -> *mut avifIO {
let cio = Box::new(avifCIOWrapper {
io: Box::new(unsafe { DecoderRawIO::create(data, size) }),
buf: Vec::new(),
});
let io = Box::new(avifIO {
destroy: cioDestroy,
read: cioRead,
write: cioWrite,
sizeHint: size as u64,
persistent: 0,
data: Box::into_raw(cio) as *mut c_void,
});
Box::into_raw(io)
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifIOCreateFileReader(filename: *const c_char) -> *mut avifIO {
let filename = unsafe { String::from(CStr::from_ptr(filename).to_str().unwrap_or("")) };
let file_io = match DecoderFileIO::create(&filename) {
Ok(x) => x,
Err(_) => return std::ptr::null_mut(),
};
let cio = Box::new(avifCIOWrapper {
io: Box::new(file_io),
buf: Vec::new(),
});
let io = Box::new(avifIO {
destroy: cioDestroy,
read: cioRead,
write: cioWrite,
sizeHint: cio.io.size_hint(),
persistent: 0,
data: Box::into_raw(cio) as *mut c_void,
});
Box::into_raw(io)
}
#[no_mangle]
pub unsafe extern "C" fn crabby_avifIODestroy(io: *mut avifIO) {
unsafe {
let _ = Box::from_raw((*io).data as *mut avifCIOWrapper);
let _ = Box::from_raw(io);
}
}