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