#![allow(unused, nonstandard_style)]
pub use crate::c_types_gen::{
GifByteType, GifColorType, GifPixelType, GifPrefixType, GifRecordType, GifWord,
GraphicsControlBlock, InputFunc, OutputFunc, APPLICATION_EXT_FUNC_CODE, COMMENT_EXT_FUNC_CODE,
CONTINUE_EXT_FUNC_CODE, DISPOSAL_UNSPECIFIED, D_GIF_ERR_CLOSE_FAILED, D_GIF_ERR_DATA_TOO_BIG,
D_GIF_ERR_EOF_TOO_SOON, D_GIF_ERR_IMAGE_DEFECT, D_GIF_ERR_NOT_ENOUGH_MEM,
D_GIF_ERR_NOT_GIF_FILE, D_GIF_ERR_NOT_READABLE, D_GIF_ERR_NO_COLOR_MAP, D_GIF_ERR_NO_IMAG_DSCR,
D_GIF_ERR_NO_SCRN_DSCR, D_GIF_ERR_OPEN_FAILED, D_GIF_ERR_READ_FAILED, D_GIF_ERR_WRONG_RECORD,
E_GIF_ERR_CLOSE_FAILED, E_GIF_ERR_DATA_TOO_BIG, E_GIF_ERR_DISK_IS_FULL,
E_GIF_ERR_HAS_IMAG_DSCR, E_GIF_ERR_HAS_SCRN_DSCR, E_GIF_ERR_NOT_ENOUGH_MEM,
E_GIF_ERR_NOT_WRITEABLE, E_GIF_ERR_NO_COLOR_MAP, E_GIF_ERR_OPEN_FAILED, E_GIF_ERR_WRITE_FAILED,
E_GIF_SUCCEEDED, GIF87_STAMP, GIF89_STAMP, GIF_ERROR, GIF_OK, GIF_STAMP, GIF_VERSION_POS,
GRAPHICS_EXT_FUNC_CODE, NO_TRANSPARENT_COLOR, PLAINTEXT_EXT_FUNC_CODE,
};
use safer_cffi::{CSlicePtr, CSliceRefMut};
use std::os::raw::c_int;
use std::os::raw::c_uchar;
use std::os::raw::c_uint;
use std::os::raw::c_void;
#[repr(C)]
#[derive(Debug)]
pub struct ColorMapObject {
pub ColorCount: c_int,
pub BitsPerPixel: c_int,
pub SortFlag: bool,
pub Colors: CSlicePtr<GifColorType>,
}
impl ColorMapObject {
pub fn colors(&self) -> &[GifColorType] {
unsafe { self.Colors.with_len(self.ColorCount) }
}
pub fn colors_mut(&mut self) -> CSliceRefMut<'_, GifColorType, c_int> {
unsafe { self.Colors.with_len_mut(&mut self.ColorCount) }
}
}
impl Drop for ColorMapObject {
fn drop(&mut self) {
self.colors_mut().clear();
}
}
impl Clone for ColorMapObject {
fn clone(&self) -> Self {
Self {
ColorCount: self.ColorCount,
BitsPerPixel: self.BitsPerPixel,
SortFlag: self.SortFlag,
Colors: CSlicePtr::clone_and_leak(self.colors()),
}
}
}
#[derive(Debug)]
pub struct InvalidColorCount;
impl ColorMapObject {
pub fn new(color_count: c_int) -> Result<Self, InvalidColorCount> {
if !(0..=256).contains(&color_count) {
return Err(InvalidColorCount);
}
let stack_colors: [GifColorType; 256] =
std::array::from_fn(|_| GifColorType { Red: 0, Green: 0, Blue: 0 });
Self::from_slice(&stack_colors[..color_count as usize])
}
pub fn from_slice(src: &[GifColorType]) -> Result<Self, InvalidColorCount> {
let color_count = src.len() as c_int;
let bits = Self::bit_size(color_count);
if color_count <= 0 || color_count != (1 << bits) {
return Err(InvalidColorCount);
}
Ok(Self {
ColorCount: color_count,
BitsPerPixel: bits,
SortFlag: false,
Colors: CSlicePtr::clone_and_leak(src),
})
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct GifImageDesc {
pub Left: GifWord,
pub Top: GifWord,
pub Width: GifWord,
pub Height: GifWord,
pub Interlace: bool,
pub ColorMap: Option<Box<ColorMapObject>>,
}
#[repr(C)]
#[derive(Debug)]
pub struct ExtensionBlock {
pub ByteCount: c_int,
pub Bytes: CSlicePtr<GifByteType>,
pub Function: c_int,
}
impl ExtensionBlock {
pub fn bytes(&self) -> &[u8] {
unsafe { self.Bytes.with_len(self.ByteCount) }
}
pub fn bytes_mut(&mut self) -> CSliceRefMut<'_, u8, c_int> {
unsafe { self.Bytes.with_len_mut(&mut self.ByteCount) }
}
}
impl Drop for ExtensionBlock {
fn drop(&mut self) {
self.bytes_mut().clear();
}
}
impl Clone for ExtensionBlock {
fn clone(&self) -> Self {
Self {
ByteCount: self.ByteCount,
Bytes: CSlicePtr::clone_and_leak(self.bytes()),
Function: self.Function,
}
}
}
impl ExtensionBlock {
pub fn new(function: c_int, data: &[u8]) -> Self {
let bytes =
if data.is_empty() { CSlicePtr::null() } else { CSlicePtr::clone_and_leak(data) };
Self { Function: function, ByteCount: data.len() as c_int, Bytes: bytes }
}
}
#[repr(C)]
#[derive(Debug)]
pub struct SavedImage {
pub ImageDesc: GifImageDesc,
pub RasterBits: CSlicePtr<GifByteType>,
pub ExtensionBlockCount: c_int,
pub ExtensionBlocks: CSlicePtr<ExtensionBlock>,
}
impl SavedImage {
pub fn size(&self) -> Option<c_int> {
match (self.ImageDesc.Width, self.ImageDesc.Height) {
(1..=65535, 1..=65535) => self.ImageDesc.Width.checked_mul(self.ImageDesc.Height),
_ => None,
}
}
pub fn raster_bits(&self) -> &[u8] {
let size = self.size().unwrap_or(0);
unsafe { self.RasterBits.with_len(size) }
}
pub fn raster_bits_mut(&mut self) -> &mut [u8] {
if self.RasterBits.is_null() {
return &mut [];
}
let Some(size) = self.size() else {
return &mut [];
};
unsafe { core::slice::from_raw_parts_mut(self.RasterBits.as_ptr(), size as usize) }
}
pub fn raster_bits_row_mut(&mut self, row: usize) -> Option<&mut [u8]> {
let start = row.checked_mul(self.ImageDesc.Width as usize)?;
let end = start.checked_add(self.ImageDesc.Width as usize)?;
self.raster_bits_mut().get_mut(start..end)
}
pub fn extension_blocks(&self) -> &[ExtensionBlock] {
unsafe { self.ExtensionBlocks.with_len(self.ExtensionBlockCount) }
}
pub fn extension_blocks_mut(&mut self) -> CSliceRefMut<'_, ExtensionBlock, c_int> {
unsafe { self.ExtensionBlocks.with_len_mut(&mut self.ExtensionBlockCount) }
}
}
impl Drop for SavedImage {
fn drop(&mut self) {
let mut count = self.raster_bits().len() as c_int;
let mut slice = unsafe { self.RasterBits.with_len_mut(&mut count) };
slice.clear();
self.extension_blocks_mut().clear();
}
}
impl Clone for SavedImage {
fn clone(&self) -> Self {
Self {
ImageDesc: self.ImageDesc.clone(),
RasterBits: CSlicePtr::clone_and_leak(self.raster_bits()),
ExtensionBlockCount: self.ExtensionBlockCount,
ExtensionBlocks: CSlicePtr::clone_and_leak(self.extension_blocks()),
}
}
}
impl SavedImage {
pub fn new(desc: GifImageDesc) -> Self {
Self {
ImageDesc: desc,
RasterBits: CSlicePtr::null(),
ExtensionBlockCount: 0,
ExtensionBlocks: CSlicePtr::null(),
}
}
}
#[repr(C)]
pub struct GifFileType {
pub SWidth: GifWord,
pub SHeight: GifWord,
pub SColorResolution: GifWord,
pub SBackGroundColor: GifWord,
pub AspectByte: GifByteType,
pub SColorMap: Option<Box<ColorMapObject>>,
pub ImageCount: c_int,
pub Image: GifImageDesc,
pub SavedImages: CSlicePtr<SavedImage>,
pub ExtensionBlockCount: c_int,
pub ExtensionBlocks: CSlicePtr<ExtensionBlock>,
pub Error: c_int,
pub UserData: UserData,
pub Private: Box<crate::private::GifFilePrivateType>,
}
impl GifFileType {
pub fn saved_images(&self) -> &[SavedImage] {
unsafe { self.SavedImages.with_len(self.ImageCount) }
}
pub fn saved_images_mut(&mut self) -> CSliceRefMut<'_, SavedImage, c_int> {
unsafe { self.SavedImages.with_len_mut(&mut self.ImageCount) }
}
pub fn extension_blocks(&self) -> &[ExtensionBlock] {
unsafe { self.ExtensionBlocks.with_len(self.ExtensionBlockCount) }
}
pub fn extension_blocks_mut(&mut self) -> CSliceRefMut<'_, ExtensionBlock, c_int> {
unsafe { self.ExtensionBlocks.with_len_mut(&mut self.ExtensionBlockCount) }
}
}
impl Drop for GifFileType {
fn drop(&mut self) {
self.saved_images_mut().clear();
self.extension_blocks_mut().clear();
}
}
impl GifFileType {
pub(crate) fn new(
private: Box<crate::private::GifFilePrivateType>,
user_data: *mut c_void,
) -> Self {
Self {
SWidth: 0,
SHeight: 0,
SColorResolution: 0,
SBackGroundColor: 0,
AspectByte: 0,
SColorMap: None,
ImageCount: 0,
Image: GifImageDesc {
Left: 0,
Top: 0,
Width: 0,
Height: 0,
Interlace: false,
ColorMap: None,
},
SavedImages: CSlicePtr::null(),
ExtensionBlockCount: 0,
ExtensionBlocks: CSlicePtr::null(),
Error: 0,
UserData: UserData(user_data),
Private: private,
}
}
pub fn result_to_status(&mut self, result: Result<(), crate::err::GifError>) -> c_int {
match result {
Ok(()) => GIF_OK,
Err(e) => {
self.Error = e as c_int;
GIF_ERROR
}
}
}
}
#[repr(transparent)]
pub struct UserData(*mut c_void);
unsafe impl Send for UserData {}
#[derive(Clone, Copy, Debug)]
pub(crate) struct ReadCallback(
unsafe extern "C" fn(*mut GifFileType, *mut GifByteType, c_int) -> c_int,
);
impl ReadCallback {
#[rustfmt::skip]
pub(crate) unsafe fn new(
func: unsafe extern "C" fn(*mut crate::c_types_gen::GifFileType, *mut GifByteType, c_int) -> c_int,
) -> Self {
let func = unsafe {
core::mem::transmute::<
unsafe extern "C" fn(*mut crate::c_types_gen::GifFileType, *mut GifByteType, c_int) -> c_int,
unsafe extern "C" fn(*mut crate::c_types::GifFileType, *mut GifByteType, c_int) -> c_int,
>(func)
};
Self(func)
}
pub(crate) fn read(&self, gif: *mut GifFileType, buf: &mut [u8]) -> c_int {
unsafe { (self.0)(gif, buf.as_mut_ptr(), buf.len() as c_int) }
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct WriteCallback(
unsafe extern "C" fn(*mut GifFileType, *const GifByteType, c_int) -> c_int,
);
impl WriteCallback {
#[rustfmt::skip]
pub(crate) unsafe fn new(
func: unsafe extern "C" fn(*mut crate::c_types_gen::GifFileType, *const GifByteType, c_int) -> c_int,
) -> Self {
let func = unsafe {
core::mem::transmute::<
unsafe extern "C" fn(*mut crate::c_types_gen::GifFileType, *const GifByteType, c_int) -> c_int,
unsafe extern "C" fn(*mut crate::c_types::GifFileType, *const GifByteType, c_int) -> c_int,
>(func)
};
Self(func)
}
pub(crate) fn write(&self, gif: *mut GifFileType, buf: &[u8]) -> c_int {
unsafe { (self.0)(gif, buf.as_ptr(), buf.len() as c_int) }
}
}