diff options
author | Genny <gen@nyble.dev> | 2021-11-21 18:35:57 -0600 |
---|---|---|
committer | Genny <gen@nyble.dev> | 2021-11-21 18:35:57 -0600 |
commit | 1de64a3818875947f7f1044b1d4cfdf271b04fd3 (patch) | |
tree | 3a5bfbb237d67832dfa1beeb3d28566173484b63 /src/reader/mod.rs | |
parent | f35e18cb0531e7d6a3544560746d592aa47ed555 (diff) | |
download | gifed-1de64a3818875947f7f1044b1d4cfdf271b04fd3.tar.gz gifed-1de64a3818875947f7f1044b1d4cfdf271b04fd3.zip |
Bring gifprobe into this repository
Diffstat (limited to 'src/reader/mod.rs')
-rw-r--r-- | src/reader/mod.rs | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/src/reader/mod.rs b/src/reader/mod.rs deleted file mode 100644 index 41494df..0000000 --- a/src/reader/mod.rs +++ /dev/null @@ -1,274 +0,0 @@ -use std::{ - borrow::Cow, - convert::{TryFrom, TryInto}, - error::Error, - fmt, - fs::File, - io::{BufRead, BufReader, Read}, - path::Path, -}; - -use crate::{ - block::{ - extension::{Application, Extension, GraphicControl}, - Block, ColorTable, CompressedImage, ImageDescriptor, IndexedImage, ScreenDescriptor, - Version, - }, - color, Gif, -}; - -pub struct GifReader {} - -impl GifReader { - pub fn file<P: AsRef<Path>>(path: P) -> Result<Gif, DecodingError> { - let mut file = File::open(path)?; - let mut reader = SmartReader { - inner: vec![], - position: 0, - }; - file.read_to_end(&mut reader.inner)?; - - let mut gif = Self::read_required(&mut reader)?; - - if gif.screen_descriptor.color_table_present() { - let gct_size = gif.screen_descriptor.color_table_len() * 3; - gif.global_color_table = Some(Self::read_color_table(&mut reader, gct_size)?); - } - - loop { - match Self::read_block(&mut reader)? { - Some(block) => gif.blocks.push(block), - None => return Ok(gif), - } - } - } - - fn read_required(reader: &mut SmartReader) -> Result<Gif, DecodingError> { - let version = match reader.take_lossy_utf8(6).as_deref() { - Some("GIF87a") => Version::Gif87a, - Some("GIF89a") => Version::Gif89a, - _ => return Err(DecodingError::UnknownVersionString), - }; - - let mut lsd_buffer: [u8; 7] = [0; 7]; - reader - .read_exact(&mut lsd_buffer) - .ok_or(DecodingError::UnexpectedEof)?; - - let lsd = ScreenDescriptor::from(lsd_buffer); - - Ok(Gif { - header: version, - screen_descriptor: lsd, - global_color_table: None, - blocks: vec![], - }) - } - - fn read_color_table( - reader: &mut SmartReader, - size: usize, - ) -> Result<ColorTable, DecodingError> { - let buffer = reader - .take(size as usize) - .ok_or(DecodingError::UnexpectedEof)?; - - // We get the size from the screen descriptor. This should never return Err - Ok(ColorTable::try_from(&buffer[..]).unwrap()) - } - - fn read_block(reader: &mut SmartReader) -> Result<Option<Block>, DecodingError> { - let block_id = reader.u8().ok_or(DecodingError::UnexpectedEof)?; - - //TODO: remove panic - match block_id { - 0x21 => Self::read_extension(reader).map(|block| Some(block)), - 0x2C => Self::read_image(reader).map(|block| Some(block)), - 0x3B => Ok(None), - _ => panic!( - "Unknown block identifier {:X} {:X}", - block_id, reader.position - ), - } - } - - fn read_extension(reader: &mut SmartReader) -> Result<Block, DecodingError> { - let extension_id = reader.u8().expect("File ended early"); - - match extension_id { - 0xF9 => { - reader.skip(1); // Skip block length, we know it - let mut data = [0u8; 4]; - reader - .read_exact(&mut data) - .ok_or(DecodingError::UnexpectedEof)?; - reader.skip(1); // Skip block terminator - - Ok(Block::Extension(Extension::GraphicControl( - GraphicControl::from(data), - ))) - } - 0xFE => Ok(Block::Extension(Extension::Comment( - reader.take_and_collapse_subblocks(), - ))), - 0x01 => todo!(), //TODO: do; plain text extension - 0xFF => { - //TODO: error instead of unwraps - assert_eq!(Some(11), reader.u8()); - let identifier = reader.take_lossy_utf8(8).unwrap().to_string(); - let authentication_code: [u8; 3] = - TryInto::try_into(reader.take(3).unwrap()).unwrap(); - let data = reader.take_and_collapse_subblocks(); - - Ok(Block::Extension(Extension::Application(Application { - identifier, - authentication_code, - data, - }))) - } - _ => panic!("Unknown Extension Identifier!"), - } - } - - fn read_image(mut reader: &mut SmartReader) -> Result<Block, DecodingError> { - let mut buffer = [0u8; 9]; - reader - .read_exact(&mut buffer) - .ok_or(DecodingError::UnexpectedEof)?; - let descriptor = ImageDescriptor::from(buffer); - - let color_table = if descriptor.color_table_present() { - let size = descriptor.color_table_size() * 3; - Some(Self::read_color_table(&mut reader, size)?) - } else { - None - }; - - let lzw_csize = reader.u8().ok_or(DecodingError::UnexpectedEof)?; - - let compressed_data = reader.take_and_collapse_subblocks(); - - let mut decompress = weezl::decode::Decoder::new(weezl::BitOrder::Lsb, lzw_csize); - //TODO: remove unwrap - let mut decompressed_data = decompress.decode(&compressed_data).unwrap(); - - Ok(Block::IndexedImage(IndexedImage { - image_descriptor: descriptor, - local_color_table: color_table, - indicies: decompressed_data, - })) - } -} - -#[derive(Debug)] -pub enum DecodingError { - IoError(std::io::Error), - UnknownVersionString, - UnexpectedEof, - ColorIndexOutOfBounds, -} - -impl Error for DecodingError {} -impl fmt::Display for DecodingError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DecodingError::IoError(error) => write!(f, "{}", error), - DecodingError::UnknownVersionString => { - write!(f, "File did not start with a valid header") - } - DecodingError::UnexpectedEof => { - write!(f, "Found the end of the data at a weird spot") - } - DecodingError::ColorIndexOutOfBounds => { - write!( - f, - "The image contained an index not found in the color table" - ) - } - } - } -} - -impl From<std::io::Error> for DecodingError { - fn from(ioerror: std::io::Error) -> Self { - DecodingError::IoError(ioerror) - } -} - -struct SmartReader { - inner: Vec<u8>, - position: usize, -} - -impl SmartReader { - pub fn u8(&mut self) -> Option<u8> { - self.position += 1; - self.inner.get(self.position - 1).map(|b| *b) - } - - pub fn u16(&mut self) -> Option<u16> { - self.position += 2; - self.inner - .get(self.position - 2..self.position) - .map(|bytes| u16::from_le_bytes(bytes.try_into().unwrap())) - } - - pub fn skip(&mut self, size: usize) { - self.position += size; - } - - pub fn take(&mut self, size: usize) -> Option<&[u8]> { - self.position += size; - self.inner.get(self.position - size..self.position) - } - - //TODO: Result not Option when buffer len - pub fn read_exact(&mut self, buf: &mut [u8]) -> Option<()> { - if self.position + buf.len() > self.inner.len() { - None - } else { - self.position += buf.len(); - buf.copy_from_slice(&self.inner[self.position - buf.len()..self.position]); - Some(()) - } - } - - pub fn take_vec(&mut self, size: usize) -> Option<Vec<u8>> { - self.position += size; - self.inner - .get(self.position - size..self.position) - .map(|bytes| bytes.to_vec()) - } - - pub fn take_lossy_utf8(&mut self, size: usize) -> Option<Cow<'_, str>> { - self.take(size).map(|bytes| String::from_utf8_lossy(bytes)) - } - - pub fn take_data_subblocks(&mut self) -> Vec<Vec<u8>> { - let mut blocks = vec![]; - - loop { - let block_size = self.u8().expect("Failed to read length of sublock"); - - if block_size == 0 { - return blocks; - } - - let block = self - .take_vec(block_size as usize) - .expect("Failed to read sublock"); - - blocks.push(block); - } - } - - pub fn take_and_collapse_subblocks(&mut self) -> Vec<u8> { - let blocks = self.take_data_subblocks(); - let mut ret = vec![]; - for block in blocks { - ret.extend_from_slice(&block) - } - - ret - } -} |