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
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 #[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#[derive(Debug, Copy, Clone)]
134pub enum FrameDataType {
135 Pixels,
137 Lzw {
139 min_code_size: u8,
141 },
142}
143
144#[derive(Debug)]
146#[non_exhaustive]
147pub enum Decoded {
148 Nothing,
150 GlobalPalette(Box<[u8]>),
152 BackgroundColor(u8),
154 HeaderEnd,
157 BlockStart(Block),
160 SubBlock {
164 ext: AnyExtension,
166 is_last: bool,
168 },
169 FrameMetadata(FrameDataType),
175 BytesDecoded(NonZeroUsize),
177 LzwDataCopied(usize),
179 DataEnd,
181}
182
183#[derive(Debug, Copy, Clone)]
185enum State {
186 Magic,
187 ScreenDescriptor,
188 ImageBlockStart,
189 GlobalPalette(usize),
190 BlockStart(u8),
191 BlockEnd,
192 ExtensionBlockStart,
193 ExtensionDataSubBlockStart(usize),
195 ExtensionDataSubBlock(usize),
197 ExtensionBlockEnd,
198 LocalPalette(usize),
199 LzwInit(u8),
200 DecodeSubBlock(usize),
202 CopySubBlock(usize),
204 FrameDecoded,
205 Trailer,
206}
207use self::State::*;
208
209use super::converter::PixelConverter;
210
211pub struct FrameDecoder {
213 lzw_reader: LzwReader,
214 pixel_converter: PixelConverter,
215 memory_limit: MemoryLimit,
216}
217
218impl FrameDecoder {
219 #[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 #[inline]
232 pub fn set_global_palette(&mut self, palette: Vec<u8>) {
233 self.pixel_converter.set_global_palette(palette);
234 }
235
236 #[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 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 #[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 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 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
366pub struct StreamingDecoder {
370 state: State,
371 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: ExtensionData,
385 current: Option<Frame<'static>>,
387 header_end_reached: bool,
389}
390
391#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
393pub enum Version {
394 V87a,
396 V89a,
398}
399
400struct ExtensionData {
401 id: AnyExtension,
402 data: Vec<u8>,
403}
404
405pub enum OutputBuffer<'a> {
407 Slice(&'a mut [u8]),
409 Vec(&'a mut Vec<u8>),
411 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 OutputBuffer::None => (buf.len(), 0),
439 };
440 Ok((consumed, copied))
441 }
442}
443
444impl StreamingDecoder {
445 #[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), },
470 current: None,
471 header_end_reached: false,
472 }
473 }
474
475 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 #[must_use]
501 pub fn last_ext_sub_block(&mut self) -> &[u8] {
502 &self.ext.data
503 }
504
505 #[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 #[track_caller]
514 #[must_use]
515 pub fn current_frame(&self) -> &Frame<'static> {
516 self.current.as_ref().unwrap()
517 }
518
519 #[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 #[must_use]
529 pub fn width(&self) -> u16 {
530 self.width
531 }
532
533 #[must_use]
535 pub fn height(&self) -> u16 {
536 self.height
537 }
538
539 #[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 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 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 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 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 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 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 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 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 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}