Coverage Report

Created: 2025-07-04 06:57

/rust/registry/src/index.crates.io-6f17d22bba15001f/gif-0.13.3/src/reader/mod.rs
Line
Count
Source (jump to first uncovered line)
1
use std::borrow::Cow;
2
use std::io;
3
use std::iter::FusedIterator;
4
use std::mem;
5
6
use std::io::prelude::*;
7
use std::num::NonZeroU64;
8
use std::convert::{TryFrom, TryInto};
9
10
use crate::Repeat;
11
use crate::common::{Block, Frame};
12
13
mod decoder;
14
mod converter;
15
16
pub use self::decoder::{
17
    PLTE_CHANNELS, StreamingDecoder, Decoded, DecodingError, DecodingFormatError,
18
    Version, FrameDataType, OutputBuffer, FrameDecoder
19
};
20
21
use self::converter::PixelConverter;
22
pub use self::converter::ColorOutput;
23
24
#[derive(Clone, Debug)]
25
/// The maximum amount of memory the decoder is allowed to use for each frame
26
pub enum MemoryLimit {
27
    /// Enforce no memory limit.
28
    ///
29
    /// If you intend to process images from unknown origins this is a potentially dangerous
30
    /// constant to use, as your program could be vulnerable to decompression bombs. That is,
31
    /// malicious images crafted specifically to require an enormous amount of memory to process
32
    /// while having a disproportionately small file size.
33
    ///
34
    /// The risks for modern machines are a bit smaller as the size of each frame cannot
35
    /// exceed 16GiB, but this is still a significant amount of memory.
36
    Unlimited,
37
    /// Limit the amount of memory that can be used for a single frame to this many bytes.
38
    ///
39
    /// It may not be enforced precisely due to allocator overhead
40
    /// and the decoder potentially allocating small auxiliary buffers,
41
    /// but it will precisely limit the size of the output buffer for each frame.
42
    //
43
    // The `NonZero` type is used to make FFI simpler.
44
    // Due to the guaranteed niche optimization, `Unlimited` will be represented as `0`,
45
    // and the whole enum as a simple `u64`.
46
    Bytes(NonZeroU64),
47
}
48
49
impl MemoryLimit {
50
229k
    fn check_size(&self, size: usize) -> Result<(), DecodingError> {
51
229k
        match self {
52
0
            Self::Unlimited => Ok(()),
53
229k
            Self::Bytes(limit) => {
54
229k
                if size as u64 <= limit.get() {
55
229k
                    Ok(())
56
                } else {
57
0
                    Err(DecodingError::format("memory limit reached"))
58
                }
59
            },
60
        }
61
229k
    }
62
63
0
    fn buffer_size(&self, color: ColorOutput, width: u16, height: u16) -> Option<usize> {
64
0
        let pixels = u64::from(width) * u64::from(height);
65
66
0
        let bytes_per_pixel = match color {
67
0
            ColorOutput::Indexed => 1,
68
0
            ColorOutput::RGBA => 4,
69
        };
70
71
        // This cannot overflow because the maximum possible value is 16GiB, well within u64 range
72
0
        let total_bytes = pixels * bytes_per_pixel;
73
74
        // On 32-bit platforms the size of the output buffer may not be representable
75
0
        let usize_bytes = usize::try_from(total_bytes).ok()?;
76
77
0
        match self {
78
0
            Self::Unlimited => Some(usize_bytes),
79
0
            Self::Bytes(limit) => {
80
0
                if total_bytes > limit.get() {
81
0
                    None
82
                } else {
83
0
                    Some(usize_bytes)
84
                }
85
            },
86
        }
87
0
    }
88
}
89
90
/// Options for opening a GIF decoder. [`DecodeOptions::read_info`] will start the decoder.
91
#[derive(Clone, Debug)]
92
pub struct DecodeOptions {
93
    memory_limit: MemoryLimit,
94
    color_output: ColorOutput,
95
    check_frame_consistency: bool,
96
    skip_frame_decoding: bool,
97
    check_for_end_code: bool,
98
    allow_unknown_blocks: bool,
99
}
100
101
impl Default for DecodeOptions {
102
0
    fn default() -> Self {
103
0
        Self::new()
104
0
    }
105
}
106
107
impl DecodeOptions {
108
    /// Creates a new decoder builder
109
    #[must_use]
110
    #[inline]
111
1.85k
    pub fn new() -> Self {
112
1.85k
        Self {
113
1.85k
            memory_limit: MemoryLimit::Bytes(50_000_000.try_into().unwrap()), // 50 MB
114
1.85k
            color_output: ColorOutput::Indexed,
115
1.85k
            check_frame_consistency: false,
116
1.85k
            skip_frame_decoding: false,
117
1.85k
            check_for_end_code: false,
118
1.85k
            allow_unknown_blocks: false,
119
1.85k
        }
120
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
<gif::reader::DecodeOptions>::new
Line
Count
Source
111
1.85k
    pub fn new() -> Self {
112
1.85k
        Self {
113
1.85k
            memory_limit: MemoryLimit::Bytes(50_000_000.try_into().unwrap()), // 50 MB
114
1.85k
            color_output: ColorOutput::Indexed,
115
1.85k
            check_frame_consistency: false,
116
1.85k
            skip_frame_decoding: false,
117
1.85k
            check_for_end_code: false,
118
1.85k
            allow_unknown_blocks: false,
119
1.85k
        }
120
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
121
122
    /// Configure how color data is decoded.
123
    #[inline]
124
1.85k
    pub fn set_color_output(&mut self, color: ColorOutput) {
125
1.85k
        self.color_output = color;
126
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
<gif::reader::DecodeOptions>::set_color_output
Line
Count
Source
124
1.85k
    pub fn set_color_output(&mut self, color: ColorOutput) {
125
1.85k
        self.color_output = color;
126
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
127
128
    /// Configure a memory limit for decoding.
129
0
    pub fn set_memory_limit(&mut self, limit: MemoryLimit) {
130
0
        self.memory_limit = limit;
131
0
    }
132
133
    /// Configure if frames must be within the screen descriptor.
134
    ///
135
    /// The default is `false`.
136
    ///
137
    /// When turned on, all frame descriptors being read must fit within the screen descriptor or
138
    /// otherwise an error is returned and the stream left in an unspecified state.
139
    ///
140
    /// When turned off, frames may be arbitrarily larger or offset in relation to the screen. Many
141
    /// other decoder libraries handle this in highly divergent ways. This moves all checks to the
142
    /// caller, for example to emulate a specific style.
143
0
    pub fn check_frame_consistency(&mut self, check: bool) {
144
0
        self.check_frame_consistency = check;
145
0
    }
146
147
    /// Configure whether to skip decoding frames.
148
    ///
149
    /// The default is false.
150
    ///
151
    /// When turned on, LZW decoding is skipped. [`Decoder::read_next_frame`] will return
152
    /// compressed LZW bytes in frame's data.
153
    /// [`Decoder::next_frame_info`] will return the metadata of the next frame as usual.
154
    /// This is useful to count frames without incurring the overhead of decoding.
155
0
    pub fn skip_frame_decoding(&mut self, skip: bool) {
156
0
        self.skip_frame_decoding = skip;
157
0
    }
158
159
    /// Configure if LZW encoded blocks must end with a marker end code.
160
    ///
161
    /// The default is `false`.
162
    ///
163
    /// When turned on, all image data blocks—which are LZW encoded—must contain a special bit
164
    /// sequence signalling the end of the data. LZW processing terminates when this code is
165
    /// encountered. The specification states that it must be the last code output by the encoder
166
    /// for an image.
167
    ///
168
    /// When turned off then image data blocks can simply end. Note that this might silently ignore
169
    /// some bits of the last or second to last byte.
170
0
    pub fn check_lzw_end_code(&mut self, check: bool) {
171
0
        self.check_for_end_code = check;
172
0
    }
173
174
    /// Configure if unknown blocks are allowed to be decoded.
175
    ///
176
    /// The default is `false`.
177
    ///
178
    /// When turned on, the decoder will allow unknown blocks to be in the
179
    /// `BlockStart` position.
180
    ///
181
    /// When turned off, decoded block starts must mark an `Image`, `Extension`,
182
    /// or `Trailer` block. Otherwise, the decoded image will return an error.
183
    /// If an unknown block error is returned from decoding, enabling this
184
    /// setting may allow for a further state of decoding on the next attempt.
185
    ///
186
    /// This option also allows unknown extension blocks. The decoder assumes the follow the same
187
    /// block layout, i.e. a sequence of zero-length terminated sub-blocks immediately follow the
188
    /// extension introducer.
189
0
    pub fn allow_unknown_blocks(&mut self, check: bool) {
190
0
        self.allow_unknown_blocks = check;
191
0
    }
192
193
    /// Reads the logical screen descriptor including the global color palette
194
    ///
195
    /// Returns a [`Decoder`]. All decoder configuration has to be done beforehand.
196
1.85k
    pub fn read_info<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> {
197
1.85k
        Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init()
198
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<_>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
<gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Line
Count
Source
196
1.85k
    pub fn read_info<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> {
197
1.85k
        Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init()
198
1.85k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
199
}
200
201
struct ReadDecoder<R: Read> {
202
    reader: io::BufReader<R>,
203
    decoder: StreamingDecoder,
204
    at_eof: bool,
205
}
206
207
impl<R: Read> ReadDecoder<R> {
208
    #[inline(never)]
209
571k
    fn decode_next(&mut self, write_into: &mut OutputBuffer<'_>) -> Result<Option<Decoded>, DecodingError> {
210
572k
        while !self.at_eof {
211
571k
            let (consumed, result) = {
212
572k
                let buf = self.reader.fill_buf()?;
213
572k
                if buf.is_empty() {
214
1.23k
                    return Err(io::ErrorKind::UnexpectedEof.into());
215
571k
                }
216
571k
217
571k
                self.decoder.update(buf, write_into)?
218
            };
219
571k
            self.reader.consume(consumed);
220
4.69k
            match result {
221
1.16k
                Decoded::Nothing => (),
222
7
                Decoded::BlockStart(Block::Trailer) => {
223
7
                    self.at_eof = true;
224
7
                },
225
569k
                result => return Ok(Some(result)),
226
            }
227
        }
228
7
        Ok(None)
229
571k
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<_>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
<gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Line
Count
Source
209
571k
    fn decode_next(&mut self, write_into: &mut OutputBuffer<'_>) -> Result<Option<Decoded>, DecodingError> {
210
572k
        while !self.at_eof {
211
571k
            let (consumed, result) = {
212
572k
                let buf = self.reader.fill_buf()?;
213
572k
                if buf.is_empty() {
214
1.23k
                    return Err(io::ErrorKind::UnexpectedEof.into());
215
571k
                }
216
571k
217
571k
                self.decoder.update(buf, write_into)?
218
            };
219
571k
            self.reader.consume(consumed);
220
4.69k
            match result {
221
1.16k
                Decoded::Nothing => (),
222
7
                Decoded::BlockStart(Block::Trailer) => {
223
7
                    self.at_eof = true;
224
7
                },
225
569k
                result => return Ok(Some(result)),
226
            }
227
        }
228
7
        Ok(None)
229
571k
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
230
231
0
    fn into_inner(self) -> io::BufReader<R> {
232
0
        self.reader
233
0
    }
234
235
330k
    fn decode_next_bytes(&mut self, out: &mut OutputBuffer<'_>) -> Result<usize, DecodingError> {
236
330k
        match self.decode_next(out)? {
237
329k
            Some(Decoded::BytesDecoded(len)) => Ok(len.get()),
238
114
            Some(Decoded::DataEnd) => Ok(0),
239
0
            _ => Err(DecodingError::format("unexpected data")),
240
        }
241
330k
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<_>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
<gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Line
Count
Source
235
330k
    fn decode_next_bytes(&mut self, out: &mut OutputBuffer<'_>) -> Result<usize, DecodingError> {
236
330k
        match self.decode_next(out)? {
237
329k
            Some(Decoded::BytesDecoded(len)) => Ok(len.get()),
238
114
            Some(Decoded::DataEnd) => Ok(0),
239
0
            _ => Err(DecodingError::format("unexpected data")),
240
        }
241
330k
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Unexecuted instantiation: <gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
242
}
243
244
#[allow(dead_code)]
245
/// GIF decoder. Create [`DecodeOptions`] to get started, and call [`DecodeOptions::read_info`].
246
pub struct Decoder<R: Read> {
247
    decoder: ReadDecoder<R>,
248
    pixel_converter: PixelConverter,
249
    bg_color: Option<u8>,
250
    repeat: Repeat,
251
    current_frame: Frame<'static>,
252
    current_frame_data_type: FrameDataType,
253
}
254
255
impl<R> Decoder<R> where R: Read {
256
    /// Create a new decoder with default options.
257
    #[inline]
258
0
    pub fn new(reader: R) -> Result<Self, DecodingError> {
259
0
        DecodeOptions::new().read_info(reader)
260
0
    }
261
262
    /// Return a builder that allows configuring limits etc.
263
    #[must_use]
264
    #[inline]
265
0
    pub fn build() -> DecodeOptions {
266
0
        DecodeOptions::new()
267
0
    }
268
269
1.85k
    fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Self {
270
1.85k
        Self {
271
1.85k
            decoder: ReadDecoder {
272
1.85k
                reader: io::BufReader::new(reader),
273
1.85k
                decoder,
274
1.85k
                at_eof: false,
275
1.85k
            },
276
1.85k
            bg_color: None,
277
1.85k
            pixel_converter: PixelConverter::new(options.color_output, options.memory_limit),
278
1.85k
            repeat: Repeat::default(),
279
1.85k
            current_frame: Frame::default(),
280
1.85k
            current_frame_data_type: FrameDataType::Pixels,
281
1.85k
        }
282
1.85k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<_>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Line
Count
Source
269
1.85k
    fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Self {
270
1.85k
        Self {
271
1.85k
            decoder: ReadDecoder {
272
1.85k
                reader: io::BufReader::new(reader),
273
1.85k
                decoder,
274
1.85k
                at_eof: false,
275
1.85k
            },
276
1.85k
            bg_color: None,
277
1.85k
            pixel_converter: PixelConverter::new(options.color_output, options.memory_limit),
278
1.85k
            repeat: Repeat::default(),
279
1.85k
            current_frame: Frame::default(),
280
1.85k
            current_frame_data_type: FrameDataType::Pixels,
281
1.85k
        }
282
1.85k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
283
284
1.85k
    fn init(mut self) -> Result<Self, DecodingError> {
285
        loop {
286
238k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
287
1.77k
                Some(Decoded::BackgroundColor(bg_color)) => {
288
1.77k
                    self.bg_color = Some(bg_color);
289
1.77k
                }
290
1.75k
                Some(Decoded::GlobalPalette(palette)) => {
291
1.75k
                    self.pixel_converter.set_global_palette(palette.into());
292
1.75k
                },
293
389
                Some(Decoded::Repetitions(repeat)) => {
294
389
                    self.repeat = repeat;
295
389
                },
296
1.52k
                Some(Decoded::HeaderEnd) => break,
297
                Some(_) => {
298
                    // There will be extra events when parsing application extension
299
232k
                    continue;
300
                },
301
0
                None => return Err(DecodingError::format(
302
0
                    "file does not contain any image data"
303
0
                ))
304
            }
305
        }
306
        // If the background color is invalid, ignore it
307
1.52k
        if let Some(palette) = self.pixel_converter.global_palette() {
308
1.31k
            if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) {
309
811
                self.bg_color = None;
310
811
            }
311
211
        }
312
1.52k
        Ok(self)
313
1.85k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<_>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Line
Count
Source
284
1.85k
    fn init(mut self) -> Result<Self, DecodingError> {
285
        loop {
286
238k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
287
1.77k
                Some(Decoded::BackgroundColor(bg_color)) => {
288
1.77k
                    self.bg_color = Some(bg_color);
289
1.77k
                }
290
1.75k
                Some(Decoded::GlobalPalette(palette)) => {
291
1.75k
                    self.pixel_converter.set_global_palette(palette.into());
292
1.75k
                },
293
389
                Some(Decoded::Repetitions(repeat)) => {
294
389
                    self.repeat = repeat;
295
389
                },
296
1.52k
                Some(Decoded::HeaderEnd) => break,
297
                Some(_) => {
298
                    // There will be extra events when parsing application extension
299
232k
                    continue;
300
                },
301
0
                None => return Err(DecodingError::format(
302
0
                    "file does not contain any image data"
303
0
                ))
304
            }
305
        }
306
        // If the background color is invalid, ignore it
307
1.52k
        if let Some(palette) = self.pixel_converter.global_palette() {
308
1.31k
            if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) {
309
811
                self.bg_color = None;
310
811
            }
311
211
        }
312
1.52k
        Ok(self)
313
1.85k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
314
315
    /// Returns the next frame info
316
1.51k
    pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
317
        loop {
318
2.96k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
319
1.39k
                Some(Decoded::FrameMetadata(frame_data_type)) => {
320
1.39k
                    self.current_frame = self.decoder.decoder.current_frame_mut().take();
321
1.39k
                    self.current_frame_data_type = frame_data_type;
322
1.39k
                    if self.current_frame.palette.is_none() && self.global_palette().is_none() {
323
6
                        return Err(DecodingError::format(
324
6
                            "no color table available for current frame",
325
6
                        ));
326
1.38k
                    }
327
1.38k
                    break;
328
                }
329
1.45k
                Some(_) => (),
330
7
                None => return Ok(None),
331
            }
332
        }
333
1.38k
        Ok(Some(&self.current_frame))
334
1.51k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<_>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Line
Count
Source
316
1.51k
    pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
317
        loop {
318
2.96k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
319
1.39k
                Some(Decoded::FrameMetadata(frame_data_type)) => {
320
1.39k
                    self.current_frame = self.decoder.decoder.current_frame_mut().take();
321
1.39k
                    self.current_frame_data_type = frame_data_type;
322
1.39k
                    if self.current_frame.palette.is_none() && self.global_palette().is_none() {
323
6
                        return Err(DecodingError::format(
324
6
                            "no color table available for current frame",
325
6
                        ));
326
1.38k
                    }
327
1.38k
                    break;
328
                }
329
1.45k
                Some(_) => (),
330
7
                None => return Ok(None),
331
            }
332
        }
333
1.38k
        Ok(Some(&self.current_frame))
334
1.51k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
335
336
    /// Reads the next frame from the image.
337
    ///
338
    /// Do not call `Self::next_frame_info` beforehand.
339
    /// Deinterlaces the result.
340
    ///
341
    /// You can also call `.into_iter()` on the decoder to use it as a regular iterator.
342
0
    pub fn read_next_frame(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
343
0
        if self.next_frame_info()?.is_some() {
344
0
            match self.current_frame_data_type {
345
                FrameDataType::Pixels => {
346
0
                    self.pixel_converter.read_frame(&mut self.current_frame, &mut |out| self.decoder.decode_next_bytes(out))?;
347
                },
348
0
                FrameDataType::Lzw { min_code_size } => {
349
0
                    let mut vec = if matches!(self.current_frame.buffer, Cow::Owned(_)) {
350
0
                        let mut vec = mem::replace(&mut self.current_frame.buffer, Cow::Borrowed(&[])).into_owned();
351
0
                        vec.clear();
352
0
                        vec
353
                    } else {
354
0
                        Vec::new()
355
                    };
356
                    // Guesstimate 2bpp
357
0
                    vec.try_reserve(usize::from(self.current_frame.width) * usize::from(self.current_frame.height) / 4)
358
0
                        .map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
359
0
                    self.copy_lzw_into_buffer(min_code_size, &mut vec)?;
360
0
                    self.current_frame.buffer = Cow::Owned(vec);
361
                },
362
            }
363
0
            Ok(Some(&self.current_frame))
364
        } else {
365
0
            Ok(None)
366
        }
367
0
    }
368
369
    /// This is private for iterator's use
370
0
    fn take_current_frame(&mut self) -> Option<Frame<'static>> {
371
0
        if self.current_frame.buffer.is_empty() {
372
0
            return None;
373
0
        }
374
0
        Some(self.current_frame.take())
375
0
    }
376
377
    /// Reads the data of the current frame into a pre-allocated buffer.
378
    ///
379
    /// `Self::next_frame_info` needs to be called beforehand.
380
    /// The length of `buf` must be at least `Self::buffer_size`.
381
    /// Deinterlaces the result.
382
1.37k
    pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> {
383
330k
        self.pixel_converter.read_into_buffer(&self.current_frame, buf, &mut |out| self.decoder.decode_next_bytes(out))
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<_>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Line
Count
Source
383
330k
        self.pixel_converter.read_into_buffer(&self.current_frame, buf, &mut |out| self.decoder.decode_next_bytes(out))
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
384
1.37k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<_>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Line
Count
Source
382
1.37k
    pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> {
383
1.37k
        self.pixel_converter.read_into_buffer(&self.current_frame, buf, &mut |out| self.decoder.decode_next_bytes(out))
384
1.37k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
385
386
0
    fn copy_lzw_into_buffer(&mut self, min_code_size: u8, buf: &mut Vec<u8>) -> Result<(), DecodingError> {
387
0
        // `write_lzw_pre_encoded_frame` smuggles `min_code_size` in the first byte.
388
0
        buf.push(min_code_size);
389
        loop {
390
0
            match self.decoder.decode_next(&mut OutputBuffer::Vec(buf))? {
391
0
                Some(Decoded::LzwDataCopied(_len)) => {},
392
0
                Some(Decoded::DataEnd) => return Ok(()),
393
0
                _ => return Err(DecodingError::format("unexpected data")),
394
            }
395
        }
396
0
    }
397
398
    /// Reads data of the current frame into a pre-allocated buffer until the buffer has been
399
    /// filled completely.
400
    ///
401
    /// The buffer length must be an even number of pixels (multiple of 4 if decoding RGBA).
402
    ///
403
    /// `Self::next_frame_info` needs to be called beforehand. Returns `true` if the supplied
404
    /// buffer could be filled completely. Should not be called after `false` had been returned.
405
0
    pub fn fill_buffer(&mut self, buf: &mut [u8]) -> Result<bool, DecodingError> {
406
0
        self.pixel_converter.fill_buffer(&self.current_frame, buf, &mut |out| self.decoder.decode_next_bytes(out))
407
0
    }
408
409
    /// Output buffer size
410
0
    pub fn buffer_size(&self) -> usize {
411
0
        self.pixel_converter.buffer_size(&self.current_frame).unwrap()
412
0
    }
413
414
    /// Line length of the current frame
415
0
    pub fn line_length(&self) -> usize {
416
0
        self.pixel_converter.line_length(&self.current_frame)
417
0
    }
418
419
    /// Returns the color palette relevant for the frame that has been decoded
420
    #[inline]
421
0
    pub fn palette(&self) -> Result<&[u8], DecodingError> {
422
0
        Ok(match self.current_frame.palette {
423
0
            Some(ref table) => table,
424
0
            None => self.global_palette().ok_or(DecodingError::format(
425
0
                "no color table available for current frame",
426
0
            ))?,
427
        })
428
0
    }
429
430
    /// The global color palette
431
1.27k
    pub fn global_palette(&self) -> Option<&[u8]> {
432
1.27k
        self.pixel_converter.global_palette()
433
1.27k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<_>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Line
Count
Source
431
1.27k
    pub fn global_palette(&self) -> Option<&[u8]> {
432
1.27k
        self.pixel_converter.global_palette()
433
1.27k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
434
435
    /// Width of the image
436
    #[inline]
437
8.98k
    pub fn width(&self) -> u16 {
438
8.98k
        self.decoder.decoder.width()
439
8.98k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<_>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Line
Count
Source
437
8.98k
    pub fn width(&self) -> u16 {
438
8.98k
        self.decoder.decoder.width()
439
8.98k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
440
441
    /// Height of the image
442
    #[inline]
443
8.98k
    pub fn height(&self) -> u16 {
444
8.98k
        self.decoder.decoder.height()
445
8.98k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<_>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Line
Count
Source
443
8.98k
    pub fn height(&self) -> u16 {
444
8.98k
        self.decoder.decoder.height()
445
8.98k
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
446
447
    /// Abort decoding and recover the `io::Read` instance
448
0
    pub fn into_inner(self) -> io::BufReader<R> {
449
0
        self.decoder.into_inner()
450
0
    }
451
452
    /// Index of the background color in the global palette
453
    ///
454
    /// In practice this is not used, and the background is
455
    /// always transparent
456
0
    pub fn bg_color(&self) -> Option<usize> {
457
0
        self.bg_color.map(|v| v as usize)
458
0
    }
459
460
    /// Number of loop repetitions
461
    #[inline]
462
0
    pub fn repeat(&self) -> Repeat {
463
0
        self.repeat
464
0
    }
465
}
466
467
impl<R: Read> IntoIterator for Decoder<R> {
468
    type Item = Result<Frame<'static>, DecodingError>;
469
    type IntoIter = DecoderIter<R>;
470
471
    #[inline]
472
0
    fn into_iter(self) -> Self::IntoIter {
473
0
        DecoderIter {
474
0
            inner: self,
475
0
            ended: false,
476
0
        }
477
0
    }
478
}
479
480
/// Use `decoder.into_iter()` to iterate over the frames
481
pub struct DecoderIter<R: Read> {
482
    inner: Decoder<R>,
483
    ended: bool,
484
}
485
486
impl<R: Read> DecoderIter<R> {
487
    /// Abort decoding and recover the `io::Read` instance
488
    ///
489
    /// Use `for frame in iter.by_ref()` to be able to call this afterwards.
490
0
    pub fn into_inner(self) -> io::BufReader<R> {
491
0
        self.inner.into_inner()
492
0
    }
493
}
494
495
impl<R: Read> FusedIterator for DecoderIter<R> {}
496
497
impl<R: Read> Iterator for DecoderIter<R> {
498
    type Item = Result<Frame<'static>, DecodingError>;
499
500
0
    fn next(&mut self) -> Option<Self::Item> {
501
0
        if !self.ended {
502
0
            match self.inner.read_next_frame() {
503
0
                Ok(Some(_)) => self.inner.take_current_frame().map(Ok),
504
                Ok(None) => {
505
0
                    self.ended = true;
506
0
                    None
507
                },
508
0
                Err(err) => {
509
0
                    self.ended = true;
510
0
                    Some(Err(err))
511
                },
512
            }
513
        } else {
514
0
            None
515
        }
516
0
    }
517
}