Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/gif-0.14.1/src/reader/mod.rs
Line
Count
Source
1
use alloc::borrow::Cow;
2
use alloc::vec::Vec;
3
use core::convert::{TryFrom, TryInto};
4
use core::iter::FusedIterator;
5
use core::mem;
6
use core::num::NonZeroU64;
7
use std::io;
8
use std::io::prelude::*;
9
10
use crate::common::{Block, Frame};
11
use crate::{AnyExtension, Extension, Repeat};
12
13
mod converter;
14
mod decoder;
15
16
pub use self::decoder::{
17
    Decoded, DecodingError, DecodingFormatError, FrameDataType, FrameDecoder, OutputBuffer,
18
    StreamingDecoder, Version, PLTE_CHANNELS,
19
};
20
21
pub use self::converter::ColorOutput;
22
use self::converter::PixelConverter;
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
825k
    fn check_size(&self, size: usize) -> Result<(), DecodingError> {
51
825k
        match self {
52
0
            Self::Unlimited => Ok(()),
53
825k
            Self::Bytes(limit) => {
54
825k
                if size as u64 <= limit.get() {
55
825k
                    Ok(())
56
                } else {
57
0
                    Err(DecodingError::MemoryLimit)
58
                }
59
            }
60
        }
61
825k
    }
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
    #[inline]
90
825k
    fn try_reserve(&self, vec: &mut Vec<u8>, additional: usize) -> Result<(), DecodingError> {
91
825k
        let len = vec
92
825k
            .len()
93
825k
            .checked_add(additional)
94
825k
            .ok_or(DecodingError::MemoryLimit)?;
95
825k
        self.check_size(len)?;
96
825k
        vec.try_reserve(additional)
97
825k
            .map_err(|_| DecodingError::OutOfMemory)?;
98
825k
        Ok(())
99
825k
    }
<gif::reader::MemoryLimit>::try_reserve
Line
Count
Source
90
825k
    fn try_reserve(&self, vec: &mut Vec<u8>, additional: usize) -> Result<(), DecodingError> {
91
825k
        let len = vec
92
825k
            .len()
93
825k
            .checked_add(additional)
94
825k
            .ok_or(DecodingError::MemoryLimit)?;
95
825k
        self.check_size(len)?;
96
825k
        vec.try_reserve(additional)
97
825k
            .map_err(|_| DecodingError::OutOfMemory)?;
98
825k
        Ok(())
99
825k
    }
Unexecuted instantiation: <gif::reader::MemoryLimit>::try_reserve
100
}
101
102
/// Options for opening a GIF decoder. [`DecodeOptions::read_info`] will start the decoder.
103
#[derive(Clone, Debug)]
104
pub struct DecodeOptions {
105
    memory_limit: MemoryLimit,
106
    color_output: ColorOutput,
107
    check_frame_consistency: bool,
108
    skip_frame_decoding: bool,
109
    check_for_end_code: bool,
110
    allow_unknown_blocks: bool,
111
}
112
113
impl Default for DecodeOptions {
114
0
    fn default() -> Self {
115
0
        Self::new()
116
0
    }
117
}
118
119
impl DecodeOptions {
120
    /// Creates a new decoder builder
121
    #[must_use]
122
    #[inline]
123
3.17k
    pub fn new() -> Self {
124
3.17k
        Self {
125
3.17k
            memory_limit: MemoryLimit::Bytes(50_000_000.try_into().unwrap()), // 50 MB
126
3.17k
            color_output: ColorOutput::Indexed,
127
3.17k
            check_frame_consistency: false,
128
3.17k
            skip_frame_decoding: false,
129
3.17k
            check_for_end_code: false,
130
3.17k
            allow_unknown_blocks: false,
131
3.17k
        }
132
3.17k
    }
<gif::reader::DecodeOptions>::new
Line
Count
Source
123
3.17k
    pub fn new() -> Self {
124
3.17k
        Self {
125
3.17k
            memory_limit: MemoryLimit::Bytes(50_000_000.try_into().unwrap()), // 50 MB
126
3.17k
            color_output: ColorOutput::Indexed,
127
3.17k
            check_frame_consistency: false,
128
3.17k
            skip_frame_decoding: false,
129
3.17k
            check_for_end_code: false,
130
3.17k
            allow_unknown_blocks: false,
131
3.17k
        }
132
3.17k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::new
133
134
    /// Configure how color data is decoded.
135
    #[inline]
136
3.17k
    pub fn set_color_output(&mut self, color: ColorOutput) {
137
3.17k
        self.color_output = color;
138
3.17k
    }
<gif::reader::DecodeOptions>::set_color_output
Line
Count
Source
136
3.17k
    pub fn set_color_output(&mut self, color: ColorOutput) {
137
3.17k
        self.color_output = color;
138
3.17k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::set_color_output
139
140
    /// Configure a memory limit for decoding.
141
0
    pub fn set_memory_limit(&mut self, limit: MemoryLimit) {
142
0
        self.memory_limit = limit;
143
0
    }
144
145
    /// Configure if frames must be within the screen descriptor.
146
    ///
147
    /// The default is `false`.
148
    ///
149
    /// When turned on, all frame descriptors being read must fit within the screen descriptor or
150
    /// otherwise an error is returned and the stream left in an unspecified state.
151
    ///
152
    /// When turned off, frames may be arbitrarily larger or offset in relation to the screen. Many
153
    /// other decoder libraries handle this in highly divergent ways. This moves all checks to the
154
    /// caller, for example to emulate a specific style.
155
0
    pub fn check_frame_consistency(&mut self, check: bool) {
156
0
        self.check_frame_consistency = check;
157
0
    }
158
159
    /// Configure whether to skip decoding frames.
160
    ///
161
    /// The default is false.
162
    ///
163
    /// When turned on, LZW decoding is skipped. [`Decoder::read_next_frame`] will return
164
    /// compressed LZW bytes in frame's data.
165
    /// [`Decoder::next_frame_info`] will return the metadata of the next frame as usual.
166
    /// This is useful to count frames without incurring the overhead of decoding.
167
0
    pub fn skip_frame_decoding(&mut self, skip: bool) {
168
0
        self.skip_frame_decoding = skip;
169
0
    }
170
171
    /// Configure if LZW encoded blocks must end with a marker end code.
172
    ///
173
    /// The default is `false`.
174
    ///
175
    /// When turned on, all image data blocks—which are LZW encoded—must contain a special bit
176
    /// sequence signalling the end of the data. LZW processing terminates when this code is
177
    /// encountered. The specification states that it must be the last code output by the encoder
178
    /// for an image.
179
    ///
180
    /// When turned off then image data blocks can simply end. Note that this might silently ignore
181
    /// some bits of the last or second to last byte.
182
0
    pub fn check_lzw_end_code(&mut self, check: bool) {
183
0
        self.check_for_end_code = check;
184
0
    }
185
186
    /// Configure if unknown blocks are allowed to be decoded.
187
    ///
188
    /// The default is `false`.
189
    ///
190
    /// When turned on, the decoder will allow unknown blocks to be in the
191
    /// `BlockStart` position.
192
    ///
193
    /// When turned off, decoded block starts must mark an `Image`, `Extension`,
194
    /// or `Trailer` block. Otherwise, the decoded image will return an error.
195
    /// If an unknown block error is returned from decoding, enabling this
196
    /// setting may allow for a further state of decoding on the next attempt.
197
    ///
198
    /// This option also allows unknown extension blocks. The decoder assumes the follow the same
199
    /// block layout, i.e. a sequence of zero-length terminated sub-blocks immediately follow the
200
    /// extension introducer.
201
0
    pub fn allow_unknown_blocks(&mut self, check: bool) {
202
0
        self.allow_unknown_blocks = check;
203
0
    }
204
205
    /// Reads the logical screen descriptor including the global color palette
206
    ///
207
    /// Returns a [`Decoder`]. All decoder configuration has to be done beforehand.
208
3.17k
    pub fn read_info<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> {
209
3.17k
        Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init()
210
3.17k
    }
<gif::reader::DecodeOptions>::read_info::<std::io::cursor::Cursor<&[u8]>>
Line
Count
Source
208
3.17k
    pub fn read_info<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> {
209
3.17k
        Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init()
210
3.17k
    }
Unexecuted instantiation: <gif::reader::DecodeOptions>::read_info::<_>
211
}
212
213
struct ReadDecoder<R: Read> {
214
    reader: io::BufReader<R>,
215
    decoder: StreamingDecoder,
216
    at_eof: bool,
217
}
218
219
impl<R: Read> ReadDecoder<R> {
220
    #[inline(never)]
221
1.63M
    fn decode_next(
222
1.63M
        &mut self,
223
1.63M
        write_into: &mut OutputBuffer<'_>,
224
1.63M
    ) -> Result<Option<Decoded>, DecodingError> {
225
1.63M
        while !self.at_eof {
226
1.63M
            let (consumed, result) = {
227
1.63M
                let buf = self.reader.fill_buf()?;
228
1.63M
                if buf.is_empty() {
229
2.25k
                    return Err(DecodingError::UnexpectedEof);
230
1.63M
                }
231
232
1.63M
                self.decoder.update(buf, write_into)?
233
            };
234
1.63M
            self.reader.consume(consumed);
235
38.0k
            match result {
236
3.78k
                Decoded::Nothing => (),
237
6
                Decoded::BlockStart(Block::Trailer) => {
238
6
                    self.at_eof = true;
239
6
                }
240
1.63M
                result => return Ok(Some(result)),
241
            }
242
        }
243
6
        Ok(None)
244
1.63M
    }
<gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next
Line
Count
Source
221
1.63M
    fn decode_next(
222
1.63M
        &mut self,
223
1.63M
        write_into: &mut OutputBuffer<'_>,
224
1.63M
    ) -> Result<Option<Decoded>, DecodingError> {
225
1.63M
        while !self.at_eof {
226
1.63M
            let (consumed, result) = {
227
1.63M
                let buf = self.reader.fill_buf()?;
228
1.63M
                if buf.is_empty() {
229
2.25k
                    return Err(DecodingError::UnexpectedEof);
230
1.63M
                }
231
232
1.63M
                self.decoder.update(buf, write_into)?
233
            };
234
1.63M
            self.reader.consume(consumed);
235
38.0k
            match result {
236
3.78k
                Decoded::Nothing => (),
237
6
                Decoded::BlockStart(Block::Trailer) => {
238
6
                    self.at_eof = true;
239
6
                }
240
1.63M
                result => return Ok(Some(result)),
241
            }
242
        }
243
6
        Ok(None)
244
1.63M
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<_>>::decode_next
245
246
0
    fn into_inner(self) -> io::BufReader<R> {
247
0
        self.reader
248
0
    }
249
250
465k
    fn decode_next_bytes(&mut self, out: &mut OutputBuffer<'_>) -> Result<usize, DecodingError> {
251
465k
        match self.decode_next(out)? {
252
463k
            Some(Decoded::BytesDecoded(len)) => Ok(len.get()),
253
126
            Some(Decoded::DataEnd) => Ok(0),
254
0
            _ => Err(DecodingError::format("unexpected data")),
255
        }
256
465k
    }
<gif::reader::ReadDecoder<std::io::cursor::Cursor<&[u8]>>>::decode_next_bytes
Line
Count
Source
250
465k
    fn decode_next_bytes(&mut self, out: &mut OutputBuffer<'_>) -> Result<usize, DecodingError> {
251
465k
        match self.decode_next(out)? {
252
463k
            Some(Decoded::BytesDecoded(len)) => Ok(len.get()),
253
126
            Some(Decoded::DataEnd) => Ok(0),
254
0
            _ => Err(DecodingError::format("unexpected data")),
255
        }
256
465k
    }
Unexecuted instantiation: <gif::reader::ReadDecoder<_>>::decode_next_bytes
257
}
258
/// Headers for supported extensions.
259
const EXT_NAME_NETSCAPE: &[u8] = b"NETSCAPE2.0";
260
const EXT_NAME_XMP: &[u8] = b"XMP DataXMP";
261
const EXT_NAME_ICC: &[u8] = b"ICCRGBG1012";
262
263
/// State when parsing application extension
264
enum AppExtensionState {
265
    /// Waiting for app name
266
    None,
267
    Netscape,
268
    Xmp,
269
    Icc,
270
    Skip,
271
}
272
273
#[allow(dead_code)]
274
/// GIF decoder. Create [`DecodeOptions`] to get started, and call [`DecodeOptions::read_info`].
275
pub struct Decoder<R: Read> {
276
    decoder: ReadDecoder<R>,
277
    pixel_converter: PixelConverter,
278
    memory_limit: MemoryLimit,
279
    bg_color: Option<u8>,
280
    repeat: Repeat,
281
    current_frame: Frame<'static>,
282
    current_frame_data_type: FrameDataType,
283
    app_extension_state: AppExtensionState,
284
    /// XMP metadata bytes.
285
    xmp_metadata: Option<Vec<u8>>,
286
    /// ICC profile bytes.
287
    icc_profile: Option<Vec<u8>>,
288
}
289
290
impl<R> Decoder<R>
291
where
292
    R: Read,
293
{
294
    /// Create a new decoder with default options.
295
    #[inline]
296
0
    pub fn new(reader: R) -> Result<Self, DecodingError> {
297
0
        DecodeOptions::new().read_info(reader)
298
0
    }
299
300
    /// Return a builder that allows configuring limits etc.
301
    #[must_use]
302
    #[inline]
303
0
    pub fn build() -> DecodeOptions {
304
0
        DecodeOptions::new()
305
0
    }
306
307
3.17k
    fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Self {
308
3.17k
        Self {
309
3.17k
            decoder: ReadDecoder {
310
3.17k
                reader: io::BufReader::new(reader),
311
3.17k
                decoder,
312
3.17k
                at_eof: false,
313
3.17k
            },
314
3.17k
            bg_color: None,
315
3.17k
            pixel_converter: PixelConverter::new(options.color_output),
316
3.17k
            memory_limit: options.memory_limit.clone(),
317
3.17k
            repeat: Repeat::default(),
318
3.17k
            current_frame: Frame::default(),
319
3.17k
            current_frame_data_type: FrameDataType::Pixels,
320
3.17k
            app_extension_state: AppExtensionState::None,
321
3.17k
            xmp_metadata: None,
322
3.17k
            icc_profile: None,
323
3.17k
        }
324
3.17k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_no_init
Line
Count
Source
307
3.17k
    fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Self {
308
3.17k
        Self {
309
3.17k
            decoder: ReadDecoder {
310
3.17k
                reader: io::BufReader::new(reader),
311
3.17k
                decoder,
312
3.17k
                at_eof: false,
313
3.17k
            },
314
3.17k
            bg_color: None,
315
3.17k
            pixel_converter: PixelConverter::new(options.color_output),
316
3.17k
            memory_limit: options.memory_limit.clone(),
317
3.17k
            repeat: Repeat::default(),
318
3.17k
            current_frame: Frame::default(),
319
3.17k
            current_frame_data_type: FrameDataType::Pixels,
320
3.17k
            app_extension_state: AppExtensionState::None,
321
3.17k
            xmp_metadata: None,
322
3.17k
            icc_profile: None,
323
3.17k
        }
324
3.17k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::with_no_init
325
326
3.17k
    fn init(mut self) -> Result<Self, DecodingError> {
327
        const APP_EXTENSION: AnyExtension = AnyExtension(Extension::Application as u8);
328
        loop {
329
1.16M
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
330
3.08k
                Some(Decoded::BackgroundColor(bg_color)) => {
331
3.08k
                    self.bg_color = Some(bg_color);
332
3.08k
                }
333
3.06k
                Some(Decoded::GlobalPalette(palette)) => {
334
3.06k
                    self.pixel_converter.set_global_palette(palette.into());
335
3.06k
                }
336
                Some(Decoded::SubBlock {
337
                    ext: APP_EXTENSION,
338
1.10M
                    is_last,
339
                }) => {
340
1.10M
                    self.read_application_extension(is_last)?;
341
                }
342
1.98k
                Some(Decoded::HeaderEnd) => break,
343
                Some(_) => {
344
                    // There will be extra events when parsing application extension
345
49.0k
                    continue;
346
                }
347
                None => {
348
0
                    return Err(DecodingError::format(
349
0
                        "file does not contain any image data",
350
0
                    ))
351
                }
352
            }
353
        }
354
        // If the background color is invalid, ignore it
355
1.98k
        if let Some(palette) = self.pixel_converter.global_palette() {
356
1.48k
            if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) {
357
956
                self.bg_color = None;
358
956
            }
359
507
        }
360
1.98k
        Ok(self)
361
3.17k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::init
Line
Count
Source
326
3.17k
    fn init(mut self) -> Result<Self, DecodingError> {
327
        const APP_EXTENSION: AnyExtension = AnyExtension(Extension::Application as u8);
328
        loop {
329
1.16M
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
330
3.08k
                Some(Decoded::BackgroundColor(bg_color)) => {
331
3.08k
                    self.bg_color = Some(bg_color);
332
3.08k
                }
333
3.06k
                Some(Decoded::GlobalPalette(palette)) => {
334
3.06k
                    self.pixel_converter.set_global_palette(palette.into());
335
3.06k
                }
336
                Some(Decoded::SubBlock {
337
                    ext: APP_EXTENSION,
338
1.10M
                    is_last,
339
                }) => {
340
1.10M
                    self.read_application_extension(is_last)?;
341
                }
342
1.98k
                Some(Decoded::HeaderEnd) => break,
343
                Some(_) => {
344
                    // There will be extra events when parsing application extension
345
49.0k
                    continue;
346
                }
347
                None => {
348
0
                    return Err(DecodingError::format(
349
0
                        "file does not contain any image data",
350
0
                    ))
351
                }
352
            }
353
        }
354
        // If the background color is invalid, ignore it
355
1.98k
        if let Some(palette) = self.pixel_converter.global_palette() {
356
1.48k
            if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) {
357
956
                self.bg_color = None;
358
956
            }
359
507
        }
360
1.98k
        Ok(self)
361
3.17k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::init
362
363
1.10M
    fn read_application_extension(&mut self, is_last: bool) -> Result<(), DecodingError> {
364
1.10M
        let data = self.decoder.decoder.last_ext_sub_block();
365
1.10M
        match self.app_extension_state {
366
            AppExtensionState::None => {
367
                // GIF spec requires len == 11
368
34.1k
                self.app_extension_state = match data {
369
34.1k
                    EXT_NAME_NETSCAPE => AppExtensionState::Netscape,
370
                    EXT_NAME_XMP => {
371
3.20k
                        self.xmp_metadata = Some(Vec::new());
372
3.20k
                        AppExtensionState::Xmp
373
                    }
374
                    EXT_NAME_ICC => {
375
2.34k
                        self.icc_profile = Some(Vec::new());
376
2.34k
                        AppExtensionState::Icc
377
                    }
378
26.6k
                    _ => AppExtensionState::Skip,
379
                }
380
            }
381
            AppExtensionState::Netscape => {
382
1.95k
                if let [1, rest @ ..] = data {
383
1.51k
                    if let Ok(repeat) = rest.try_into().map(u16::from_le_bytes) {
384
1.30k
                        self.repeat = if repeat == 0 {
385
966
                            Repeat::Infinite
386
                        } else {
387
342
                            Repeat::Finite(repeat)
388
                        };
389
208
                    }
390
443
                }
391
1.95k
                self.app_extension_state = AppExtensionState::Skip;
392
            }
393
            AppExtensionState::Xmp => {
394
502k
                if let Some(xmp_metadata) = &mut self.xmp_metadata {
395
                    // XMP is not written as a valid "pascal-string", so we need to stitch together
396
                    // the text from our collected sublock-lengths.
397
502k
                    self.memory_limit
398
502k
                        .try_reserve(xmp_metadata, 1 + data.len())?;
399
502k
                    xmp_metadata.push(data.len() as u8);
400
502k
                    xmp_metadata.extend_from_slice(data);
401
502k
                    if is_last {
402
                        // XMP adds a "ramp" of 257 bytes to the end of the metadata to let the "pascal-strings"
403
                        // parser converge to the null byte. The ramp looks like "0x01, 0xff, .., 0x01, 0x00".
404
                        // For convenience and to allow consumers to not be bothered with this implementation detail,
405
                        // we cut the ramp.
406
                        const RAMP_SIZE: usize = 257;
407
2.89k
                        if xmp_metadata.len() >= RAMP_SIZE
408
969
                            && xmp_metadata.ends_with(&[0x03, 0x02, 0x01, 0x00])
409
387
                            && xmp_metadata[xmp_metadata.len() - RAMP_SIZE..]
410
387
                                .starts_with(&[0x01, 0x0ff])
411
68
                        {
412
68
                            xmp_metadata.truncate(xmp_metadata.len() - RAMP_SIZE);
413
2.82k
                        }
414
500k
                    }
415
0
                }
416
            }
417
            AppExtensionState::Icc => {
418
322k
                if let Some(icc) = &mut self.icc_profile {
419
322k
                    self.memory_limit.try_reserve(icc, data.len())?;
420
322k
                    icc.extend_from_slice(data);
421
0
                }
422
            }
423
245k
            AppExtensionState::Skip => {}
424
        };
425
1.10M
        if is_last {
426
33.3k
            self.app_extension_state = AppExtensionState::None;
427
1.07M
        }
428
1.10M
        Ok(())
429
1.10M
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_application_extension
Line
Count
Source
363
1.10M
    fn read_application_extension(&mut self, is_last: bool) -> Result<(), DecodingError> {
364
1.10M
        let data = self.decoder.decoder.last_ext_sub_block();
365
1.10M
        match self.app_extension_state {
366
            AppExtensionState::None => {
367
                // GIF spec requires len == 11
368
34.1k
                self.app_extension_state = match data {
369
34.1k
                    EXT_NAME_NETSCAPE => AppExtensionState::Netscape,
370
                    EXT_NAME_XMP => {
371
3.20k
                        self.xmp_metadata = Some(Vec::new());
372
3.20k
                        AppExtensionState::Xmp
373
                    }
374
                    EXT_NAME_ICC => {
375
2.34k
                        self.icc_profile = Some(Vec::new());
376
2.34k
                        AppExtensionState::Icc
377
                    }
378
26.6k
                    _ => AppExtensionState::Skip,
379
                }
380
            }
381
            AppExtensionState::Netscape => {
382
1.95k
                if let [1, rest @ ..] = data {
383
1.51k
                    if let Ok(repeat) = rest.try_into().map(u16::from_le_bytes) {
384
1.30k
                        self.repeat = if repeat == 0 {
385
966
                            Repeat::Infinite
386
                        } else {
387
342
                            Repeat::Finite(repeat)
388
                        };
389
208
                    }
390
443
                }
391
1.95k
                self.app_extension_state = AppExtensionState::Skip;
392
            }
393
            AppExtensionState::Xmp => {
394
502k
                if let Some(xmp_metadata) = &mut self.xmp_metadata {
395
                    // XMP is not written as a valid "pascal-string", so we need to stitch together
396
                    // the text from our collected sublock-lengths.
397
502k
                    self.memory_limit
398
502k
                        .try_reserve(xmp_metadata, 1 + data.len())?;
399
502k
                    xmp_metadata.push(data.len() as u8);
400
502k
                    xmp_metadata.extend_from_slice(data);
401
502k
                    if is_last {
402
                        // XMP adds a "ramp" of 257 bytes to the end of the metadata to let the "pascal-strings"
403
                        // parser converge to the null byte. The ramp looks like "0x01, 0xff, .., 0x01, 0x00".
404
                        // For convenience and to allow consumers to not be bothered with this implementation detail,
405
                        // we cut the ramp.
406
                        const RAMP_SIZE: usize = 257;
407
2.89k
                        if xmp_metadata.len() >= RAMP_SIZE
408
969
                            && xmp_metadata.ends_with(&[0x03, 0x02, 0x01, 0x00])
409
387
                            && xmp_metadata[xmp_metadata.len() - RAMP_SIZE..]
410
387
                                .starts_with(&[0x01, 0x0ff])
411
68
                        {
412
68
                            xmp_metadata.truncate(xmp_metadata.len() - RAMP_SIZE);
413
2.82k
                        }
414
500k
                    }
415
0
                }
416
            }
417
            AppExtensionState::Icc => {
418
322k
                if let Some(icc) = &mut self.icc_profile {
419
322k
                    self.memory_limit.try_reserve(icc, data.len())?;
420
322k
                    icc.extend_from_slice(data);
421
0
                }
422
            }
423
245k
            AppExtensionState::Skip => {}
424
        };
425
1.10M
        if is_last {
426
33.3k
            self.app_extension_state = AppExtensionState::None;
427
1.07M
        }
428
1.10M
        Ok(())
429
1.10M
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::read_application_extension
430
431
    /// Returns the next frame info
432
1.97k
    pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
433
        loop {
434
3.68k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
435
1.64k
                Some(Decoded::FrameMetadata(frame_data_type)) => {
436
1.64k
                    self.current_frame = self.decoder.decoder.current_frame_mut().take();
437
1.64k
                    self.current_frame_data_type = frame_data_type;
438
1.64k
                    if self.current_frame.palette.is_none() && self.global_palette().is_none() {
439
8
                        return Err(DecodingError::format(
440
8
                            "no color table available for current frame",
441
8
                        ));
442
1.63k
                    }
443
1.63k
                    break;
444
                }
445
1.70k
                Some(_) => (),
446
6
                None => return Ok(None),
447
            }
448
        }
449
1.63k
        Ok(Some(&self.current_frame))
450
1.97k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_frame_info
Line
Count
Source
432
1.97k
    pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
433
        loop {
434
3.68k
            match self.decoder.decode_next(&mut OutputBuffer::None)? {
435
1.64k
                Some(Decoded::FrameMetadata(frame_data_type)) => {
436
1.64k
                    self.current_frame = self.decoder.decoder.current_frame_mut().take();
437
1.64k
                    self.current_frame_data_type = frame_data_type;
438
1.64k
                    if self.current_frame.palette.is_none() && self.global_palette().is_none() {
439
8
                        return Err(DecodingError::format(
440
8
                            "no color table available for current frame",
441
8
                        ));
442
1.63k
                    }
443
1.63k
                    break;
444
                }
445
1.70k
                Some(_) => (),
446
6
                None => return Ok(None),
447
            }
448
        }
449
1.63k
        Ok(Some(&self.current_frame))
450
1.97k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::next_frame_info
451
452
    /// Query information about the frame previously advanced with [`Self::next_frame_info`].
453
    ///
454
    /// Returns `None` past the end of file.
455
0
    pub fn current_frame_info(&self) -> Option<&Frame<'static>> {
456
0
        if self.decoder.at_eof {
457
0
            None
458
        } else {
459
0
            Some(&self.current_frame)
460
        }
461
0
    }
462
463
    /// Reads the next frame from the image.
464
    ///
465
    /// Do not call `Self::next_frame_info` beforehand.
466
    /// Deinterlaces the result.
467
    ///
468
    /// You can also call `.into_iter()` on the decoder to use it as a regular iterator.
469
0
    pub fn read_next_frame(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
470
0
        if self.next_frame_info()?.is_some() {
471
0
            match self.current_frame_data_type {
472
                FrameDataType::Pixels => {
473
0
                    self.pixel_converter.read_frame(
474
0
                        &mut self.current_frame,
475
0
                        &mut |out| self.decoder.decode_next_bytes(out),
476
0
                        &self.memory_limit,
477
0
                    )?;
478
                }
479
0
                FrameDataType::Lzw { min_code_size } => {
480
0
                    let mut vec = if matches!(self.current_frame.buffer, Cow::Owned(_)) {
481
0
                        let mut vec =
482
0
                            mem::replace(&mut self.current_frame.buffer, Cow::Borrowed(&[]))
483
0
                                .into_owned();
484
0
                        vec.clear();
485
0
                        vec
486
                    } else {
487
0
                        Vec::new()
488
                    };
489
                    // Guesstimate 2bpp
490
0
                    vec.try_reserve(
491
0
                        usize::from(self.current_frame.width)
492
0
                            * usize::from(self.current_frame.height)
493
0
                            / 4,
494
                    )
495
0
                    .map_err(|_| DecodingError::OutOfMemory)?;
496
0
                    self.copy_lzw_into_buffer(min_code_size, &mut vec)?;
497
0
                    self.current_frame.buffer = Cow::Owned(vec);
498
                }
499
            }
500
0
            Ok(Some(&self.current_frame))
501
        } else {
502
0
            Ok(None)
503
        }
504
0
    }
505
506
    /// This is private for iterator's use
507
0
    fn take_current_frame(&mut self) -> Option<Frame<'static>> {
508
0
        if self.current_frame.buffer.is_empty() {
509
0
            return None;
510
0
        }
511
0
        Some(self.current_frame.take())
512
0
    }
513
514
    /// Reads the data of the current frame into a pre-allocated buffer.
515
    ///
516
    /// `Self::next_frame_info` needs to be called beforehand.
517
    /// The length of `buf` must be at least `Self::buffer_size`.
518
    /// Deinterlaces the result.
519
1.62k
    pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> {
520
1.62k
        self.pixel_converter
521
465k
            .read_into_buffer(&self.current_frame, buf, &mut |out| {
522
465k
                self.decoder.decode_next_bytes(out)
523
465k
            })
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer::{closure#0}
Line
Count
Source
521
465k
            .read_into_buffer(&self.current_frame, buf, &mut |out| {
522
465k
                self.decoder.decode_next_bytes(out)
523
465k
            })
Unexecuted instantiation: <gif::reader::Decoder<_>>::read_into_buffer::{closure#0}
524
1.62k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_into_buffer
Line
Count
Source
519
1.62k
    pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> {
520
1.62k
        self.pixel_converter
521
1.62k
            .read_into_buffer(&self.current_frame, buf, &mut |out| {
522
                self.decoder.decode_next_bytes(out)
523
            })
524
1.62k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::read_into_buffer
525
526
0
    fn copy_lzw_into_buffer(
527
0
        &mut self,
528
0
        min_code_size: u8,
529
0
        buf: &mut Vec<u8>,
530
0
    ) -> Result<(), DecodingError> {
531
        // `write_lzw_pre_encoded_frame` smuggles `min_code_size` in the first byte.
532
0
        buf.push(min_code_size);
533
        loop {
534
0
            match self.decoder.decode_next(&mut OutputBuffer::Vec(buf))? {
535
0
                Some(Decoded::LzwDataCopied(_len)) => {}
536
0
                Some(Decoded::DataEnd) => return Ok(()),
537
0
                _ => return Err(DecodingError::format("unexpected data")),
538
            }
539
        }
540
0
    }
541
542
    /// Reads data of the current frame into a pre-allocated buffer until the buffer has been
543
    /// filled completely.
544
    ///
545
    /// The buffer length must be an even number of pixels (multiple of 4 if decoding RGBA).
546
    ///
547
    /// `Self::next_frame_info` needs to be called beforehand. Returns `true` if the supplied
548
    /// buffer could be filled completely. Should not be called after `false` had been returned.
549
0
    pub fn fill_buffer(&mut self, buf: &mut [u8]) -> Result<bool, DecodingError> {
550
0
        self.pixel_converter
551
0
            .fill_buffer(&self.current_frame, buf, &mut |out| {
552
0
                self.decoder.decode_next_bytes(out)
553
0
            })
554
0
    }
555
556
    /// Output buffer size
557
0
    pub fn buffer_size(&self) -> usize {
558
0
        self.pixel_converter
559
0
            .buffer_size(&self.current_frame)
560
0
            .unwrap()
561
0
    }
562
563
    /// Line length of the current frame
564
0
    pub fn line_length(&self) -> usize {
565
0
        self.pixel_converter.line_length(&self.current_frame)
566
0
    }
567
568
    /// Returns the color palette relevant for the frame that has been decoded
569
    #[inline]
570
0
    pub fn palette(&self) -> Result<&[u8], DecodingError> {
571
0
        Ok(match self.current_frame.palette {
572
0
            Some(ref table) => table,
573
0
            None => self.global_palette().ok_or_else(|| {
574
0
                DecodingError::format("no color table available for current frame")
575
0
            })?,
576
        })
577
0
    }
578
579
    /// The global color palette
580
1.40k
    pub fn global_palette(&self) -> Option<&[u8]> {
581
1.40k
        self.pixel_converter.global_palette()
582
1.40k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::global_palette
Line
Count
Source
580
1.40k
    pub fn global_palette(&self) -> Option<&[u8]> {
581
1.40k
        self.pixel_converter.global_palette()
582
1.40k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::global_palette
583
584
    /// Width of the image
585
    #[inline]
586
11.5k
    pub fn width(&self) -> u16 {
587
11.5k
        self.decoder.decoder.width()
588
11.5k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::width
Line
Count
Source
586
11.5k
    pub fn width(&self) -> u16 {
587
11.5k
        self.decoder.decoder.width()
588
11.5k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::width
589
590
    /// Height of the image
591
    #[inline]
592
11.5k
    pub fn height(&self) -> u16 {
593
11.5k
        self.decoder.decoder.height()
594
11.5k
    }
<gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::height
Line
Count
Source
592
11.5k
    pub fn height(&self) -> u16 {
593
11.5k
        self.decoder.decoder.height()
594
11.5k
    }
Unexecuted instantiation: <gif::reader::Decoder<_>>::height
595
596
    /// XMP metadata stored in the image.
597
    #[inline]
598
    #[must_use]
599
0
    pub fn xmp_metadata(&self) -> Option<&[u8]> {
600
0
        self.xmp_metadata.as_deref()
601
0
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::xmp_metadata
Unexecuted instantiation: <gif::reader::Decoder<_>>::xmp_metadata
602
603
    /// ICC profile stored in the image.
604
    #[inline]
605
    #[must_use]
606
0
    pub fn icc_profile(&self) -> Option<&[u8]> {
607
0
        self.icc_profile.as_deref()
608
0
    }
Unexecuted instantiation: <gif::reader::Decoder<std::io::cursor::Cursor<&[u8]>>>::icc_profile
Unexecuted instantiation: <gif::reader::Decoder<_>>::icc_profile
609
610
    /// Abort decoding and recover the `io::Read` instance
611
0
    pub fn into_inner(self) -> io::BufReader<R> {
612
0
        self.decoder.into_inner()
613
0
    }
614
615
    /// Index of the background color in the global palette
616
    ///
617
    /// In practice this is not used, and the background is
618
    /// always transparent
619
0
    pub fn bg_color(&self) -> Option<usize> {
620
0
        self.bg_color.map(|v| v as usize)
621
0
    }
622
623
    /// Number of loop repetitions
624
    #[inline]
625
0
    pub fn repeat(&self) -> Repeat {
626
0
        self.repeat
627
0
    }
628
}
629
630
impl<R: Read> IntoIterator for Decoder<R> {
631
    type Item = Result<Frame<'static>, DecodingError>;
632
    type IntoIter = DecoderIter<R>;
633
634
    #[inline]
635
0
    fn into_iter(self) -> Self::IntoIter {
636
0
        DecoderIter {
637
0
            inner: self,
638
0
            ended: false,
639
0
        }
640
0
    }
641
}
642
643
/// Use `decoder.into_iter()` to iterate over the frames
644
pub struct DecoderIter<R: Read> {
645
    inner: Decoder<R>,
646
    ended: bool,
647
}
648
649
impl<R: Read> DecoderIter<R> {
650
    /// Abort decoding and recover the `io::Read` instance
651
    ///
652
    /// Use `for frame in iter.by_ref()` to be able to call this afterwards.
653
0
    pub fn into_inner(self) -> io::BufReader<R> {
654
0
        self.inner.into_inner()
655
0
    }
656
}
657
658
impl<R: Read> FusedIterator for DecoderIter<R> {}
659
660
impl<R: Read> Iterator for DecoderIter<R> {
661
    type Item = Result<Frame<'static>, DecodingError>;
662
663
0
    fn next(&mut self) -> Option<Self::Item> {
664
0
        if !self.ended {
665
0
            match self.inner.read_next_frame() {
666
0
                Ok(Some(_)) => self.inner.take_current_frame().map(Ok),
667
                Ok(None) => {
668
0
                    self.ended = true;
669
0
                    None
670
                }
671
0
                Err(err) => {
672
0
                    self.ended = true;
673
0
                    Some(Err(err))
674
                }
675
            }
676
        } else {
677
0
            None
678
        }
679
0
    }
680
}