diff options
author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/gif/src/reader/decoder.rs | |
parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/gif/src/reader/decoder.rs')
-rw-r--r-- | vendor/gif/src/reader/decoder.rs | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/vendor/gif/src/reader/decoder.rs b/vendor/gif/src/reader/decoder.rs new file mode 100644 index 0000000..f0f8eea --- /dev/null +++ b/vendor/gif/src/reader/decoder.rs @@ -0,0 +1,724 @@ +use std::cmp; +use std::error; +use std::fmt; +use std::io; +use std::mem; +use std::default::Default; + +use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame}; +use crate::reader::DecodeOptions; + +use weezl::{BitOrder, decode::Decoder as LzwDecoder, LzwStatus}; + +/// GIF palettes are RGB +pub const PLTE_CHANNELS: usize = 3; + +/// An error returned in the case of the image not being formatted properly. +#[derive(Debug)] +pub struct DecodingFormatError { + underlying: Box<dyn error::Error + Send + Sync + 'static> +} + +impl fmt::Display for DecodingFormatError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&*self.underlying, fmt) + } +} + +impl error::Error for DecodingFormatError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(&*self.underlying as _) + } +} + +impl DecodingFormatError { + fn new( + err: impl Into<Box<dyn error::Error + Send + Sync>>, + ) -> Self { + DecodingFormatError { + underlying: err.into(), + } + } +} + +#[derive(Debug)] +/// Decoding error. +pub enum DecodingError { + /// Returned if the image is found to be malformed. + Format(DecodingFormatError), + /// Wraps `std::io::Error`. + Io(io::Error), +} + +impl DecodingError { + #[inline] + pub(crate) fn format( + err: impl Into<Box<dyn error::Error + Send + Sync>>, + ) -> Self { + DecodingError::Format(DecodingFormatError::new(err)) + } +} + +impl fmt::Display for DecodingError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + DecodingError::Format(ref d) => d.fmt(fmt), + DecodingError::Io(ref err) => err.fmt(fmt), + } + } +} + +impl error::Error for DecodingError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + DecodingError::Format(ref err) => Some(err), + DecodingError::Io(ref err) => Some(err), + } + } +} + +impl From<io::Error> for DecodingError { + fn from(err: io::Error) -> Self { + DecodingError::Io(err) + } +} + +impl From<DecodingFormatError> for DecodingError { + fn from(err: DecodingFormatError) -> Self { + DecodingError::Format(err) + } +} + +/// Configures how extensions should be handled +#[derive(PartialEq, Debug)] +pub enum Extensions { + /// Saves all extention data + Save, + /// Skips the data of unknown extensions + /// and extracts the data from known ones + Skip +} + +/// Indicates whether a certain object has been decoded +#[derive(Debug)] +pub enum Decoded<'a> { + /// Decoded nothing. + Nothing, + /// Global palette. + GlobalPalette(Vec<u8>), + /// Index of the background color in the global palette. + BackgroundColor(u8), + /// Decoded the image trailer. + Trailer, + /// The start of a block. + BlockStart(Block), + /// Decoded a sub-block. More sub-block are available. + /// + /// Indicates the label of the extension which might be unknown. A label of `0` is used when + /// the sub block does not belong to an extension. + SubBlockFinished(AnyExtension, &'a [u8]), + /// Decoded the last (or only) sub-block of a block. + /// + /// Indicates the label of the extension which might be unknown. A label of `0` is used when + /// the sub block does not belong to an extension. + BlockFinished(AnyExtension, &'a [u8]), + /// Decoded all information of the next frame. + /// + /// The returned frame does **not** contain any owned image data. + Frame(&'a Frame<'static>), + /// Decoded some data of the current frame. + Data(&'a [u8]), + /// No more data available the current frame. + DataEnd, + +} + +/// Internal state of the GIF decoder +#[derive(Debug)] +enum State { + Magic(usize, [u8; 6]), + U16Byte1(U16Value, u8), + U16(U16Value), + Byte(ByteValue), + GlobalPalette(usize), + BlockStart(Option<Block>), + /// Block end, with remaining expected data. NonZero for invalid EOF. + BlockEnd(u8), + ExtensionBlock(AnyExtension), + SkipBlock(usize), + LocalPalette(usize), + LzwInit(u8), + DecodeSubBlock(usize), + FrameDecoded, + Trailer +} +use self::State::*; + +/// U16 values that may occur in a GIF image +#[derive(Debug)] +enum U16Value { + /// Logical screen descriptor width + ScreenWidth, + /// Logical screen descriptor height + ScreenHeight, + /// Delay time + Delay, + /// Left frame offset + ImageLeft, + /// Top frame offset + ImageTop, + /// Frame width + ImageWidth, + /// Frame height + ImageHeight, +} + +/// Single byte screen descriptor values +#[derive(Debug)] +enum ByteValue { + GlobalFlags, + Background { table_size: usize }, + AspectRatio { table_size: usize }, + ControlFlags, + ImageFlags, + TransparentIdx, + CodeSize, +} + +/// GIF decoder which supports streaming +pub struct StreamingDecoder { + state: Option<State>, + lzw_reader: Option<LzwDecoder>, + decode_buffer: Vec<u8>, + skip_extensions: bool, + check_frame_consistency: bool, + check_for_end_code: bool, + allow_unknown_blocks: bool, + version: Version, + width: u16, + height: u16, + global_color_table: Vec<u8>, + background_color: [u8; 4], + /// ext buffer + ext: ExtensionData, + /// Frame data + current: Option<Frame<'static>>, +} + +/// One version number of the GIF standard. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Version { + /// Version 87a, from May 1987. + V87a, + /// Version 89a, from July 1989. + V89a, +} + +struct ExtensionData { + id: AnyExtension, + data: Vec<u8>, + is_block_end: bool, +} + +impl StreamingDecoder { + /// Creates a new streaming decoder + pub fn new() -> StreamingDecoder { + let options = DecodeOptions::new(); + Self::with_options(&options) + } + + pub(crate) fn with_options(options: &DecodeOptions) -> Self { + StreamingDecoder { + state: Some(Magic(0, [0; 6])), + lzw_reader: None, + decode_buffer: vec![], + skip_extensions: true, + check_frame_consistency: options.check_frame_consistency, + check_for_end_code: options.check_for_end_code, + allow_unknown_blocks: options.allow_unknown_blocks, + version: Version::V87a, + width: 0, + height: 0, + global_color_table: Vec::new(), + background_color: [0, 0, 0, 0xFF], + ext: ExtensionData { + id: AnyExtension(0), + data: Vec::with_capacity(256), // 0xFF + 1 byte length + is_block_end: true, + }, + current: None + } + } + + /// Updates the internal state of the decoder. + /// + /// Returns the number of bytes consumed from the input buffer + /// and the last decoding result. + pub fn update<'a>(&'a mut self, mut buf: &[u8]) + -> Result<(usize, Decoded<'a>), DecodingError> { + // NOTE: Do not change the function signature without double-checking the + // unsafe block! + let len = buf.len(); + while buf.len() > 0 && self.state.is_some() { + match self.next_state(buf) { + Ok((bytes, Decoded::Nothing)) => { + buf = &buf[bytes..] + } + Ok((bytes, Decoded::Trailer)) => { + buf = &buf[bytes..]; + break + } + Ok((bytes, result)) => { + buf = &buf[bytes..]; + return Ok( + (len-buf.len(), + // This transmute just casts the lifetime away. Since Rust only + // has SESE regions, this early return cannot be worked out and + // such that the borrow region of self includes the whole block. + // The explixit lifetimes in the function signature ensure that + // this is safe. + // ### NOTE + // To check that everything is sound, return the result without + // the match (e.g. `return Ok(self.next_state(buf)?)`). If + // it compiles the returned lifetime is correct. + unsafe { + mem::transmute::<Decoded, Decoded>(result) + } + )) + } + Err(err) => return Err(err) + } + } + Ok((len-buf.len(), Decoded::Nothing)) + + } + + /// Returns the data of the last extension that has been decoded. + pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) { + (self.ext.id, &self.ext.data, self.ext.is_block_end) + } + + #[inline(always)] + /// Current frame info as a mutable ref. + pub fn current_frame_mut<'a>(&'a mut self) -> &'a mut Frame<'static> { + self.current.as_mut().unwrap() + } + + #[inline(always)] + /// Current frame info as a ref. + pub fn current_frame<'a>(&'a self) -> &'a Frame<'static> { + self.current.as_ref().unwrap() + } + + /// Width of the image + pub fn width(&self) -> u16 { + self.width + } + + /// Height of the image + pub fn height(&self) -> u16 { + self.height + } + + /// The version number of the GIF standard used in this image. + /// + /// We suppose a minimum of `V87a` compatibility. This value will be reported until we have + /// read the version information in the magic header bytes. + pub fn version(&self) -> Version { + self.version + } + + /// Configure whether extensions are saved or skipped. + #[deprecated = "Does not work as intended. In fact, doesn't do anything. This may disappear soon."] + pub fn set_extensions(&mut self, extensions: Extensions) { + self.skip_extensions = match extensions { + Extensions::Skip => true, + Extensions::Save => false, + } + } + + fn next_state<'a>(&'a mut self, buf: &[u8]) -> Result<(usize, Decoded<'a>), DecodingError> { + macro_rules! goto ( + ($n:expr, $state:expr) => ({ + self.state = Some($state); + Ok(($n, Decoded::Nothing)) + }); + ($state:expr) => ({ + self.state = Some($state); + Ok((1, Decoded::Nothing)) + }); + ($n:expr, $state:expr, emit $res:expr) => ({ + self.state = Some($state); + Ok(($n, $res)) + }); + ($state:expr, emit $res:expr) => ({ + self.state = Some($state); + Ok((1, $res)) + }) + ); + + let b = buf[0]; + + // Driver should ensure that state is never None + let state = self.state.take().unwrap(); + //println!("{:?}", state); + + match state { + Magic(i, mut version) => if i < 6 { + version[i] = b; + goto!(Magic(i+1, version)) + } else if &version[..3] == b"GIF" { + self.version = match &version[3..] { + b"87a" => Version::V87a, + b"89a" => Version::V89a, + _ => return Err(DecodingError::format("unsupported GIF version")) + }; + goto!(U16Byte1(U16Value::ScreenWidth, b)) + } else { + Err(DecodingError::format("malformed GIF header")) + }, + U16(next) => goto!(U16Byte1(next, b)), + U16Byte1(next, value) => { + use self::U16Value::*; + let value = ((b as u16) << 8) | value as u16; + match (next, value) { + (ScreenWidth, width) => { + self.width = width; + goto!(U16(U16Value::ScreenHeight)) + }, + (ScreenHeight, height) => { + self.height = height; + goto!(Byte(ByteValue::GlobalFlags)) + }, + (Delay, delay) => { + self.ext.data.push(value as u8); + self.ext.data.push(b); + self.current_frame_mut().delay = delay; + goto!(Byte(ByteValue::TransparentIdx)) + }, + (ImageLeft, left) => { + self.current_frame_mut().left = left; + goto!(U16(U16Value::ImageTop)) + }, + (ImageTop, top) => { + self.current_frame_mut().top = top; + goto!(U16(U16Value::ImageWidth)) + }, + (ImageWidth, width) => { + self.current_frame_mut().width = width; + goto!(U16(U16Value::ImageHeight)) + }, + (ImageHeight, height) => { + self.current_frame_mut().height = height; + goto!(Byte(ByteValue::ImageFlags)) + } + } + } + Byte(value) => { + use self::ByteValue::*; + match value { + GlobalFlags => { + let global_table = b & 0x80 != 0; + let entries = if global_table { + let entries = PLTE_CHANNELS*(1 << ((b & 0b111) + 1) as usize); + self.global_color_table.reserve_exact(entries); + entries + } else { + 0usize + }; + goto!(Byte(Background { table_size: entries })) + }, + Background { table_size } => { + goto!( + Byte(AspectRatio { table_size: table_size }), + emit Decoded::BackgroundColor(b) + ) + }, + AspectRatio { table_size } => { + goto!(GlobalPalette(table_size)) + }, + ControlFlags => { + self.ext.data.push(b); + let control_flags = b; + if control_flags & 1 != 0 { + // Set to Some(...), gets overwritten later + self.current_frame_mut().transparent = Some(0) + } + self.current_frame_mut().needs_user_input = + control_flags & 0b10 != 0; + self.current_frame_mut().dispose = match DisposalMethod::from_u8( + (control_flags & 0b11100) >> 2 + ) { + Some(method) => method, + None => DisposalMethod::Any + }; + goto!(U16(U16Value::Delay)) + } + TransparentIdx => { + self.ext.data.push(b); + if let Some(ref mut idx) = self.current_frame_mut().transparent { + *idx = b + } + goto!(SkipBlock(0)) + //goto!(AwaitBlockEnd) + } + ImageFlags => { + let local_table = (b & 0b1000_0000) != 0; + let interlaced = (b & 0b0100_0000) != 0; + let table_size = b & 0b0000_0111; + + self.current_frame_mut().interlaced = interlaced; + + if self.check_frame_consistency { + // Consistency checks. + let (width, height) = (self.width, self.height); + let frame = self.current_frame_mut(); + if width.checked_sub(frame.width) < Some(frame.left) + || height.checked_sub(frame.height) < Some(frame.top) + { + return Err(DecodingError::format("frame descriptor is out-of-bounds")) + } + } + + if local_table { + let entries = PLTE_CHANNELS * (1 << (table_size + 1)); + + self.current_frame_mut().palette = + Some(Vec::with_capacity(entries)); + goto!(LocalPalette(entries)) + } else { + goto!(Byte(CodeSize)) + } + }, + CodeSize => goto!(LzwInit(b)) + } + } + GlobalPalette(left) => { + let n = cmp::min(left, buf.len()); + if left > 0 { + self.global_color_table.extend_from_slice(&buf[..n]); + goto!(n, GlobalPalette(left - n)) + } else { + let idx = self.background_color[0]; + match self.global_color_table.chunks(PLTE_CHANNELS).nth(idx as usize) { + Some(chunk) => self.background_color[..PLTE_CHANNELS] + .copy_from_slice(&chunk[..PLTE_CHANNELS]), + None => self.background_color[0] = 0 + } + goto!(BlockStart(Block::from_u8(b)), emit Decoded::GlobalPalette( + mem::replace(&mut self.global_color_table, Vec::new()) + )) + } + } + BlockStart(type_) => { + match type_ { + Some(Block::Image) => { + self.add_frame(); + goto!(U16Byte1(U16Value::ImageLeft, b), emit Decoded::BlockStart(Block::Image)) + } + Some(Block::Extension) => { + goto!(ExtensionBlock(AnyExtension(b)), emit Decoded::BlockStart(Block::Extension)) + } + Some(Block::Trailer) => { + goto!(0, State::Trailer, emit Decoded::BlockStart(Block::Trailer)) + } + None => { + if self.allow_unknown_blocks { + goto!(SkipBlock(b as usize)) + } else { + Err(DecodingError::format("unknown block type encountered")) + } + } + } + } + BlockEnd(terminator) => { + if terminator == 0 { + if b == Block::Trailer as u8 { + goto!(0, BlockStart(Some(Block::Trailer))) + } else { + goto!(BlockStart(Block::from_u8(b))) + } + } else { + return Err(DecodingError::format( + "expected block terminator not found" + )) + } + } + ExtensionBlock(id) => { + use Extension::*; + self.ext.id = id; + self.ext.data.clear(); + self.ext.data.push(b); + if let Some(ext) = Extension::from_u8(id.0) { + match ext { + Control => { + goto!(self.read_control_extension(b)?) + } + Text | Comment | Application => { + goto!(SkipBlock(b as usize)) + } + } + } else { + return Err(DecodingError::format( + "unknown extention block encountered" + )) + } + } + SkipBlock(left) => { + let n = cmp::min(left, buf.len()); + if left > 0 { + self.ext.data.extend_from_slice(&buf[..n]); + goto!(n, SkipBlock(left - n)) + } else { + if b == 0 { + self.ext.is_block_end = true; + goto!(BlockEnd(b), emit Decoded::BlockFinished(self.ext.id, &self.ext.data)) + } else { + self.ext.is_block_end = false; + goto!(SkipBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id, &self.ext.data)) + } + } + } + LocalPalette(left) => { + let n = cmp::min(left, buf.len()); + if left > 0 { + + self.current_frame_mut().palette + .as_mut().unwrap().extend(buf[..n].iter().cloned()); + goto!(n, LocalPalette(left - n)) + } else { + goto!(LzwInit(b)) + } + } + LzwInit(code_size) => { + // LZW spec: max 12 bits per code + if code_size > 11 { + return Err(DecodingError::format( + "invalid minimal code size" + )) + } + self.lzw_reader = Some(LzwDecoder::new(BitOrder::Lsb, code_size)); + goto!(DecodeSubBlock(b as usize), emit Decoded::Frame(self.current_frame_mut())) + } + DecodeSubBlock(left) => { + if left > 0 { + let n = cmp::min(left, buf.len()); + let max_bytes = self.current_frame().required_bytes(); + let decoder = self.lzw_reader.as_mut().unwrap(); + if decoder.has_ended() { + debug_assert!(n > 0, "Made forward progress after LZW end"); + return goto!(n, DecodeSubBlock(0), emit Decoded::Data(&[])); + } + + let mut dummy_target; + let decode_target; + + if self.decode_buffer.is_empty() { + let size = (1 << 14).min(max_bytes); + self.decode_buffer = vec![0; size]; + } + + if max_bytes == 0 { + dummy_target = [0; 16]; + decode_target = &mut dummy_target[..]; + } else { + decode_target = self.decode_buffer.as_mut_slice(); + } + + debug_assert!(!decode_target.is_empty(), "LZW decoding can make forward progress."); + let decoded = decoder.decode_bytes(&buf[..n], decode_target); + + if let Err(err) = decoded.status { + return Err(io::Error::new(io::ErrorKind::InvalidData, &*format!("{:?}", err)).into()); + } + + let bytes = &self.decode_buffer[..decoded.consumed_out.min(max_bytes)]; + let consumed = decoded.consumed_in; + goto!(consumed, DecodeSubBlock(left - consumed), emit Decoded::Data(bytes)) + } else if b != 0 { // decode next sub-block + goto!(DecodeSubBlock(b as usize)) + } else { + let max_bytes = self.current_frame().required_bytes(); + // The end of the lzw stream is only reached if left == 0 and an additional call + // to `decode_bytes` results in an empty slice. + let decoder = self.lzw_reader.as_mut().unwrap(); + // Some mutable bytes to decode into. We need this for forward progress in + // `lzw`. However, in some cases we do not actually need any bytes, when + // `max_bytes` is `0`. + let mut dummy_target; + let decode_target; + + if self.decode_buffer.is_empty() { + let size = (1 << 14).min(max_bytes); + self.decode_buffer = vec![0; size]; + } + + if max_bytes == 0 { + dummy_target = [0; 16]; + decode_target = &mut dummy_target[..]; + } else { + decode_target = self.decode_buffer.as_mut_slice(); + } + + debug_assert!(!decode_target.is_empty(), "LZW decoding can make forward progress."); + let decoded = decoder.decode_bytes(&[], decode_target); + + match decoded.status { + Ok(LzwStatus::Done) | Ok(LzwStatus::Ok) => {}, + Ok(LzwStatus::NoProgress) => { + if self.check_for_end_code { + return Err(io::Error::new(io::ErrorKind::InvalidData, "No end code in lzw stream").into()); + } else { + self.current = None; + return goto!(0, FrameDecoded, emit Decoded::DataEnd); + } + }, + Err(err) => { + return Err(io::Error::new(io::ErrorKind::InvalidData, &*format!("{:?}", err)).into()); + } + } + let bytes = &self.decode_buffer[..decoded.consumed_out.min(max_bytes)]; + + if bytes.len() > 0 { + goto!(0, DecodeSubBlock(0), emit Decoded::Data(bytes)) + } else { + // end of image data reached + self.current = None; + goto!(0, FrameDecoded, emit Decoded::DataEnd) + } + } + } + FrameDecoded => { + goto!(BlockEnd(b)) + } + Trailer => { + self.state = None; + Ok((1, Decoded::Trailer)) + //panic!("EOF {:?}", self) + } + } + } + + fn read_control_extension(&mut self, b: u8) -> Result<State, DecodingError> { + self.add_frame(); + self.ext.data.push(b); + if b != 4 { + return Err(DecodingError::format( + "control extension has wrong length" + )) + } + Ok(Byte(ByteValue::ControlFlags)) + } + + fn add_frame(&mut self) { + if self.current.is_none() { + self.current = Some(Frame::default()) + } + } +} + +#[test] +fn error_cast() { + let _ : Box<dyn error::Error> = DecodingError::Format(DecodingFormatError::new("testing")).into(); +} |