diff options
Diffstat (limited to 'vendor/gif/src/reader/mod.rs')
-rw-r--r-- | vendor/gif/src/reader/mod.rs | 522 |
1 files changed, 0 insertions, 522 deletions
diff --git a/vendor/gif/src/reader/mod.rs b/vendor/gif/src/reader/mod.rs deleted file mode 100644 index a453e79..0000000 --- a/vendor/gif/src/reader/mod.rs +++ /dev/null @@ -1,522 +0,0 @@ -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); - } - } -} |