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 std::error;
11use std::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
19pub const PLTE_CHANNELS: usize = 3;
21
22#[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#[derive(Debug)]
44#[non_exhaustive]
45pub enum DecodingError {
46 OutOfMemory,
48 MemoryLimit,
50 DecoderNotFound,
52 EndCodeNotFound,
54 UnexpectedEof,
56 LzwError(LzwError),
58 Format(DecodingFormatError),
60 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 Self::LzwError(ref err) => Some(err),
99 Self::Format(ref err) => Some(err),
100 Self::Io(ref err) => Some(err),
101 }
102 }
103}
104
105impl From<LzwError> for DecodingError {
106 #[inline]
107 fn from(err: LzwError) -> Self {
108 Self::LzwError(err)
109 }
110}
111
112impl From<io::Error> for DecodingError {
113 #[inline]
114 fn from(err: io::Error) -> Self {
115 Self::Io(err)
116 }
117}
118
119impl From<DecodingFormatError> for DecodingError {
120 #[inline]
121 fn from(err: DecodingFormatError) -> Self {
122 Self::Format(err)
123 }
124}
125
126#[derive(Debug, Copy, Clone)]
128pub enum FrameDataType {
129 Pixels,
131 Lzw {
133 min_code_size: u8,
135 },
136}
137
138#[derive(Debug)]
140#[non_exhaustive]
141pub enum Decoded {
142 Nothing,
144 GlobalPalette(Box<[u8]>),
146 BackgroundColor(u8),
148 HeaderEnd,
151 BlockStart(Block),
154 SubBlock {
158 ext: AnyExtension,
160 is_last: bool,
162 },
163 FrameMetadata(FrameDataType),
169 BytesDecoded(NonZeroUsize),
171 LzwDataCopied(usize),
173 DataEnd,
175}
176
177#[derive(Debug, Copy, Clone)]
179enum State {
180 Magic,
181 ScreenDescriptor,
182 ImageBlockStart,
183 GlobalPalette(usize),
184 BlockStart(u8),
185 BlockEnd,
186 ExtensionBlockStart,
187 ExtensionDataSubBlockStart(usize),
189 ExtensionDataSubBlock(usize),
191 ExtensionBlockEnd,
192 LocalPalette(usize),
193 LzwInit(u8),
194 DecodeSubBlock(usize),
196 CopySubBlock(usize),
198 FrameDecoded,
199 Trailer,
200}
201use self::State::*;
202
203use super::converter::PixelConverter;
204
205pub struct FrameDecoder {
207 lzw_reader: LzwReader,
208 pixel_converter: PixelConverter,
209 memory_limit: MemoryLimit,
210}
211
212impl FrameDecoder {
213 #[inline]
215 #[must_use]
216 pub fn new(options: DecodeOptions) -> Self {
217 Self {
218 lzw_reader: LzwReader::new(options.check_for_end_code),
219 pixel_converter: PixelConverter::new(options.color_output),
220 memory_limit: options.memory_limit.clone(),
221 }
222 }
223
224 #[inline]
226 pub fn set_global_palette(&mut self, palette: Vec<u8>) {
227 self.pixel_converter.set_global_palette(palette);
228 }
229
230 #[inline]
234 pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> {
235 let pixel_bytes = self
236 .pixel_converter
237 .check_buffer_size(frame, &self.memory_limit)?;
238 let mut vec = vec![0; pixel_bytes];
239 self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?;
240 frame.buffer = Cow::Owned(vec);
241 frame.interlaced = false;
242 Ok(())
243 }
244
245 pub fn decode_lzw_encoded_frame_into_buffer(
249 &mut self,
250 frame: &Frame<'_>,
251 buf: &mut [u8],
252 ) -> Result<(), DecodingError> {
253 let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[]));
254 self.lzw_reader.reset(min_code_size)?;
255 let lzw_reader = &mut self.lzw_reader;
256 self.pixel_converter
257 .read_into_buffer(frame, buf, &mut move |out| loop {
258 let (bytes_read, bytes_written, status) = lzw_reader.decode_bytes(data, out)?;
259 data = data.get(bytes_read..).unwrap_or_default();
260 if bytes_written > 0 || matches!(status, LzwStatus::NoProgress) {
261 return Ok(bytes_written);
262 }
263 })?;
264 Ok(())
265 }
266
267 #[inline]
269 #[must_use]
270 pub fn buffer_size(&self, frame: &Frame<'_>) -> usize {
271 self.pixel_converter.buffer_size(frame).unwrap()
272 }
273}
274
275struct LzwReader {
276 decoder: Option<LzwDecoder>,
277 min_code_size: u8,
278 check_for_end_code: bool,
279}
280
281impl LzwReader {
282 pub fn new(check_for_end_code: bool) -> Self {
283 Self {
284 decoder: None,
285 min_code_size: 0,
286 check_for_end_code,
287 }
288 }
289
290 pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> {
291 if min_code_size > 11 || min_code_size < 1 {
294 return Err(DecodingError::format("invalid minimal code size"));
295 }
296 Ok(())
297 }
298
299 pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> {
300 Self::check_code_size(min_code_size)?;
301
302 if self.min_code_size != min_code_size || self.decoder.is_none() {
304 self.min_code_size = min_code_size;
305 self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size));
306 } else {
307 self.decoder
308 .as_mut()
309 .ok_or_else(|| DecodingError::format("bad state"))?
310 .reset();
311 }
312
313 Ok(())
314 }
315
316 pub fn has_ended(&self) -> bool {
317 self.decoder.as_ref().map_or(true, |e| e.has_ended())
318 }
319
320 pub fn decode_bytes(
321 &mut self,
322 lzw_data: &[u8],
323 decode_buffer: &mut OutputBuffer<'_>,
324 ) -> Result<(usize, usize, LzwStatus), DecodingError> {
325 let decoder = self
326 .decoder
327 .as_mut()
328 .ok_or(DecodingError::DecoderNotFound)?;
329
330 let (status, consumed_in, consumed_out) = match decode_buffer {
331 OutputBuffer::Slice(buf) => {
332 let decoded = decoder.decode_bytes(lzw_data, buf);
333 (decoded.status, decoded.consumed_in, decoded.consumed_out)
334 }
335 OutputBuffer::None => {
336 let decoded = decoder.decode_bytes(lzw_data, &mut []);
337 (decoded.status, decoded.consumed_in, decoded.consumed_out)
338 }
339 OutputBuffer::Vec(buf) => {
340 let decoded = decoder.into_vec(buf).decode(lzw_data);
341 (decoded.status, decoded.consumed_in, decoded.consumed_out)
342 }
343 };
344
345 let status = match status? {
346 ok @ LzwStatus::Done | ok @ LzwStatus::Ok => ok,
347 ok @ LzwStatus::NoProgress => {
348 if self.check_for_end_code {
349 return Err(DecodingError::EndCodeNotFound);
350 }
351
352 ok
353 }
354 };
355
356 Ok((consumed_in, consumed_out, status))
357 }
358}
359
360pub struct StreamingDecoder {
364 state: State,
365 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: ExtensionData,
379 current: Option<Frame<'static>>,
381 header_end_reached: bool,
383}
384
385#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
387pub enum Version {
388 V87a,
390 V89a,
392}
393
394struct ExtensionData {
395 id: AnyExtension,
396 data: Vec<u8>,
397}
398
399pub enum OutputBuffer<'a> {
401 Slice(&'a mut [u8]),
403 Vec(&'a mut Vec<u8>),
405 None,
407}
408
409impl OutputBuffer<'_> {
410 fn append(
411 &mut self,
412 buf: &[u8],
413 memory_limit: &MemoryLimit,
414 ) -> Result<(usize, usize), DecodingError> {
415 let (consumed, copied) = match self {
416 OutputBuffer::Slice(slice) => {
417 let len = cmp::min(buf.len(), slice.len());
418 slice[..len].copy_from_slice(&buf[..len]);
419 (len, len)
420 }
421 OutputBuffer::Vec(vec) => {
422 let vec: &mut Vec<u8> = vec;
423 let len = buf.len();
424 memory_limit.try_reserve(vec, len)?;
425 if vec.capacity() - vec.len() >= len {
426 vec.extend_from_slice(buf);
427 }
428 (len, len)
429 }
430 OutputBuffer::None => (buf.len(), 0),
433 };
434 Ok((consumed, copied))
435 }
436}
437
438impl StreamingDecoder {
439 #[must_use]
441 pub fn new() -> Self {
442 let options = DecodeOptions::new();
443 Self::with_options(&options)
444 }
445
446 pub(crate) fn with_options(options: &DecodeOptions) -> Self {
447 Self {
448 internal_buffer: [0; 9],
449 unused_internal_buffer_len: 0,
450 state: Magic,
451 lzw_reader: LzwReader::new(options.check_for_end_code),
452 skip_frame_decoding: options.skip_frame_decoding,
453 check_frame_consistency: options.check_frame_consistency,
454 allow_unknown_blocks: options.allow_unknown_blocks,
455 memory_limit: options.memory_limit.clone(),
456 version: Version::V87a,
457 width: 0,
458 height: 0,
459 global_color_table: Vec::new(),
460 ext: ExtensionData {
461 id: AnyExtension(0),
462 data: Vec::with_capacity(256), },
464 current: None,
465 header_end_reached: false,
466 }
467 }
468
469 pub fn update(
474 &mut self,
475 mut buf: &[u8],
476 write_into: &mut OutputBuffer<'_>,
477 ) -> Result<(usize, Decoded), DecodingError> {
478 let len = buf.len();
479 while !buf.is_empty() {
480 let (bytes, decoded) = self.next_state(buf, write_into)?;
481 buf = buf.get(bytes..).unwrap_or_default();
482 match decoded {
483 Decoded::Nothing => {}
484 result => {
485 return Ok((len - buf.len(), result));
486 }
487 };
488 }
489 Ok((len - buf.len(), Decoded::Nothing))
490 }
491
492 #[must_use]
495 pub fn last_ext_sub_block(&mut self) -> &[u8] {
496 &self.ext.data
497 }
498
499 #[must_use]
501 #[track_caller]
502 pub fn current_frame_mut(&mut self) -> &mut Frame<'static> {
503 self.current.as_mut().unwrap()
504 }
505
506 #[track_caller]
508 #[must_use]
509 pub fn current_frame(&self) -> &Frame<'static> {
510 self.current.as_ref().unwrap()
511 }
512
513 #[inline(always)]
515 fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> {
516 self.current
517 .as_mut()
518 .ok_or_else(|| DecodingError::format("bad state"))
519 }
520
521 #[must_use]
523 pub fn width(&self) -> u16 {
524 self.width
525 }
526
527 #[must_use]
529 pub fn height(&self) -> u16 {
530 self.height
531 }
532
533 #[must_use]
538 pub fn version(&self) -> Version {
539 self.version
540 }
541
542 #[inline]
543 fn next_state(
544 &mut self,
545 buf: &[u8],
546 write_into: &mut OutputBuffer<'_>,
547 ) -> 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 let b = *buf.first().ok_or(DecodingError::UnexpectedEof)?;
593
594 match self.state {
595 Magic => {
596 let (consumed, version) = ensure_min_length_buffer!(6);
597
598 self.version = match version {
599 b"GIF87a" => Version::V87a,
600 b"GIF89a" => Version::V89a,
601 _ => return Err(DecodingError::format("malformed GIF header")),
602 };
603
604 goto!(consumed, ScreenDescriptor)
605 }
606 ScreenDescriptor => {
607 let (consumed, desc) = ensure_min_length_buffer!(7);
608
609 self.width = u16::from_le_bytes(desc[..2].try_into().unwrap());
610 self.height = u16::from_le_bytes(desc[2..4].try_into().unwrap());
611 let global_flags = desc[4];
612 let background_color = desc[5];
613
614 let global_table = global_flags & 0x80 != 0;
615 let table_size = if global_table {
616 let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize);
617 self.global_color_table
618 .try_reserve_exact(table_size)
619 .map_err(|_| DecodingError::OutOfMemory)?;
620 table_size
621 } else {
622 0usize
623 };
624
625 goto!(
626 consumed,
627 GlobalPalette(table_size),
628 emit Decoded::BackgroundColor(background_color)
629 )
630 }
631 ImageBlockStart => {
632 let (consumed, header) = ensure_min_length_buffer!(9);
633
634 let frame = self
635 .current
636 .as_mut()
637 .ok_or_else(|| DecodingError::format("bad state"))?;
638 frame.left = u16::from_le_bytes(header[..2].try_into().unwrap());
639 frame.top = u16::from_le_bytes(header[2..4].try_into().unwrap());
640 frame.width = u16::from_le_bytes(header[4..6].try_into().unwrap());
641 frame.height = u16::from_le_bytes(header[6..8].try_into().unwrap());
642
643 let flags = header[8];
644 frame.interlaced = (flags & 0b0100_0000) != 0;
645
646 if self.check_frame_consistency {
647 if self.width.checked_sub(frame.width) < Some(frame.left)
649 || self.height.checked_sub(frame.height) < Some(frame.top)
650 {
651 return Err(DecodingError::format("frame descriptor is out-of-bounds"));
652 }
653 }
654
655 let local_table = (flags & 0b1000_0000) != 0;
656 if local_table {
657 let table_size = flags & 0b0000_0111;
658 let pal_len = PLTE_CHANNELS * (1 << (table_size + 1));
659 frame
660 .palette
661 .get_or_insert_with(Vec::new)
662 .try_reserve_exact(pal_len)
663 .map_err(|_| DecodingError::OutOfMemory)?;
664 goto!(consumed, LocalPalette(pal_len))
665 } else {
666 goto!(consumed, LocalPalette(0))
667 }
668 }
669 GlobalPalette(left) => {
670 if left > 0 {
672 let n = cmp::min(left, buf.len());
673 if n <= self.global_color_table.capacity() - self.global_color_table.len() {
674 self.global_color_table.extend_from_slice(&buf[..n]);
675 }
676 goto!(n, GlobalPalette(left - n))
677 } else {
678 goto!(BlockStart(b), emit Decoded::GlobalPalette(
679 mem::take(&mut self.global_color_table).into_boxed_slice()
680 ))
681 }
682 }
683 BlockStart(type_) => {
684 if !self.header_end_reached && type_ != Block::Extension as u8 {
685 self.header_end_reached = true;
686 return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd);
687 }
688
689 match Block::from_u8(type_) {
690 Some(Block::Image) => {
691 self.add_frame();
692 goto!(0, ImageBlockStart, emit Decoded::BlockStart(Block::Image))
693 }
694 Some(Block::Extension) => {
695 self.ext.id = AnyExtension(b);
696 if !self.allow_unknown_blocks && self.ext.id.into_known().is_none() {
697 return Err(DecodingError::format(
698 "unknown extension block encountered",
699 ));
700 }
701 goto!(ExtensionBlockStart)
702 }
703 Some(Block::Trailer) => {
704 goto!(Trailer, emit Decoded::BlockStart(Block::Trailer))
706 }
707 None => {
708 if self.allow_unknown_blocks {
709 self.ext.id = AnyExtension(0);
710 goto!(0, ExtensionBlockStart)
711 } else {
712 Err(DecodingError::format("unknown block type encountered"))
713 }
714 }
715 }
716 }
717 ExtensionBlockStart => {
718 goto!(ExtensionDataSubBlockStart(b as usize), emit Decoded::BlockStart(Block::Extension))
719 }
720 ExtensionBlockEnd => {
721 self.ext.data.clear();
722 goto!(0, BlockEnd)
723 }
724 BlockEnd => {
725 if b == Block::Trailer as u8 {
726 goto!(0, BlockStart(b))
729 } else {
730 goto!(BlockStart(b))
731 }
732 }
733 ExtensionDataSubBlockStart(sub_block_len) => {
734 self.ext.data.clear();
735 goto!(0, ExtensionDataSubBlock(sub_block_len))
736 }
737 ExtensionDataSubBlock(left) => {
738 if left > 0 {
739 let n = cmp::min(left, buf.len());
740 let needs_to_grow =
741 n > self.ext.data.capacity().wrapping_sub(self.ext.data.len());
742 if needs_to_grow {
743 return Err(DecodingError::OutOfMemory);
744 }
745 self.ext.data.extend_from_slice(&buf[..n]);
746 goto!(n, ExtensionDataSubBlock(left - n))
747 } else if b == 0 {
748 if self.ext.id.into_known() == Some(Extension::Control) {
749 self.read_control_extension()?;
750 }
751 goto!(ExtensionBlockEnd, emit Decoded::SubBlock { ext: self.ext.id, is_last: true })
752 } else {
753 goto!(ExtensionDataSubBlockStart(b as usize), emit Decoded::SubBlock { ext: self.ext.id, is_last: false })
754 }
755 }
756 LocalPalette(left) => {
757 if left > 0 {
758 let n = cmp::min(left, buf.len());
759 let src = &buf[..n];
760 if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
761 if pal.capacity() - pal.len() >= src.len() {
763 pal.extend_from_slice(src);
764 }
765 }
766 goto!(n, LocalPalette(left - n))
767 } else {
768 goto!(LzwInit(b))
769 }
770 }
771 LzwInit(min_code_size) => {
772 if !self.skip_frame_decoding {
773 self.lzw_reader.reset(min_code_size)?;
775 goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels))
776 } else {
777 LzwReader::check_code_size(min_code_size)?;
778 goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size }))
779 }
780 }
781 CopySubBlock(left) => {
782 debug_assert!(self.skip_frame_decoding);
783 if left > 0 {
784 let n = cmp::min(left, buf.len());
785 let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
786 goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
787 } else if b != 0 {
788 goto!(CopySubBlock(b as usize))
789 } else {
790 goto!(0, FrameDecoded)
791 }
792 }
793 DecodeSubBlock(left) => {
794 debug_assert!(!self.skip_frame_decoding);
795 if left > 0 {
796 let n = cmp::min(left, buf.len());
797 if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
798 return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing);
799 }
800
801 let (mut consumed, bytes_len, status) =
802 self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
803
804 if matches!(status, LzwStatus::NoProgress) {
806 consumed = n;
807 }
808
809 let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
810 Decoded::BytesDecoded(bytes_len)
811 } else {
812 Decoded::Nothing
813 };
814 goto!(consumed, DecodeSubBlock(left - consumed), emit decoded)
815 } else if b != 0 {
816 goto!(DecodeSubBlock(b as usize))
818 } else {
819 let (_, bytes_len, status) = self.lzw_reader.decode_bytes(&[], write_into)?;
820
821 if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
822 goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))
823 } else if matches!(status, LzwStatus::Ok) {
824 goto!(0, DecodeSubBlock(0), emit Decoded::Nothing)
825 } else if matches!(status, LzwStatus::Done) {
826 goto!(0, FrameDecoded)
827 } else {
828 goto!(0, FrameDecoded)
829 }
830 }
831 }
832 FrameDecoded => {
833 self.current = None;
835 debug_assert_eq!(0, b);
836 goto!(BlockEnd, emit Decoded::DataEnd)
837 }
838 Trailer => goto!(0, Trailer, emit Decoded::Nothing),
839 }
840 }
841
842 fn read_control_extension(&mut self) -> Result<(), DecodingError> {
843 if self.ext.data.len() != 4 {
844 return Err(DecodingError::format("control extension has wrong length"));
845 }
846 let control = &self.ext.data;
847
848 let frame = self.current.get_or_insert_with(Frame::default);
849 let control_flags = control[0];
850 frame.needs_user_input = control_flags & 0b10 != 0;
851 frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) {
852 Some(method) => method,
853 None => DisposalMethod::Any,
854 };
855 frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap());
856 frame.transparent = (control_flags & 1 != 0).then_some(control[3]);
857 Ok(())
858 }
859
860 fn add_frame(&mut self) {
861 if self.current.is_none() {
862 self.current = Some(Frame::default());
863 }
864 }
865}
866
867#[test]
868fn error_cast() {
869 let _: Box<dyn error::Error> = DecodingError::format("testing").into();
870}