1use std::borrow::Cow;
2use std::cmp;
3use std::default::Default;
4use std::error;
5use std::fmt;
6use std::io;
7use std::mem;
8use std::num::NonZeroUsize;
9
10use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
11use crate::reader::DecodeOptions;
12use crate::MemoryLimit;
13use crate::Repeat;
14
15use weezl::{decode::Decoder as LzwDecoder, BitOrder, LzwError, LzwStatus};
16
17pub const PLTE_CHANNELS: usize = 3;
19
20#[derive(Debug)]
22pub struct DecodingFormatError {
23 underlying: Box<dyn error::Error + Send + Sync + 'static>,
24}
25
26impl fmt::Display for DecodingFormatError {
27 #[cold]
28 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
29 fmt::Display::fmt(&*self.underlying, fmt)
30 }
31}
32
33impl error::Error for DecodingFormatError {
34 #[cold]
35 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
36 Some(&*self.underlying as _)
37 }
38}
39
40#[derive(Debug)]
41pub enum DecodingError {
43 Format(DecodingFormatError),
45 Io(io::Error),
47}
48
49impl DecodingError {
50 #[cold]
51 pub(crate) fn format(err: &'static str) -> Self {
52 Self::Format(DecodingFormatError {
53 underlying: err.into(),
54 })
55 }
56}
57
58impl fmt::Display for DecodingError {
59 #[cold]
60 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match *self {
62 Self::Format(ref d) => d.fmt(fmt),
63 Self::Io(ref err) => err.fmt(fmt),
64 }
65 }
66}
67
68impl error::Error for DecodingError {
69 #[cold]
70 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
71 match *self {
72 Self::Format(ref err) => Some(err),
73 Self::Io(ref err) => Some(err),
74 }
75 }
76}
77
78impl From<io::Error> for DecodingError {
79 #[inline]
80 fn from(err: io::Error) -> Self {
81 Self::Io(err)
82 }
83}
84
85impl From<io::ErrorKind> for DecodingError {
86 #[cold]
87 fn from(err: io::ErrorKind) -> Self {
88 Self::Io(io::Error::from(err))
89 }
90}
91
92impl From<DecodingFormatError> for DecodingError {
93 #[inline]
94 fn from(err: DecodingFormatError) -> Self {
95 Self::Format(err)
96 }
97}
98
99#[derive(Debug, Copy, Clone)]
101pub enum FrameDataType {
102 Pixels,
104 Lzw {
106 min_code_size: u8,
108 },
109}
110
111#[derive(Debug)]
113#[non_exhaustive]
114pub enum Decoded {
115 Nothing,
117 GlobalPalette(Box<[u8]>),
119 BackgroundColor(u8),
121 Repetitions(Repeat),
123 HeaderEnd,
126 BlockStart(Block),
129 SubBlockFinished(AnyExtension),
136 BlockFinished(AnyExtension),
143 FrameMetadata(FrameDataType),
149 BytesDecoded(NonZeroUsize),
151 LzwDataCopied(usize),
153 DataEnd,
155}
156
157#[derive(Debug, Copy, Clone)]
159enum State {
160 Magic,
161 ScreenDescriptor,
162 ImageBlockStart,
163 GlobalPalette(usize),
164 BlockStart(u8),
165 BlockEnd,
166 ExtensionBlockStart,
167 ExtensionDataBlock(usize),
169 ApplicationExtension,
170 LocalPalette(usize),
171 LzwInit(u8),
172 DecodeSubBlock(usize),
174 CopySubBlock(usize),
176 FrameDecoded,
177 Trailer,
178}
179use self::State::*;
180
181use super::converter::PixelConverter;
182
183pub struct FrameDecoder {
185 lzw_reader: LzwReader,
186 pixel_converter: PixelConverter,
187}
188
189impl FrameDecoder {
190 #[inline]
192 #[must_use]
193 pub fn new(options: DecodeOptions) -> Self {
194 Self {
195 lzw_reader: LzwReader::new(options.check_for_end_code),
196 pixel_converter: PixelConverter::new(options.color_output, options.memory_limit),
197 }
198 }
199
200 #[inline]
202 pub fn set_global_palette(&mut self, palette: Vec<u8>) {
203 self.pixel_converter.set_global_palette(palette);
204 }
205
206 #[inline]
210 pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> {
211 let pixel_bytes = self.pixel_converter.check_buffer_size(frame)?;
212 let mut vec = vec![0; pixel_bytes];
213 self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?;
214 frame.buffer = Cow::Owned(vec);
215 frame.interlaced = false;
216 Ok(())
217 }
218
219 pub fn decode_lzw_encoded_frame_into_buffer(
223 &mut self,
224 frame: &Frame<'_>,
225 buf: &mut [u8],
226 ) -> Result<(), DecodingError> {
227 let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[]));
228 self.lzw_reader.reset(min_code_size)?;
229 let lzw_reader = &mut self.lzw_reader;
230 self.pixel_converter
231 .read_into_buffer(frame, buf, &mut move |out| loop {
232 let (bytes_read, bytes_written, status) = lzw_reader.decode_bytes(data, out)?;
233 data = data.get(bytes_read..).unwrap_or_default();
234 if bytes_written > 0 || matches!(status, LzwStatus::NoProgress) {
235 return Ok(bytes_written);
236 }
237 })?;
238 Ok(())
239 }
240
241 #[inline]
243 #[must_use]
244 pub fn buffer_size(&self, frame: &Frame<'_>) -> usize {
245 self.pixel_converter.buffer_size(frame).unwrap()
246 }
247}
248
249struct LzwReader {
250 decoder: Option<LzwDecoder>,
251 min_code_size: u8,
252 check_for_end_code: bool,
253}
254
255impl LzwReader {
256 pub fn new(check_for_end_code: bool) -> Self {
257 Self {
258 decoder: None,
259 min_code_size: 0,
260 check_for_end_code,
261 }
262 }
263
264 pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> {
265 if min_code_size > 11 || min_code_size < 1 {
268 return Err(DecodingError::format("invalid minimal code size"));
269 }
270 Ok(())
271 }
272
273 pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> {
274 Self::check_code_size(min_code_size)?;
275
276 if self.min_code_size != min_code_size || self.decoder.is_none() {
278 self.min_code_size = min_code_size;
279 self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size));
280 } else {
281 self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state"))?.reset();
282 }
283
284 Ok(())
285 }
286
287 pub fn has_ended(&self) -> bool {
288 self.decoder.as_ref().map_or(true, |e| e.has_ended())
289 }
290
291 pub fn decode_bytes(
292 &mut self,
293 lzw_data: &[u8],
294 decode_buffer: &mut OutputBuffer<'_>,
295 ) -> io::Result<(usize, usize, LzwStatus)> {
296 let decoder = self.decoder.as_mut().ok_or(io::ErrorKind::Unsupported)?;
297
298 let decode_buffer = match decode_buffer {
299 OutputBuffer::Slice(buf) => &mut **buf,
300 OutputBuffer::None => &mut [],
301 OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)),
302 };
303
304 let decoded = decoder.decode_bytes(lzw_data, decode_buffer);
305
306 let status = match decoded.status {
307 Ok(ok @ LzwStatus::Done | ok @ LzwStatus::Ok) => ok,
308 Ok(ok @ LzwStatus::NoProgress) => {
309 if self.check_for_end_code {
310 return Err(io::Error::new(
311 io::ErrorKind::InvalidData,
312 "no end code in lzw stream",
313 ));
314 }
315
316 ok
317 }
318 Err(err @ LzwError::InvalidCode) => {
319 return Err(io::Error::new(io::ErrorKind::InvalidData, err));
320 }
321 };
322
323 Ok((decoded.consumed_in, decoded.consumed_out, status))
324 }
325}
326
327pub struct StreamingDecoder {
331 state: State,
332 internal_buffer: [u8; 9],
334 unused_internal_buffer_len: u8,
335 lzw_reader: LzwReader,
336 skip_frame_decoding: bool,
337 check_frame_consistency: bool,
338 allow_unknown_blocks: bool,
339 memory_limit: MemoryLimit,
340 version: Version,
341 width: u16,
342 height: u16,
343 global_color_table: Vec<u8>,
344 ext: ExtensionData,
346 current: Option<Frame<'static>>,
348 header_end_reached: bool,
350}
351
352#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
354pub enum Version {
355 V87a,
357 V89a,
359}
360
361struct ExtensionData {
362 id: AnyExtension,
363 data: Vec<u8>,
364 is_block_end: bool,
365}
366
367pub enum OutputBuffer<'a> {
369 Slice(&'a mut [u8]),
371 Vec(&'a mut Vec<u8>),
373 None,
375}
376
377impl OutputBuffer<'_> {
378 fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> {
379 let (consumed, copied) = match self {
380 OutputBuffer::Slice(slice) => {
381 let len = cmp::min(buf.len(), slice.len());
382 slice[..len].copy_from_slice(&buf[..len]);
383 (len, len)
384 },
385 OutputBuffer::Vec(vec) => {
386 let vec: &mut Vec<u8> = vec;
387 let len = buf.len();
388 memory_limit.check_size(vec.len() + len)?;
389 vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?;
390 if vec.capacity() - vec.len() >= len {
391 vec.extend_from_slice(buf);
392 }
393 (len, len)
394 },
395 OutputBuffer::None => (buf.len(), 0),
398 };
399 Ok((consumed, copied))
400 }
401}
402
403impl StreamingDecoder {
404 #[must_use]
406 pub fn new() -> Self {
407 let options = DecodeOptions::new();
408 Self::with_options(&options)
409 }
410
411 pub(crate) fn with_options(options: &DecodeOptions) -> Self {
412 Self {
413 internal_buffer: [0; 9],
414 unused_internal_buffer_len: 0,
415 state: Magic,
416 lzw_reader: LzwReader::new(options.check_for_end_code),
417 skip_frame_decoding: options.skip_frame_decoding,
418 check_frame_consistency: options.check_frame_consistency,
419 allow_unknown_blocks: options.allow_unknown_blocks,
420 memory_limit: options.memory_limit.clone(),
421 version: Version::V87a,
422 width: 0,
423 height: 0,
424 global_color_table: Vec::new(),
425 ext: ExtensionData {
426 id: AnyExtension(0),
427 data: Vec::with_capacity(256), is_block_end: true,
429 },
430 current: None,
431 header_end_reached: false,
432 }
433 }
434
435 pub fn update(
440 &mut self,
441 mut buf: &[u8],
442 write_into: &mut OutputBuffer<'_>,
443 ) -> Result<(usize, Decoded), DecodingError> {
444 let len = buf.len();
445 while !buf.is_empty() {
446 let (bytes, decoded) = self.next_state(buf, write_into)?;
447 buf = buf.get(bytes..).unwrap_or_default();
448 match decoded {
449 Decoded::Nothing => {},
450 result => {
451 return Ok((len-buf.len(), result));
452 },
453 };
454 }
455 Ok((len - buf.len(), Decoded::Nothing))
456 }
457
458 #[must_use]
460 pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) {
461 (self.ext.id, &self.ext.data, self.ext.is_block_end)
462 }
463
464 #[must_use]
466 #[track_caller]
467 pub fn current_frame_mut(&mut self) -> &mut Frame<'static> {
468 self.current.as_mut().unwrap()
469 }
470
471 #[track_caller]
473 #[must_use]
474 pub fn current_frame(&self) -> &Frame<'static> {
475 self.current.as_ref().unwrap()
476 }
477
478 #[inline(always)]
480 fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> {
481 self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))
482 }
483
484 #[must_use]
486 pub fn width(&self) -> u16 {
487 self.width
488 }
489
490 #[must_use]
492 pub fn height(&self) -> u16 {
493 self.height
494 }
495
496 #[must_use]
501 pub fn version(&self) -> Version {
502 self.version
503 }
504
505 #[inline]
506 fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded), DecodingError> {
507 macro_rules! goto (
508 ($n:expr, $state:expr) => ({
509 self.state = $state;
510 Ok(($n, Decoded::Nothing))
511 });
512 ($state:expr) => ({
513 self.state = $state;
514 Ok((1, Decoded::Nothing))
515 });
516 ($n:expr, $state:expr, emit $res:expr) => ({
517 self.state = $state;
518 Ok(($n, $res))
519 });
520 ($state:expr, emit $res:expr) => ({
521 self.state = $state;
522 Ok((1, $res))
523 })
524 );
525
526 macro_rules! ensure_min_length_buffer (
527 ($required:expr) => ({
528 let required: usize = $required;
529 if buf.len() >= required && self.unused_internal_buffer_len == 0 {
530 (required, &buf[..required])
531 } else {
532 let has = usize::from(self.unused_internal_buffer_len);
533 let mut consumed = 0;
534 if has < required {
535 let to_copy = buf.len().min(required - has);
536 let new_len = has + to_copy;
537 self.internal_buffer[has .. new_len].copy_from_slice(&buf[..to_copy]);
538 consumed += to_copy;
539 if new_len < required {
540 self.unused_internal_buffer_len = new_len as u8;
541 return Ok((consumed, Decoded::Nothing));
542 } else {
543 self.unused_internal_buffer_len = 0;
544 }
545 }
546 (consumed, &self.internal_buffer[..required])
547 }
548 })
549 );
550
551 let b = *buf.first().ok_or(io::ErrorKind::UnexpectedEof)?;
552
553 match self.state {
554 Magic => {
555 let (consumed, version) = ensure_min_length_buffer!(6);
556
557 self.version = match version {
558 b"GIF87a" => Version::V87a,
559 b"GIF89a" => Version::V89a,
560 _ => return Err(DecodingError::format("malformed GIF header")),
561 };
562
563 goto!(consumed, ScreenDescriptor)
564 },
565 ScreenDescriptor => {
566 let (consumed, desc) = ensure_min_length_buffer!(7);
567
568 self.width = u16::from_le_bytes(desc[..2].try_into().unwrap());
569 self.height = u16::from_le_bytes(desc[2..4].try_into().unwrap());
570 let global_flags = desc[4];
571 let background_color = desc[5];
572
573 let global_table = global_flags & 0x80 != 0;
574 let table_size = if global_table {
575 let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize);
576 self.global_color_table.try_reserve_exact(table_size).map_err(|_| io::ErrorKind::OutOfMemory)?;
577 table_size
578 } else {
579 0usize
580 };
581
582 goto!(
583 consumed,
584 GlobalPalette(table_size),
585 emit Decoded::BackgroundColor(background_color)
586 )
587 },
588 ImageBlockStart => {
589 let (consumed, header) = ensure_min_length_buffer!(9);
590
591 let frame = self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))?;
592 frame.left = u16::from_le_bytes(header[..2].try_into().unwrap());
593 frame.top = u16::from_le_bytes(header[2..4].try_into().unwrap());
594 frame.width = u16::from_le_bytes(header[4..6].try_into().unwrap());
595 frame.height = u16::from_le_bytes(header[6..8].try_into().unwrap());
596
597 let flags = header[8];
598 frame.interlaced = (flags & 0b0100_0000) != 0;
599
600 if self.check_frame_consistency {
601 if self.width.checked_sub(frame.width) < Some(frame.left)
603 || self.height.checked_sub(frame.height) < Some(frame.top)
604 {
605 return Err(DecodingError::format("frame descriptor is out-of-bounds"));
606 }
607 }
608
609 let local_table = (flags & 0b1000_0000) != 0;
610 if local_table {
611 let table_size = flags & 0b0000_0111;
612 let pal_len = PLTE_CHANNELS * (1 << (table_size + 1));
613 frame.palette.get_or_insert_with(Vec::new)
614 .try_reserve_exact(pal_len).map_err(|_| io::ErrorKind::OutOfMemory)?;
615 goto!(consumed, LocalPalette(pal_len))
616 } else {
617 goto!(consumed, LocalPalette(0))
618 }
619 },
620 GlobalPalette(left) => {
621 if left > 0 {
623 let n = cmp::min(left, buf.len());
624 if n <= self.global_color_table.capacity() - self.global_color_table.len() {
625 self.global_color_table.extend_from_slice(&buf[..n]);
626 }
627 goto!(n, GlobalPalette(left - n))
628 } else {
629 goto!(BlockStart(b), emit Decoded::GlobalPalette(
630 mem::take(&mut self.global_color_table).into_boxed_slice()
631 ))
632 }
633 }
634 BlockStart(type_) => {
635 if !self.header_end_reached && type_ != Block::Extension as u8 {
636 self.header_end_reached = true;
637 return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd);
638 }
639
640 match Block::from_u8(type_) {
641 Some(Block::Image) => {
642 self.add_frame();
643 goto!(0, ImageBlockStart, emit Decoded::BlockStart(Block::Image))
644 }
645 Some(Block::Extension) => {
646 self.ext.data.clear();
647 self.ext.id = AnyExtension(b);
648 if self.ext.id.into_known().is_none() {
649 if !self.allow_unknown_blocks {
650 return Err(DecodingError::format(
651 "unknown extension block encountered",
652 ));
653 }
654 }
655 goto!(ExtensionBlockStart, emit Decoded::BlockStart(Block::Extension))
656 }
657 Some(Block::Trailer) => {
658 goto!(Trailer, emit Decoded::BlockStart(Block::Trailer))
660 }
661 None => {
662 if self.allow_unknown_blocks {
663 goto!(ExtensionDataBlock(b as usize))
664 } else {
665 Err(DecodingError::format("unknown block type encountered"))
666 }
667 }
668 }
669 },
670 BlockEnd => {
671 if b == Block::Trailer as u8 {
672 goto!(0, BlockStart(b))
675 } else {
676 goto!(BlockStart(b))
677 }
678 }
679 ExtensionBlockStart => {
680 self.ext.data.push(b);
681 goto!(ExtensionDataBlock(b as usize))
682 }
683 ExtensionDataBlock(left) => {
684 if left > 0 {
685 let n = cmp::min(left, buf.len());
686 self.memory_limit.check_size(self.ext.data.len() + n)?;
687 self.ext.data.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
688 self.ext.data.extend_from_slice(&buf[..n]);
689 goto!(n, ExtensionDataBlock(left - n))
690 } else if b == 0 {
691 self.ext.is_block_end = true;
692 match self.ext.id.into_known() {
693 Some(Extension::Application) => {
694 goto!(0, ApplicationExtension, emit Decoded::BlockFinished(self.ext.id))
695 }
696 Some(Extension::Control) => {
697 self.read_control_extension()?;
698 goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
699 },
700 _ => {
701 goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id))
702 }
703 }
704 } else {
705 self.ext.is_block_end = false;
706 goto!(ExtensionDataBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id))
707 }
708 }
709 ApplicationExtension => {
710 debug_assert_eq!(0, b);
711 if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0\x01" {
713 let repeat = &self.ext.data[13..15];
714 let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8;
715 goto!(BlockEnd, emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) }))
716 } else {
717 goto!(BlockEnd)
718 }
719 }
720 LocalPalette(left) => {
721 if left > 0 {
722 let n = cmp::min(left, buf.len());
723 let src = &buf[..n];
724 if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
725 if pal.capacity() - pal.len() >= src.len() {
727 pal.extend_from_slice(src);
728 }
729 }
730 goto!(n, LocalPalette(left - n))
731 } else {
732 goto!(LzwInit(b))
733 }
734 }
735 LzwInit(min_code_size) => {
736 if !self.skip_frame_decoding {
737 self.lzw_reader.reset(min_code_size)?;
739 goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels))
740 } else {
741 LzwReader::check_code_size(min_code_size)?;
742 goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size }))
743 }
744 }
745 CopySubBlock(left) => {
746 debug_assert!(self.skip_frame_decoding);
747 if left > 0 {
748 let n = cmp::min(left, buf.len());
749 let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
750 goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
751 } else if b != 0 {
752 goto!(CopySubBlock(b as usize))
753 } else {
754 goto!(0, FrameDecoded)
755 }
756 }
757 DecodeSubBlock(left) => {
758 debug_assert!(!self.skip_frame_decoding);
759 if left > 0 {
760 let n = cmp::min(left, buf.len());
761 if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
762 return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing);
763 }
764
765 let (mut consumed, bytes_len, status) =
766 self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
767
768 if matches!(status, LzwStatus::NoProgress) {
770 consumed = n;
771 }
772
773 let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
774 Decoded::BytesDecoded(bytes_len)
775 } else {
776 Decoded::Nothing
777 };
778 goto!(consumed, DecodeSubBlock(left - consumed), emit decoded)
779 } else if b != 0 {
780 goto!(DecodeSubBlock(b as usize))
782 } else {
783 let (_, bytes_len, status) = self.lzw_reader.decode_bytes(&[], write_into)?;
784
785 if let Some(bytes_len) = NonZeroUsize::new(bytes_len) {
786 goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))
787 } else if matches!(status, LzwStatus::Ok) {
788 goto!(0, DecodeSubBlock(0), emit Decoded::Nothing)
789 } else if matches!(status, LzwStatus::Done) {
790 goto!(0, FrameDecoded)
791 } else {
792 goto!(0, FrameDecoded)
793 }
794 }
795 }
796 FrameDecoded => {
797 self.current = None;
799 debug_assert_eq!(0, b);
800 goto!(BlockEnd, emit Decoded::DataEnd)
801 }
802 Trailer => goto!(0, Trailer, emit Decoded::Nothing),
803 }
804 }
805
806 fn read_control_extension(&mut self) -> Result<(), DecodingError> {
807 if self.ext.data.len() != 5 {
808 return Err(DecodingError::format("control extension has wrong length"));
809 }
810 let control = &self.ext.data[1..];
811
812 let frame = self.current.get_or_insert_with(Frame::default);
813 let control_flags = control[0];
814 frame.needs_user_input = control_flags & 0b10 != 0;
815 frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) {
816 Some(method) => method,
817 None => DisposalMethod::Any,
818 };
819 frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap());
820 frame.transparent = (control_flags & 1 != 0).then_some(control[3]);
821 Ok(())
822 }
823
824 fn add_frame(&mut self) {
825 if self.current.is_none() {
826 self.current = Some(Frame::default());
827 }
828 }
829}
830
831#[test]
832fn error_cast() {
833 let _ : Box<dyn error::Error> = DecodingError::format("testing").into();
834}