#![forbid(unsafe_code)]
use crate::c_types::{GifByteType, GifFileType, GifPrefixType, ReadCallback, WriteCallback};
use crate::encoder_lzw::GifHashTableType;
use crate::private_c_types::LZ_MAX_CODE;
use core::ffi::c_int;
use std::io::{Read, Write};
#[derive(Debug)]
pub(crate) enum IoState {
FileRead { file: std::fs::File },
CallbackRead { read_fn: ReadCallback },
FileWrite { file: std::fs::File },
CallbackWrite { write_fn: WriteCallback },
}
impl IoState {
pub(crate) fn is_readable(&self) -> bool {
matches!(self, IoState::FileRead { .. } | IoState::CallbackRead { .. })
}
pub(crate) fn is_writable(&self) -> bool {
matches!(self, IoState::FileWrite { .. } | IoState::CallbackWrite { .. })
}
pub(crate) fn read(&mut self, gif_ptr: *mut GifFileType, buf: &mut [u8]) -> usize {
match self {
IoState::CallbackRead { read_fn } => read_fn.read(gif_ptr, buf) as usize,
IoState::FileRead { file, .. } => {
let mut total = 0usize;
while total < buf.len() {
match file.read(&mut buf[total..]) {
Ok(0) => break,
Ok(n) => total += n,
Err(_) => break,
}
}
total
}
_ => 0, }
}
pub(crate) fn write(&mut self, gif_ptr: *mut GifFileType, buf: &[u8]) -> usize {
match self {
IoState::CallbackWrite { write_fn } => write_fn.write(gif_ptr, buf) as usize,
IoState::FileWrite { file, .. } => {
let mut total = 0usize;
while total < buf.len() {
match file.write(&buf[total..]) {
Ok(0) => break,
Ok(n) => total += n,
Err(_) => break,
}
}
total
}
_ => 0, }
}
}
#[derive(Debug)]
pub(crate) struct LzwState {
pub(crate) bits_per_pixel: c_int,
pub(crate) clear_code: c_int,
pub(crate) eof_code: c_int,
pub(crate) running_code: c_int,
pub(crate) running_bits: c_int,
pub(crate) max_code1: c_int,
pub(crate) last_code: c_int,
pub(crate) crnt_code: c_int,
pub(crate) stack_ptr: c_int,
pub(crate) crnt_shift_state: c_int,
pub(crate) crnt_shift_dword: u64,
pub(crate) buf: [GifByteType; 256],
pub(crate) stack: Box<[GifByteType; LZ_MAX_CODE + 1]>,
pub(crate) suffix: Box<[GifByteType; LZ_MAX_CODE + 1]>,
pub(crate) prefix: Box<[GifPrefixType; LZ_MAX_CODE + 1]>,
pub(crate) hash_table: Option<Box<GifHashTableType>>,
}
impl Default for LzwState {
fn default() -> Self {
Self {
bits_per_pixel: 0,
clear_code: 0,
eof_code: 0,
running_code: 0,
running_bits: 0,
max_code1: 0,
last_code: 0,
crnt_code: 0,
stack_ptr: 0,
crnt_shift_state: 0,
crnt_shift_dword: 0,
buf: [0; 256],
stack: Box::new([0; LZ_MAX_CODE + 1]),
suffix: Box::new([0; LZ_MAX_CODE + 1]),
prefix: Box::new([0; LZ_MAX_CODE + 1]),
hash_table: None,
}
}
}
#[derive(Debug)]
pub struct GifFilePrivateType {
pub(crate) pixel_count: usize,
pub(crate) gif89: bool,
pub(crate) screen_desc_written: bool,
pub(crate) in_image: bool,
pub(crate) io: IoState,
pub(crate) lzw: LzwState,
}
impl GifFilePrivateType {
pub(crate) fn new(io: IoState) -> Self {
Self {
pixel_count: 0,
gif89: false,
screen_desc_written: false,
in_image: false,
io,
lzw: LzwState::default(),
}
}
}