use self::reader::read_info;
use std::cell::Cell;
pub use crate::error::*;
use crate::Scans;
use std::io;
use std::io::BufRead;
use std::io::Read;
mod common;
mod reader;
mod traits;
struct CountingReader<'counter, 'data> {
buf: u8,
pub inner: &'data [u8],
pub consumed: &'counter Cell<usize>,
}
const MAX_GIF_SIZE: usize = 200_000;
impl BufRead for CountingReader<'_, '_> {
#[inline(always)]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
if let Some((s, rest)) = self.inner.split_first() {
self.inner = rest;
self.buf = *s;
} else {
return Err(io::ErrorKind::UnexpectedEof.into());
}
Ok(std::slice::from_ref(&self.buf))
}
#[inline(always)]
fn consume(&mut self, amt: usize) {
self.consumed.set(self.consumed.get() + amt)
}
}
impl Read for CountingReader<'_, '_> {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
unimplemented!()
}
}
pub fn scans(input_file: &[u8]) -> Result<Scans> {
let file_size = input_file.len();
let bytes_read = Cell::new(0);
let r = CountingReader {
buf: 0,
inner: &input_file[..MAX_GIF_SIZE.min(file_size)], consumed: &bytes_read,
};
match read_info(r) {
Ok(mut d) => {
let metadata_end = bytes_read.get();
let frame = d.next_frame_info().unwrap_or_default();
let was_interlaced = frame.map_or(false, |f| f.was_interlaced);
let frame_render_start = bytes_read.get();
let _ = d.read_into_buffer();
let first_scan_end = bytes_read.get();
Ok(Scans {
metadata_end: Some(metadata_end),
frame_render_start: Some(frame_render_start),
first_scan_end: Some(if was_interlaced { frame_render_start + (first_scan_end - frame_render_start) / 2 } else { first_scan_end }),
good_scan_end: Some(first_scan_end),
file_size,
})
},
Err(self::reader::DecodingError::Io(e)) => Err(Error::Io(e)),
Err(self::reader::DecodingError::Format) => Err(Error::Format("can't parse GIF")),
}
}