Coverage Report

Created: 2025-07-18 06:49

/rust/registry/src/index.crates.io-6f17d22bba15001f/gif-0.13.3/src/reader/decoder.rs
Line
Count
Source (jump to first uncovered line)
1
use std::borrow::Cow;
2
use std::cmp;
3
use std::default::Default;
4
use std::error;
5
use std::fmt;
6
use std::io;
7
use std::mem;
8
use std::num::NonZeroUsize;
9
10
use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
11
use crate::reader::DecodeOptions;
12
use crate::MemoryLimit;
13
use crate::Repeat;
14
15
use weezl::{decode::Decoder as LzwDecoder, BitOrder, LzwError, LzwStatus};
16
17
/// GIF palettes are RGB
18
pub const PLTE_CHANNELS: usize = 3;
19
20
/// An error returned in the case of the image not being formatted properly.
21
#[derive(Debug)]
22
pub struct DecodingFormatError {
23
    underlying: Box<dyn error::Error + Send + Sync + 'static>,
24
}
25
26
impl fmt::Display for DecodingFormatError {
27
    #[cold]
28
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
29
0
        fmt::Display::fmt(&*self.underlying, fmt)
30
0
    }
31
}
32
33
impl error::Error for DecodingFormatError {
34
    #[cold]
35
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
36
0
        Some(&*self.underlying as _)
37
0
    }
38
}
39
40
#[derive(Debug)]
41
/// Decoding error.
42
pub enum DecodingError {
43
    /// Returned if the image is found to be malformed.
44
    Format(DecodingFormatError),
45
    /// Wraps `std::io::Error`.
46
    Io(io::Error),
47
}
48
49
impl DecodingError {
50
    #[cold]
51
303
    pub(crate) fn format(err: &'static str) -> Self {
52
303
        Self::Format(DecodingFormatError {
53
303
            underlying: err.into(),
54
303
        })
55
303
    }
56
}
57
58
impl fmt::Display for DecodingError {
59
    #[cold]
60
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61
0
        match *self {
62
0
            Self::Format(ref d) => d.fmt(fmt),
63
0
            Self::Io(ref err) => err.fmt(fmt),
64
        }
65
0
    }
66
}
67
68
impl error::Error for DecodingError {
69
    #[cold]
70
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
71
0
        match *self {
72
0
            Self::Format(ref err) => Some(err),
73
0
            Self::Io(ref err) => Some(err),
74
        }
75
0
    }
76
}
77
78
impl From<io::Error> for DecodingError {
79
    #[inline]
80
265
    fn from(err: io::Error) -> Self {
81
265
        Self::Io(err)
82
265
    }
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
<gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Line
Count
Source
80
265
    fn from(err: io::Error) -> Self {
81
265
        Self::Io(err)
82
265
    }
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from
83
}
84
85
impl From<io::ErrorKind> for DecodingError {
86
    #[cold]
87
1.39k
    fn from(err: io::ErrorKind) -> Self {
88
1.39k
        Self::Io(io::Error::from(err))
89
1.39k
    }
90
}
91
92
impl From<DecodingFormatError> for DecodingError {
93
    #[inline]
94
0
    fn from(err: DecodingFormatError) -> Self {
95
0
        Self::Format(err)
96
0
    }
97
}
98
99
/// Varies depending on `skip_frame_decoding`
100
#[derive(Debug, Copy, Clone)]
101
pub enum FrameDataType {
102
    /// `Frame.buffer` will be regular pixel data
103
    Pixels,
104
    /// Raw LZW data
105
    Lzw {
106
        /// Needed for decoding
107
        min_code_size: u8,
108
    },
109
}
110
111
/// Indicates whether a certain object has been decoded
112
#[derive(Debug)]
113
#[non_exhaustive]
114
pub enum Decoded {
115
    /// Decoded nothing.
116
    Nothing,
117
    /// Global palette.
118
    GlobalPalette(Box<[u8]>),
119
    /// Index of the background color in the global palette.
120
    BackgroundColor(u8),
121
    /// Loop count is known
122
    Repetitions(Repeat),
123
    /// Palette and optional `Application` extension have been parsed,
124
    /// reached frame data.
125
    HeaderEnd,
126
    /// The start of a block.
127
    /// `BlockStart(Block::Trailer)` is the very last decode event
128
    BlockStart(Block),
129
    /// Decoded a sub-block. More sub-block are available.
130
    ///
131
    /// Indicates the label of the extension which might be unknown. A label of `0` is used when
132
    /// the sub block does not belong to an extension.
133
    ///
134
    /// Call `last_ext()` to get the data
135
    SubBlockFinished(AnyExtension),
136
    /// Decoded the last (or only) sub-block of a block.
137
    ///
138
    /// Indicates the label of the extension which might be unknown. A label of `0` is used when
139
    /// the sub block does not belong to an extension.
140
    ///
141
    /// Call `last_ext()` to get the data
142
    BlockFinished(AnyExtension),
143
    /// Decoded all information of the next frame, except the image data.
144
    ///
145
    /// The returned frame does **not** contain any owned image data.
146
    ///
147
    /// Call `current_frame_mut()` to access the frame info.
148
    FrameMetadata(FrameDataType),
149
    /// Decoded some data of the current frame. Size is in bytes, always > 0
150
    BytesDecoded(NonZeroUsize),
151
    /// Copied (or consumed and discarded) compressed data of the current frame. In bytes.
152
    LzwDataCopied(usize),
153
    /// No more data available the current frame.
154
    DataEnd,
155
}
156
157
/// Internal state of the GIF decoder
158
#[derive(Debug, Copy, Clone)]
159
enum State {
160
    Magic,
161
    ScreenDescriptor,
162
    ImageBlockStart,
163
    GlobalPalette(usize),
164
    BlockStart(u8),
165
    BlockEnd,
166
    ExtensionBlockStart,
167
    /// Collects data in ext.data
168
    ExtensionDataBlock(usize),
169
    ApplicationExtension,
170
    LocalPalette(usize),
171
    LzwInit(u8),
172
    /// Decompresses LZW
173
    DecodeSubBlock(usize),
174
    /// Keeps LZW compressed
175
    CopySubBlock(usize),
176
    FrameDecoded,
177
    Trailer,
178
}
179
use self::State::*;
180
181
use super::converter::PixelConverter;
182
183
/// Decoder for `Frame::make_lzw_pre_encoded`
184
pub struct FrameDecoder {
185
    lzw_reader: LzwReader,
186
    pixel_converter: PixelConverter,
187
}
188
189
impl FrameDecoder {
190
    /// See also `set_global_palette`
191
    #[inline]
192
    #[must_use]
193
0
    pub fn new(options: DecodeOptions) -> Self {
194
0
        Self {
195
0
            lzw_reader: LzwReader::new(options.check_for_end_code),
196
0
            pixel_converter: PixelConverter::new(options.color_output, options.memory_limit),
197
0
        }
198
0
    }
199
200
    /// Palette used for RGBA conversion
201
    #[inline]
202
0
    pub fn set_global_palette(&mut self, palette: Vec<u8>) {
203
0
        self.pixel_converter.set_global_palette(palette);
204
0
    }
205
206
    /// Converts the frame in-place, replacing its LZW buffer with pixels.
207
    ///
208
    /// If you get an error about invalid min code size, the buffer was probably pixels, not compressed data.
209
    #[inline]
210
0
    pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> {
211
0
        let pixel_bytes = self.pixel_converter.check_buffer_size(frame)?;
212
0
        let mut vec = vec![0; pixel_bytes];
213
0
        self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?;
214
0
        frame.buffer = Cow::Owned(vec);
215
0
        frame.interlaced = false;
216
0
        Ok(())
217
0
    }
218
219
    /// Converts into the given buffer. It must be [`buffer_size()`] bytes large.
220
    ///
221
    /// Pixels are always deinterlaced, so update `frame.interlaced` afterwards if you're putting the buffer back into the frame.
222
0
    pub fn decode_lzw_encoded_frame_into_buffer(
223
0
        &mut self,
224
0
        frame: &Frame<'_>,
225
0
        buf: &mut [u8],
226
0
    ) -> Result<(), DecodingError> {
227
0
        let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[]));
228
0
        self.lzw_reader.reset(min_code_size)?;
229
0
        let lzw_reader = &mut self.lzw_reader;
230
0
        self.pixel_converter
231
0
            .read_into_buffer(frame, buf, &mut move |out| loop {
232
0
                let (bytes_read, bytes_written, status) = lzw_reader.decode_bytes(data, out)?;
233
0
                data = data.get(bytes_read..).unwrap_or_default();
234
0
                if bytes_written > 0 || matches!(status, LzwStatus::NoProgress) {
235
0
                    return Ok(bytes_written);
236
0
                }
237
0
            })?;
238
0
        Ok(())
239
0
    }
240
241
    /// Number of bytes required for `decode_lzw_encoded_frame_into_buffer`
242
    #[inline]
243
    #[must_use]
244
0
    pub fn buffer_size(&self, frame: &Frame<'_>) -> usize {
245
0
        self.pixel_converter.buffer_size(frame).unwrap()
246
0
    }
247
}
248
249
struct LzwReader {
250
    decoder: Option<LzwDecoder>,
251
    min_code_size: u8,
252
    check_for_end_code: bool,
253
}
254
255
impl LzwReader {
256
2.11k
    pub fn new(check_for_end_code: bool) -> Self {
257
2.11k
        Self {
258
2.11k
            decoder: None,
259
2.11k
            min_code_size: 0,
260
2.11k
            check_for_end_code,
261
2.11k
        }
262
2.11k
    }
263
264
1.59k
    pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> {
265
1.59k
        // LZW spec: max 12 bits per code. This check helps catch confusion
266
1.59k
        // between LZW-compressed buffers and raw pixel data
267
1.59k
        if min_code_size > 11 || min_code_size < 1 {
268
12
            return Err(DecodingError::format("invalid minimal code size"));
269
1.58k
        }
270
1.58k
        Ok(())
271
1.59k
    }
272
273
1.59k
    pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> {
274
1.59k
        Self::check_code_size(min_code_size)?;
275
276
        // The decoder can be reused if the code size stayed the same
277
1.58k
        if self.min_code_size != min_code_size || self.decoder.is_none() {
278
1.58k
            self.min_code_size = min_code_size;
279
1.58k
            self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size));
280
1.58k
        } else {
281
0
            self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state"))?.reset();
282
        }
283
284
1.58k
        Ok(())
285
1.59k
    }
286
287
469k
    pub fn has_ended(&self) -> bool {
288
469k
        self.decoder.as_ref().map_or(true, |e| e.has_ended())
289
469k
    }
290
291
461k
    pub fn decode_bytes(
292
461k
        &mut self,
293
461k
        lzw_data: &[u8],
294
461k
        decode_buffer: &mut OutputBuffer<'_>,
295
461k
    ) -> io::Result<(usize, usize, LzwStatus)> {
296
461k
        let decoder = self.decoder.as_mut().ok_or(io::ErrorKind::Unsupported)?;
297
298
461k
        let decode_buffer = match decode_buffer {
299
461k
            OutputBuffer::Slice(buf) => &mut **buf,
300
0
            OutputBuffer::None => &mut [],
301
0
            OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)),
302
        };
303
304
461k
        let decoded = decoder.decode_bytes(lzw_data, decode_buffer);
305
306
461k
        let status = match decoded.status {
307
460k
            Ok(ok @ LzwStatus::Done | ok @ LzwStatus::Ok) => ok,
308
584
            Ok(ok @ LzwStatus::NoProgress) => {
309
584
                if self.check_for_end_code {
310
0
                    return Err(io::Error::new(
311
0
                        io::ErrorKind::InvalidData,
312
0
                        "no end code in lzw stream",
313
0
                    ));
314
584
                }
315
584
316
584
                ok
317
            }
318
265
            Err(err @ LzwError::InvalidCode) => {
319
265
                return Err(io::Error::new(io::ErrorKind::InvalidData, err));
320
            }
321
        };
322
323
461k
        Ok((decoded.consumed_in, decoded.consumed_out, status))
324
461k
    }
325
}
326
327
/// GIF decoder which emits [low-level events](Decoded) for items in the GIF file
328
///
329
/// To just get GIF frames, use [`crate::Decoder`] instead.
330
pub struct StreamingDecoder {
331
    state: State,
332
    /// Input bytes are collected here if `update` got `buf` smaller than the minimum required
333
    internal_buffer: [u8; 9],
334
    unused_internal_buffer_len: u8,
335
    lzw_reader: LzwReader,
336
    skip_frame_decoding: bool,
337
    check_frame_consistency: bool,
338
    allow_unknown_blocks: bool,
339
    memory_limit: MemoryLimit,
340
    version: Version,
341
    width: u16,
342
    height: u16,
343
    global_color_table: Vec<u8>,
344
    /// ext buffer
345
    ext: ExtensionData,
346
    /// Frame data
347
    current: Option<Frame<'static>>,
348
    /// Needs to emit `HeaderEnd` once
349
    header_end_reached: bool,
350
}
351
352
/// One version number of the GIF standard.
353
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
354
pub enum Version {
355
    /// Version 87a, from May 1987.
356
    V87a,
357
    /// Version 89a, from July 1989.
358
    V89a,
359
}
360
361
struct ExtensionData {
362
    id: AnyExtension,
363
    data: Vec<u8>,
364
    is_block_end: bool,
365
}
366
367
/// Destination to write to for `StreamingDecoder::update`
368
pub enum OutputBuffer<'a> {
369
    /// Overwrite bytes
370
    Slice(&'a mut [u8]),
371
    /// Append LZW bytes
372
    Vec(&'a mut Vec<u8>),
373
    /// Discard bytes
374
    None,
375
}
376
377
impl OutputBuffer<'_> {
378
0
    fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> {
379
0
        let (consumed, copied) = match self {
380
0
            OutputBuffer::Slice(slice) => {
381
0
                let len = cmp::min(buf.len(), slice.len());
382
0
                slice[..len].copy_from_slice(&buf[..len]);
383
0
                (len, len)
384
            },
385
0
            OutputBuffer::Vec(vec) => {
386
0
                let vec: &mut Vec<u8> = vec;
387
0
                let len = buf.len();
388
0
                memory_limit.check_size(vec.len() + len)?;
389
0
                vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?;
390
0
                if vec.capacity() - vec.len() >= len {
391
0
                    vec.extend_from_slice(buf);
392
0
                }
393
0
                (len, len)
394
            },
395
            // It's valid that bytes are discarded. For example,
396
            // when using next_frame_info() with skip_frame_decoding to only get metadata.
397
0
            OutputBuffer::None => (buf.len(), 0),
398
        };
399
0
        Ok((consumed, copied))
400
0
    }
401
}
402
403
impl StreamingDecoder {
404
    /// Creates a new streaming decoder
405
    #[must_use]
406
0
    pub fn new() -> Self {
407
0
        let options = DecodeOptions::new();
408
0
        Self::with_options(&options)
409
0
    }
410
411
2.11k
    pub(crate) fn with_options(options: &DecodeOptions) -> Self {
412
2.11k
        Self {
413
2.11k
            internal_buffer: [0; 9],
414
2.11k
            unused_internal_buffer_len: 0,
415
2.11k
            state: Magic,
416
2.11k
            lzw_reader: LzwReader::new(options.check_for_end_code),
417
2.11k
            skip_frame_decoding: options.skip_frame_decoding,
418
2.11k
            check_frame_consistency: options.check_frame_consistency,
419
2.11k
            allow_unknown_blocks: options.allow_unknown_blocks,
420
2.11k
            memory_limit: options.memory_limit.clone(),
421
2.11k
            version: Version::V87a,
422
2.11k
            width: 0,
423
2.11k
            height: 0,
424
2.11k
            global_color_table: Vec::new(),
425
2.11k
            ext: ExtensionData {
426
2.11k
                id: AnyExtension(0),
427
2.11k
                data: Vec::with_capacity(256), // 0xFF + 1 byte length
428
2.11k
                is_block_end: true,
429
2.11k
            },
430
2.11k
            current: None,
431
2.11k
            header_end_reached: false,
432
2.11k
        }
433
2.11k
    }
434
435
    /// Updates the internal state of the decoder.
436
    ///
437
    /// Returns the number of bytes consumed from the input buffer
438
    /// and the last decoding result.
439
663k
    pub fn update(
440
663k
        &mut self,
441
663k
        mut buf: &[u8],
442
663k
        write_into: &mut OutputBuffer<'_>,
443
663k
    ) -> Result<(usize, Decoded), DecodingError> {
444
663k
        let len = buf.len();
445
1.29M
        while !buf.is_empty() {
446
1.28M
            let (bytes, decoded) = self.next_state(buf, write_into)?;
447
1.28M
            buf = buf.get(bytes..).unwrap_or_default();
448
1.28M
            match decoded {
449
626k
                Decoded::Nothing => {},
450
661k
                result => {
451
661k
                    return Ok((len-buf.len(), result));
452
                },
453
            };
454
        }
455
1.55k
        Ok((len - buf.len(), Decoded::Nothing))
456
663k
    }
457
458
    /// Returns the data of the last extension that has been decoded.
459
    #[must_use]
460
0
    pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) {
461
0
        (self.ext.id, &self.ext.data, self.ext.is_block_end)
462
0
    }
463
464
    /// Current frame info as a mutable ref.
465
    #[must_use]
466
    #[track_caller]
467
1.58k
    pub fn current_frame_mut(&mut self) -> &mut Frame<'static> {
468
1.58k
        self.current.as_mut().unwrap()
469
1.58k
    }
470
471
    /// Current frame info as a ref.
472
    #[track_caller]
473
    #[must_use]
474
0
    pub fn current_frame(&self) -> &Frame<'static> {
475
0
        self.current.as_ref().unwrap()
476
0
    }
477
478
    /// Current frame info as a mutable ref.
479
    #[inline(always)]
480
255
    fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> {
481
255
        self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))
482
255
    }
483
484
    /// Width of the image
485
    #[must_use]
486
10.1k
    pub fn width(&self) -> u16 {
487
10.1k
        self.width
488
10.1k
    }
489
490
    /// Height of the image
491
    #[must_use]
492
10.1k
    pub fn height(&self) -> u16 {
493
10.1k
        self.height
494
10.1k
    }
495
496
    /// The version number of the GIF standard used in this image.
497
    ///
498
    /// We suppose a minimum of `V87a` compatibility. This value will be reported until we have
499
    /// read the version information in the magic header bytes.
500
    #[must_use]
501
0
    pub fn version(&self) -> Version {
502
0
        self.version
503
0
    }
504
505
    #[inline]
506
1.28M
    fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded), DecodingError> {
507
        macro_rules! goto (
508
            ($n:expr, $state:expr) => ({
509
                self.state = $state;
510
                Ok(($n, Decoded::Nothing))
511
            });
512
            ($state:expr) => ({
513
                self.state = $state;
514
                Ok((1, Decoded::Nothing))
515
            });
516
            ($n:expr, $state:expr, emit $res:expr) => ({
517
                self.state = $state;
518
                Ok(($n, $res))
519
            });
520
            ($state:expr, emit $res:expr) => ({
521
                self.state = $state;
522
                Ok((1, $res))
523
            })
524
        );
525
526
        macro_rules! ensure_min_length_buffer (
527
            ($required:expr) => ({
528
                let required: usize = $required;
529
                if buf.len() >= required && self.unused_internal_buffer_len == 0 {
530
                    (required, &buf[..required])
531
                } else {
532
                    let has = usize::from(self.unused_internal_buffer_len);
533
                    let mut consumed = 0;
534
                    if has < required {
535
                        let to_copy = buf.len().min(required - has);
536
                        let new_len = has + to_copy;
537
                        self.internal_buffer[has .. new_len].copy_from_slice(&buf[..to_copy]);
538
                        consumed += to_copy;
539
                        if new_len < required {
540
                            self.unused_internal_buffer_len = new_len as u8;
541
                            return Ok((consumed, Decoded::Nothing));
542
                        } else {
543
                            self.unused_internal_buffer_len = 0;
544
                        }
545
                    }
546
                    (consumed, &self.internal_buffer[..required])
547
                }
548
            })
549
        );
550
551
1.28M
        let b = *buf.first().ok_or(io::ErrorKind::UnexpectedEof)?;
552
553
1.28M
        match self.state {
554
            Magic => {
555
2.11k
                let (consumed, version) = ensure_min_length_buffer!(6);
556
557
2.10k
                self.version = match version {
558
2.10k
                    b"GIF87a" => Version::V87a,
559
1.25k
                    b"GIF89a" => Version::V89a,
560
64
                    _ => return Err(DecodingError::format("malformed GIF header")),
561
                };
562
563
2.03k
                goto!(consumed, ScreenDescriptor)
564
            },
565
            ScreenDescriptor => {
566
2.03k
                let (consumed, desc) = ensure_min_length_buffer!(7);
567
568
2.03k
                self.width = u16::from_le_bytes(desc[..2].try_into().unwrap());
569
2.03k
                self.height = u16::from_le_bytes(desc[2..4].try_into().unwrap());
570
2.03k
                let global_flags = desc[4];
571
2.03k
                let background_color = desc[5];
572
2.03k
573
2.03k
                let global_table = global_flags & 0x80 != 0;
574
2.03k
                let table_size = if global_table {
575
1.45k
                    let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize);
576
1.45k
                    self.global_color_table.try_reserve_exact(table_size).map_err(|_| io::ErrorKind::OutOfMemory)?;
577
1.45k
                    table_size
578
                } else {
579
573
                    0usize
580
                };
581
582
2.03k
                goto!(
583
2.03k
                    consumed,
584
2.03k
                    GlobalPalette(table_size),
585
2.03k
                    emit Decoded::BackgroundColor(background_color)
586
2.03k
                )
587
            },
588
            ImageBlockStart => {
589
1.64k
                let (consumed, header) = ensure_min_length_buffer!(9);
590
591
1.63k
                let frame = self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))?;
592
1.63k
                frame.left = u16::from_le_bytes(header[..2].try_into().unwrap());
593
1.63k
                frame.top = u16::from_le_bytes(header[2..4].try_into().unwrap());
594
1.63k
                frame.width = u16::from_le_bytes(header[4..6].try_into().unwrap());
595
1.63k
                frame.height = u16::from_le_bytes(header[6..8].try_into().unwrap());
596
1.63k
597
1.63k
                let flags = header[8];
598
1.63k
                frame.interlaced = (flags & 0b0100_0000) != 0;
599
1.63k
600
1.63k
                if self.check_frame_consistency {
601
                    // Consistency checks.
602
0
                    if self.width.checked_sub(frame.width) < Some(frame.left)
603
0
                        || self.height.checked_sub(frame.height) < Some(frame.top)
604
                    {
605
0
                        return Err(DecodingError::format("frame descriptor is out-of-bounds"));
606
0
                    }
607
1.63k
                }
608
609
1.63k
                let local_table = (flags & 0b1000_0000) != 0;
610
1.63k
                if local_table {
611
256
                    let table_size = flags & 0b0000_0111;
612
256
                    let pal_len = PLTE_CHANNELS * (1 << (table_size + 1));
613
256
                    frame.palette.get_or_insert_with(Vec::new)
614
256
                        .try_reserve_exact(pal_len).map_err(|_| io::ErrorKind::OutOfMemory)?;
615
256
                    goto!(consumed, LocalPalette(pal_len))
616
                } else {
617
1.37k
                    goto!(consumed, LocalPalette(0))
618
                }
619
            },
620
3.45k
            GlobalPalette(left) => {
621
3.45k
                // the global_color_table is guaranteed to have the exact capacity required
622
3.45k
                if left > 0 {
623
1.44k
                    let n = cmp::min(left, buf.len());
624
1.44k
                    if n <= self.global_color_table.capacity() - self.global_color_table.len() {
625
1.44k
                        self.global_color_table.extend_from_slice(&buf[..n]);
626
1.44k
                    }
627
1.44k
                    goto!(n, GlobalPalette(left - n))
628
                } else {
629
2.00k
                    goto!(BlockStart(b), emit Decoded::GlobalPalette(
630
2.00k
                        mem::take(&mut self.global_color_table).into_boxed_slice()
631
2.00k
                    ))
632
                }
633
            }
634
8.32k
            BlockStart(type_) => {
635
8.32k
                if !self.header_end_reached && type_ != Block::Extension as u8 {
636
1.72k
                    self.header_end_reached = true;
637
1.72k
                    return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd);
638
6.59k
                }
639
6.59k
640
6.59k
                match Block::from_u8(type_) {
641
                    Some(Block::Image) => {
642
1.64k
                        self.add_frame();
643
1.64k
                        goto!(0, ImageBlockStart, emit Decoded::BlockStart(Block::Image))
644
                    }
645
                    Some(Block::Extension) => {
646
4.88k
                        self.ext.data.clear();
647
4.88k
                        self.ext.id = AnyExtension(b);
648
4.88k
                        if self.ext.id.into_known().is_none() {
649
5
                            if !self.allow_unknown_blocks {
650
5
                                return Err(DecodingError::format(
651
5
                                    "unknown extension block encountered",
652
5
                                ));
653
0
                            }
654
4.87k
                        }
655
4.87k
                        goto!(ExtensionBlockStart, emit Decoded::BlockStart(Block::Extension))
656
                    }
657
                    Some(Block::Trailer) => {
658
                        // The `Trailer` is the final state, and isn't reachable without extraneous data after the end of file
659
6
                        goto!(Trailer, emit Decoded::BlockStart(Block::Trailer))
660
                    }
661
                    None => {
662
66
                        if self.allow_unknown_blocks {
663
0
                            goto!(ExtensionDataBlock(b as usize))
664
                        } else {
665
66
                            Err(DecodingError::format("unknown block type encountered"))
666
                        }
667
                    }
668
                }
669
            },
670
            BlockEnd => {
671
4.61k
                if b == Block::Trailer as u8 {
672
                    // can't consume yet, because the trailer is not a real block,
673
                    // and won't have futher data for BlockStart
674
3
                    goto!(0, BlockStart(b))
675
                } else {
676
4.61k
                    goto!(BlockStart(b))
677
                }
678
            }
679
            ExtensionBlockStart => {
680
4.85k
                self.ext.data.push(b);
681
4.85k
                goto!(ExtensionDataBlock(b as usize))
682
            }
683
526k
            ExtensionDataBlock(left) => {
684
526k
                if left > 0 {
685
263k
                    let n = cmp::min(left, buf.len());
686
263k
                    self.memory_limit.check_size(self.ext.data.len() + n)?;
687
263k
                    self.ext.data.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
688
263k
                    self.ext.data.extend_from_slice(&buf[..n]);
689
263k
                    goto!(n, ExtensionDataBlock(left - n))
690
263k
                } else if b == 0 {
691
4.70k
                    self.ext.is_block_end = true;
692
4.70k
                    match self.ext.id.into_known() {
693
                        Some(Extension::Application) => {
694
2.23k
                            goto!(0, ApplicationExtension, emit Decoded::BlockFinished(self.ext.id))
695
                        }
696
                        Some(Extension::Control) => {
697
1.65k
                            self.read_control_extension()?;
698
1.63k
                            goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
699
                        },
700
                        _ => {
701
815
                            goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
702
                        }
703
                    }
704
                } else {
705
258k
                    self.ext.is_block_end = false;
706
258k
                    goto!(ExtensionDataBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id))
707
                }
708
            }
709
            ApplicationExtension => {
710
2.23k
                debug_assert_eq!(0, b);
711
                // the parser removes sub-block lenghts, so app name and data are concatenated
712
2.23k
                if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0\x01" {
713
776
                    let repeat = &self.ext.data[13..15];
714
776
                    let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8;
715
776
                    goto!(BlockEnd, emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) }))
716
                } else {
717
1.45k
                    goto!(BlockEnd)
718
                }
719
            }
720
1.85k
            LocalPalette(left) => {
721
1.85k
                if left > 0 {
722
255
                    let n = cmp::min(left, buf.len());
723
255
                    let src = &buf[..n];
724
255
                    if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
725
                        // capacity has already been reserved in ImageBlockStart
726
255
                        if pal.capacity() - pal.len() >= src.len() {
727
255
                            pal.extend_from_slice(src);
728
255
                        }
729
0
                    }
730
255
                    goto!(n, LocalPalette(left - n))
731
                } else {
732
1.59k
                    goto!(LzwInit(b))
733
                }
734
            }
735
1.59k
            LzwInit(min_code_size) => {
736
1.59k
                if !self.skip_frame_decoding {
737
                    // Reset validates the min code size
738
1.59k
                    self.lzw_reader.reset(min_code_size)?;
739
1.58k
                    goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels))
740
                } else {
741
0
                    LzwReader::check_code_size(min_code_size)?;
742
0
                    goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size }))
743
                }
744
            }
745
0
            CopySubBlock(left) => {
746
0
                debug_assert!(self.skip_frame_decoding);
747
0
                if left > 0 {
748
0
                    let n = cmp::min(left, buf.len());
749
0
                    let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
750
0
                    goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
751
0
                } else if b != 0 {
752
0
                    goto!(CopySubBlock(b as usize))
753
                } else {
754
0
                    goto!(0, FrameDecoded)
755
                }
756
            }
757
729k
            DecodeSubBlock(left) => {
758
729k
                debug_assert!(!self.skip_frame_decoding);
759
729k
                if left > 0 {
760
469k
                    let n = cmp::min(left, buf.len());
761
469k
                    if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
762
9.19k
                        return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing);
763
460k
                    }
764
765
459k
                    let (mut consumed, bytes_len, status) =
766
460k
                        self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
767
768
                    // skip if can't make progress (decode would fail if check_for_end_code was set)
769
459k
                    if matches!(status, LzwStatus::NoProgress) {
770
441
                        consumed = n;
771
459k
                    }
772
773
459k
                    let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
774
382k
                        Decoded::BytesDecoded(bytes_len)
775
                    } else {
776
77.4k
                        Decoded::Nothing
777
                    };
778
459k
                    goto!(consumed, DecodeSubBlock(left - consumed), emit decoded)
779
260k
                } else if b != 0 {
780
                    // decode next sub-block
781
258k
                    goto!(DecodeSubBlock(b as usize))
782
                } else {
783
1.78k
                    let (_, bytes_len, status) = self.lzw_reader.decode_bytes(&[], write_into)?;
784
785
1.77k
                    if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
786
1.59k
                        goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))
787
178
                    } else if matches!(status, LzwStatus::Ok) {
788
58
                        goto!(0, DecodeSubBlock(0), emit Decoded::Nothing)
789
120
                    } else if matches!(status, LzwStatus::Done) {
790
4
                        goto!(0, FrameDecoded)
791
                    } else {
792
116
                        goto!(0, FrameDecoded)
793
                    }
794
                }
795
            }
796
            FrameDecoded => {
797
                // end of image data reached
798
120
                self.current = None;
799
120
                debug_assert_eq!(0, b);
800
120
                goto!(BlockEnd, emit Decoded::DataEnd)
801
            }
802
0
            Trailer => goto!(0, Trailer, emit Decoded::Nothing),
803
        }
804
1.28M
    }
805
806
1.65k
    fn read_control_extension(&mut self) -> Result<(), DecodingError> {
807
1.65k
        if self.ext.data.len() != 5 {
808
25
            return Err(DecodingError::format("control extension has wrong length"));
809
1.63k
        }
810
1.63k
        let control = &self.ext.data[1..];
811
1.63k
812
1.63k
        let frame = self.current.get_or_insert_with(Frame::default);
813
1.63k
        let control_flags = control[0];
814
1.63k
        frame.needs_user_input = control_flags & 0b10 != 0;
815
1.63k
        frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) {
816
1.54k
            Some(method) => method,
817
93
            None => DisposalMethod::Any,
818
        };
819
1.63k
        frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap());
820
1.63k
        frame.transparent = (control_flags & 1 != 0).then_some(control[3]);
821
1.63k
        Ok(())
822
1.65k
    }
823
824
1.64k
    fn add_frame(&mut self) {
825
1.64k
        if self.current.is_none() {
826
1.56k
            self.current = Some(Frame::default());
827
1.56k
        }
828
1.64k
    }
829
}
830
831
#[test]
832
fn error_cast() {
833
    let _ : Box<dyn error::Error> = DecodingError::format("testing").into();
834
}