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 if sub_block_len == 0 {
736 if self.ext.id.into_known() == Some(Extension::Control) {
741 self.read_control_extension()?;
742 }
743 goto!(0, ExtensionBlockEnd, emit Decoded::SubBlock { ext: self.ext.id, is_last: true })
744 } else {
745 goto!(0, ExtensionDataSubBlock(sub_block_len))
746 }
747 }
748 ExtensionDataSubBlock(left) => {
749 if left > 0 {
750 let n = cmp::min(left, buf.len());
751 let needs_to_grow =
752 n > self.ext.data.capacity().wrapping_sub(self.ext.data.len());
753 if needs_to_grow {
754 return Err(DecodingError::OutOfMemory);
755 }
756 self.ext.data.extend_from_slice(&buf[..n]);
757 goto!(n, ExtensionDataSubBlock(left - n))
758 } else if b == 0 {
759 if self.ext.id.into_known() == Some(Extension::Control) {
760 self.read_control_extension()?;
761 }
762 goto!(ExtensionBlockEnd, emit Decoded::SubBlock { ext: self.ext.id, is_last: true })
763 } else {
764 goto!(ExtensionDataSubBlockStart(b as usize), emit Decoded::SubBlock { ext: self.ext.id, is_last: false })
765 }
766 }
767 LocalPalette(left) => {
768 if left > 0 {
769 let n = cmp::min(left, buf.len());
770 let src = &buf[..n];
771 if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
772 if pal.capacity() - pal.len() >= src.len() {
774 pal.extend_from_slice(src);
775 }
776 }
777 goto!(n, LocalPalette(left - n))
778 } else {
779 goto!(LzwInit(b))
780 }
781 }
782 LzwInit(min_code_size) => {
783 if !self.skip_frame_decoding {
784 self.lzw_reader.reset(min_code_size)?;
786 goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels))
787 } else {
788 LzwReader::check_code_size(min_code_size)?;
789 goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size }))
790 }
791 }
792 CopySubBlock(left) => {
793 debug_assert!(self.skip_frame_decoding);
794 if left > 0 {
795 let n = cmp::min(left, buf.len());
796 let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
797 goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
798 } else if b != 0 {
799 goto!(CopySubBlock(b as usize))
800 } else {
801 goto!(0, FrameDecoded)
802 }
803 }
804 DecodeSubBlock(left) => {
805 debug_assert!(!self.skip_frame_decoding);
806 if left > 0 {
807 let n = cmp::min(left, buf.len());
808 if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
809 return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing);
810 }
811
812 let (mut consumed, bytes_len, status) =
813 self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
814
815 if matches!(status, LzwStatus::NoProgress) {
817 consumed = n;
818 }
819
820 let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
821 Decoded::BytesDecoded(bytes_len)
822 } else {
823 Decoded::Nothing
824 };
825 goto!(consumed, DecodeSubBlock(left - consumed), emit decoded)
826 } else if b != 0 {
827 goto!(DecodeSubBlock(b as usize))
829 } else {
830 let (_, bytes_len, status) = self.lzw_reader.decode_bytes(&[], write_into)?;
831
832 if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
833 goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))
834 } else if matches!(status, LzwStatus::Ok) {
835 goto!(0, DecodeSubBlock(0), emit Decoded::Nothing)
836 } else if matches!(status, LzwStatus::Done) {
837 goto!(0, FrameDecoded)
838 } else {
839 goto!(0, FrameDecoded)
840 }
841 }
842 }
843 FrameDecoded => {
844 self.current = None;
846 debug_assert_eq!(0, b);
847 goto!(BlockEnd, emit Decoded::DataEnd)
848 }
849 Trailer => goto!(0, Trailer, emit Decoded::Nothing),
850 }
851 }
852
853 fn read_control_extension(&mut self) -> Result<(), DecodingError> {
854 if self.ext.data.len() != 4 {
855 return Err(DecodingError::format("control extension has wrong length"));
856 }
857 let control = &self.ext.data;
858
859 let frame = self.current.get_or_insert_with(Frame::default);
860 let control_flags = control[0];
861 frame.needs_user_input = control_flags & 0b10 != 0;
862 frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) {
863 Some(method) => method,
864 None => DisposalMethod::Any,
865 };
866 frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap());
867 frame.transparent = (control_flags & 1 != 0).then_some(control[3]);
868 Ok(())
869 }
870
871 fn add_frame(&mut self) {
872 if self.current.is_none() {
873 self.current = Some(Frame::default());
874 }
875 }
876}
877
878#[test]
879fn error_cast() {
880 let _: Box<dyn error::Error> = DecodingError::format("testing").into();
881}