Skip to main content

ai_gif/reader/
decoder.rs

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