aboutsummaryrefslogtreecommitdiff
path: root/vendor/gif/src/reader
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gif/src/reader')
-rw-r--r--vendor/gif/src/reader/decoder.rs724
-rw-r--r--vendor/gif/src/reader/mod.rs522
2 files changed, 1246 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();
+}
diff --git a/vendor/gif/src/reader/mod.rs b/vendor/gif/src/reader/mod.rs
new file mode 100644
index 0000000..a453e79
--- /dev/null
+++ b/vendor/gif/src/reader/mod.rs
@@ -0,0 +1,522 @@
+use std::borrow::Cow;
+use std::io;
+use std::cmp;
+use std::mem;
+use std::iter;
+use std::io::prelude::*;
+
+use crate::common::{Block, Frame};
+
+mod decoder;
+pub use self::decoder::{
+ PLTE_CHANNELS, StreamingDecoder, Decoded, DecodingError, DecodingFormatError, Extensions,
+ Version
+};
+
+const N_CHANNELS: usize = 4;
+
+/// Output mode for the image data
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(u8)]
+pub enum ColorOutput {
+ /// The decoder expands the image data to 32bit RGBA.
+ /// This affects:
+ ///
+ /// - The buffer buffer of the `Frame` returned by `Decoder::read_next_frame`.
+ /// - `Decoder::fill_buffer`, `Decoder::buffer_size` and `Decoder::line_length`.
+ RGBA = 0,
+ /// The decoder returns the raw indexed data.
+ Indexed = 1,
+}
+
+#[derive(Clone, Debug)]
+/// Memory limit in bytes. `MemoryLimit(0)` means
+/// that there is no memory limit set.
+pub struct MemoryLimit(pub u32);
+
+impl MemoryLimit {
+ /// Enforce no memory limit.
+ ///
+ /// If you intend to process images from unknown origins this is a potentially dangerous
+ /// constant to use, as your program could be vulnerable to decompression bombs. That is,
+ /// malicious images crafted specifically to require an enormous amount of memory to process
+ /// while having a disproportionately small file size.
+ ///
+ /// The risks for modern machines are a bit smaller as the dimensions of each frame can not
+ /// exceed `u32::MAX` (~4Gb) but this is still a significant amount of memory.
+ pub const NONE: MemoryLimit = MemoryLimit(0);
+
+ fn buffer_size(&self, color: ColorOutput, width: u16, height: u16) -> Option<usize> {
+ let pixels = u32::from(width) * u32::from(height);
+
+ let bytes_per_pixel = match color {
+ ColorOutput::Indexed => 1,
+ ColorOutput::RGBA => 4,
+ };
+
+ if self.0 > 0 && pixels > self.0 / bytes_per_pixel {
+ None
+ } else {
+ Some(pixels as usize * bytes_per_pixel as usize)
+ }
+ }
+}
+
+/// Options for opening a GIF decoder.
+#[derive(Clone, Debug)]
+pub struct DecodeOptions {
+ memory_limit: MemoryLimit,
+ color_output: ColorOutput,
+ check_frame_consistency: bool,
+ check_for_end_code: bool,
+ allow_unknown_blocks: bool,
+}
+
+impl DecodeOptions {
+ /// Creates a new decoder builder
+ pub fn new() -> DecodeOptions {
+ DecodeOptions {
+ memory_limit: MemoryLimit(50_000_000), // 50 MB
+ color_output: ColorOutput::Indexed,
+ check_frame_consistency: false,
+ check_for_end_code: false,
+ allow_unknown_blocks: false,
+ }
+ }
+
+ /// Configure how color data is decoded.
+ pub fn set_color_output(&mut self, color: ColorOutput) {
+ self.color_output = color;
+ }
+
+ /// Configure a memory limit for decoding.
+ pub fn set_memory_limit(&mut self, limit: MemoryLimit) {
+ self.memory_limit = limit;
+ }
+
+ /// Configure if frames must be within the screen descriptor.
+ ///
+ /// The default is `false`.
+ ///
+ /// When turned on, all frame descriptors being read must fit within the screen descriptor or
+ /// otherwise an error is returned and the stream left in an unspecified state.
+ ///
+ /// When turned off, frames may be arbitrarily larger or offset in relation to the screen. Many
+ /// other decoder libraries handle this in highly divergent ways. This moves all checks to the
+ /// caller, for example to emulate a specific style.
+ pub fn check_frame_consistency(&mut self, check: bool) {
+ self.check_frame_consistency = check;
+ }
+
+ /// Configure if LZW encoded blocks must end with a marker end code.
+ ///
+ /// The default is `false`.
+ ///
+ /// When turned on, all image data blocks—which are LZW encoded—must contain a special bit
+ /// sequence signalling the end of the data. LZW processing terminates when this code is
+ /// encountered. The specification states that it must be the last code output by the encoder
+ /// for an image.
+ ///
+ /// When turned off then image data blocks can simply end. Note that this might silently ignore
+ /// some bits of the last or second to last byte.
+ pub fn check_lzw_end_code(&mut self, check: bool) {
+ self.check_for_end_code = check;
+ }
+
+ /// Configure if unknown blocks are allowed to be decoded.
+ ///
+ /// The default is `false`.
+ ///
+ /// When turned on, the decoder will allow unknown blocks to be in the
+ /// `BlockStart` position.
+ ///
+ /// When turned off, decoded block starts must mark an `Image`, `Extension`,
+ /// or `Trailer` block. Otherwise, the decoded image will return an error.
+ /// If an unknown block error is returned from decoding, enabling this
+ /// setting may allow for a further state of decoding on the next attempt.
+ pub fn allow_unknown_blocks(&mut self, check: bool) {
+ self.allow_unknown_blocks = check;
+ }
+
+ /// Reads the logical screen descriptor including the global color palette
+ ///
+ /// Returns a `Decoder`. All decoder configuration has to be done beforehand.
+ pub fn read_info<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> {
+ Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init()
+ }
+}
+
+struct ReadDecoder<R: Read> {
+ reader: io::BufReader<R>,
+ decoder: StreamingDecoder,
+ at_eof: bool
+}
+
+impl<R: Read> ReadDecoder<R> {
+ fn decode_next(&mut self) -> Result<Option<Decoded>, DecodingError> {
+ while !self.at_eof {
+ let (consumed, result) = {
+ let buf = self.reader.fill_buf()?;
+ if buf.len() == 0 {
+ return Err(DecodingError::format(
+ "unexpected EOF"
+ ))
+ }
+ self.decoder.update(buf)?
+ };
+ self.reader.consume(consumed);
+ match result {
+ Decoded::Nothing => (),
+ Decoded::BlockStart(Block::Trailer) => {
+ self.at_eof = true
+ },
+ result => return Ok(unsafe{
+ // FIXME: #6393
+ Some(mem::transmute::<Decoded, Decoded>(result))
+ }),
+ }
+ }
+ Ok(None)
+ }
+}
+
+#[allow(dead_code)]
+/// GIF decoder
+pub struct Decoder<R: Read> {
+ decoder: ReadDecoder<R>,
+ color_output: ColorOutput,
+ memory_limit: MemoryLimit,
+ bg_color: Option<u8>,
+ global_palette: Option<Vec<u8>>,
+ current_frame: Frame<'static>,
+ buffer: Vec<u8>,
+}
+
+impl<R> Decoder<R> where R: Read {
+ /// Create a new decoder with default options.
+ pub fn new(reader: R) -> Result<Self, DecodingError> {
+ DecodeOptions::new().read_info(reader)
+ }
+
+ /// Return a builder that allows configuring limits etc.
+ pub fn build() -> DecodeOptions {
+ DecodeOptions::new()
+ }
+
+ fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Decoder<R> {
+ Decoder {
+ decoder: ReadDecoder {
+ reader: io::BufReader::new(reader),
+ decoder,
+ at_eof: false
+ },
+ bg_color: None,
+ global_palette: None,
+ buffer: Vec::with_capacity(32),
+ color_output: options.color_output,
+ memory_limit: options.memory_limit,
+ current_frame: Frame::default(),
+ }
+ }
+
+ fn init(mut self) -> Result<Self, DecodingError> {
+ loop {
+ match self.decoder.decode_next()? {
+ Some(Decoded::BackgroundColor(bg_color)) => {
+ self.bg_color = Some(bg_color)
+ }
+ Some(Decoded::GlobalPalette(palette)) => {
+ self.global_palette = if palette.len() > 0 {
+ Some(palette)
+ } else {
+ None
+ };
+ break
+ },
+ Some(_) => {
+ // Unreachable since this loop exists after the global
+ // palette has been read.
+ unreachable!()
+ },
+ None => return Err(DecodingError::format(
+ "file does not contain any image data"
+ ))
+ }
+ }
+ // If the background color is invalid, ignore it
+ if let Some(ref palette) = self.global_palette {
+ if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) {
+ self.bg_color = None;
+ }
+ }
+ Ok(self)
+ }
+
+ /// Returns the next frame info
+ pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
+ if !self.buffer.is_empty() {
+ // FIXME: Warn about discarding data?
+ self.buffer.clear();
+ }
+
+ loop {
+ match self.decoder.decode_next()? {
+ Some(Decoded::Frame(frame)) => {
+ self.current_frame = frame.clone();
+ if frame.palette.is_none() && self.global_palette.is_none() {
+ return Err(DecodingError::format(
+ "no color table available for current frame"
+ ))
+ }
+ break
+ },
+ Some(_) => (),
+ None => return Ok(None)
+
+ }
+ }
+ Ok(Some(&self.current_frame))
+ }
+
+ /// Reads the next frame from the image.
+ ///
+ /// Do not call `Self::next_frame_info` beforehand.
+ /// Deinterlaces the result.
+ pub fn read_next_frame(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
+ if let Some(frame) = self.next_frame_info()? {
+ let (width, height) = (frame.width, frame.height);
+ let pixel_bytes = self.memory_limit
+ .buffer_size(self.color_output, width, height)
+ .ok_or_else(|| {
+ DecodingError::format("image is too large to decode")
+ })?;
+
+ debug_assert_eq!(
+ pixel_bytes, self.buffer_size(),
+ "Checked computation diverges from required buffer size"
+ );
+
+ let mut vec = vec![0; pixel_bytes];
+ self.read_into_buffer(&mut vec)?;
+ self.current_frame.buffer = Cow::Owned(vec);
+ self.current_frame.interlaced = false;
+ Ok(Some(&self.current_frame))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Reads the data of the current frame into a pre-allocated buffer.
+ ///
+ /// `Self::next_frame_info` needs to be called beforehand.
+ /// The length of `buf` must be at least `Self::buffer_size`.
+ /// Deinterlaces the result.
+ pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> {
+ if self.current_frame.interlaced {
+ let width = self.line_length();
+ let height = self.current_frame.height as usize;
+ for row in (InterlaceIterator { len: height, next: 0, pass: 0 }) {
+ if !self.fill_buffer(&mut buf[row*width..][..width])? {
+ return Err(DecodingError::format("image truncated"))
+ }
+ }
+ } else {
+ let buf = &mut buf[..self.buffer_size()];
+ if !self.fill_buffer(buf)? {
+ return Err(DecodingError::format("image truncated"))
+ }
+ };
+ Ok(())
+ }
+
+ /// Reads data of the current frame into a pre-allocated buffer until the buffer has been
+ /// filled completely.
+ ///
+ /// `Self::next_frame_info` needs to be called beforehand. Returns `true` if the supplied
+ /// buffer could be filled completely. Should not be called after `false` had been returned.
+ pub fn fill_buffer(&mut self, mut buf: &mut [u8]) -> Result<bool, DecodingError> {
+ use self::ColorOutput::*;
+ const PLTE_CHANNELS: usize = 3;
+ macro_rules! handle_data(
+ ($data:expr) => {
+ match self.color_output {
+ RGBA => {
+ let transparent = self.current_frame.transparent;
+ let palette: &[u8] = match self.current_frame.palette {
+ Some(ref table) => &*table,
+ None => &*self.global_palette.as_ref().unwrap(),
+ };
+ let len = cmp::min(buf.len()/N_CHANNELS, $data.len());
+ for (rgba, &idx) in buf[..len*N_CHANNELS].chunks_mut(N_CHANNELS).zip($data.iter()) {
+ let plte_offset = PLTE_CHANNELS * idx as usize;
+ if palette.len() >= plte_offset + PLTE_CHANNELS {
+ let colors = &palette[plte_offset..];
+ rgba[0] = colors[0];
+ rgba[1] = colors[1];
+ rgba[2] = colors[2];
+ rgba[3] = if let Some(t) = transparent {
+ if t == idx { 0x00 } else { 0xFF }
+ } else {
+ 0xFF
+ }
+ }
+ }
+ (len, N_CHANNELS)
+ },
+ Indexed => {
+ let len = cmp::min(buf.len(), $data.len());
+ buf[..len].copy_from_slice(&$data[..len]);
+ (len, 1)
+ }
+ }
+ }
+ );
+ let buf_len = self.buffer.len();
+ if buf_len > 0 {
+ let (len, channels) = handle_data!(&self.buffer);
+ let _ = self.buffer.drain(..len);
+ buf = &mut buf[len*channels..];
+ if buf.len() == 0 {
+ return Ok(true)
+ }
+ }
+ loop {
+ match self.decoder.decode_next()? {
+ Some(Decoded::Data(data)) => {
+ let (len, channels) = handle_data!(data);
+ buf = &mut buf[len*channels..]; // shorten buf
+ if buf.len() > 0 {
+ continue
+ } else if len < data.len() {
+ self.buffer.extend_from_slice(&data[len..]);
+ }
+ return Ok(true)
+ },
+ Some(_) => return Ok(false), // make sure that no important result is missed
+ None => return Ok(false)
+
+ }
+ }
+ }
+
+ /// Output buffer size
+ pub fn buffer_size(&self) -> usize {
+ self.line_length() * self.current_frame.height as usize
+ }
+
+ /// Line length of the current frame
+ pub fn line_length(&self) -> usize {
+ use self::ColorOutput::*;
+ match self.color_output {
+ RGBA => self.current_frame.width as usize * N_CHANNELS,
+ Indexed => self.current_frame.width as usize
+ }
+ }
+
+ /// Returns the color palette relevant for the current (next) frame
+ pub fn palette(&self) -> Result<&[u8], DecodingError> {
+ // TODO prevent planic
+ Ok(match self.current_frame.palette {
+ Some(ref table) => &*table,
+ None => &*self.global_palette.as_ref().ok_or(DecodingError::format(
+ "no color table available for current frame"
+ ))?,
+ })
+ }
+
+ /// The global color palette
+ pub fn global_palette(&self) -> Option<&[u8]> {
+ self.global_palette.as_ref().map(|v| &**v)
+ }
+
+ /// Width of the image
+ pub fn width(&self) -> u16 {
+ self.decoder.decoder.width()
+ }
+
+ /// Height of the image
+ pub fn height(&self) -> u16 {
+ self.decoder.decoder.height()
+ }
+
+ /// Index of the background color in the global palette
+ pub fn bg_color(&self) -> Option<usize> {
+ self.bg_color.map(|v| v as usize)
+ }
+}
+
+struct InterlaceIterator {
+ len: usize,
+ next: usize,
+ pass: usize
+}
+
+impl iter::Iterator for InterlaceIterator {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.len == 0 || self.pass > 3 {
+ return None
+ }
+ let mut next = self.next + [8, 8, 4, 2][self.pass];
+ while next >= self.len {
+ next = [4, 2, 1, 0][self.pass];
+ self.pass += 1;
+ }
+ mem::swap(&mut next, &mut self.next);
+ Some(next)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::File;
+
+ use super::{Decoder, InterlaceIterator};
+
+ #[test]
+ fn test_simple_indexed() {
+ let mut decoder = Decoder::new(File::open("tests/samples/sample_1.gif").unwrap()).unwrap();
+ let frame = decoder.read_next_frame().unwrap().unwrap();
+ assert_eq!(&*frame.buffer, &[
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 1, 1, 1, 0, 0, 0, 0, 2, 2, 2,
+ 1, 1, 1, 0, 0, 0, 0, 2, 2, 2,
+ 2, 2, 2, 0, 0, 0, 0, 1, 1, 1,
+ 2, 2, 2, 0, 0, 0, 0, 1, 1, 1,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1
+ ][..])
+ }
+
+ #[test]
+ fn test_interlace_iterator() {
+ for &(len, expect) in &[
+ (0, &[][..]),
+ (1, &[0][..]),
+ (2, &[0, 1][..]),
+ (3, &[0, 2, 1][..]),
+ (4, &[0, 2, 1, 3][..]),
+ (5, &[0, 4, 2, 1, 3][..]),
+ (6, &[0, 4, 2, 1, 3, 5][..]),
+ (7, &[0, 4, 2, 6, 1, 3, 5][..]),
+ (8, &[0, 4, 2, 6, 1, 3, 5, 7][..]),
+ (9, &[0, 8, 4, 2, 6, 1, 3, 5, 7][..]),
+ (10, &[0, 8, 4, 2, 6, 1, 3, 5, 7, 9][..]),
+ (11, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9][..]),
+ (12, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]),
+ (13, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]),
+ (14, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11, 13][..]),
+ (15, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13][..]),
+ (16, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]),
+ (17, &[0, 8, 16, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]),
+ ] {
+ let iter = InterlaceIterator { len: len, next: 0, pass: 0 };
+ let lines = iter.collect::<Vec<_>>();
+ assert_eq!(lines, expect);
+ }
+ }
+}