Coverage Report

Created: 2026-01-19 07:25

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