Skip to main content

png/decoder/
stream.rs

1use std::convert::TryInto;
2use std::error;
3use std::fmt;
4use std::io;
5use std::{borrow::Cow, cmp::min};
6
7use crc32fast::Hasher as Crc32;
8
9use super::zlib::UnfilterBuf;
10use super::zlib::ZlibStream;
11use crate::chunk::is_critical;
12use crate::chunk::{self, ChunkType, IDAT, IEND, IHDR};
13use crate::common::{
14    AnimationControl, BitDepth, BlendOp, ColorType, ContentLightLevelInfo, DisposeOp, FrameControl,
15    Info, MasteringDisplayColorVolume, ParameterError, ParameterErrorKind, PixelDimensions,
16    ScaledFloat, SourceChromaticities, Unit,
17};
18use crate::text_metadata::{ITXtChunk, TEXtChunk, TextDecodingError, ZTXtChunk};
19use crate::traits::ReadBytesExt;
20use crate::{CodingIndependentCodePoints, Limits};
21
22pub const CHUNK_BUFFER_SIZE: usize = 128;
23
24/// Determines if checksum checks should be disabled globally.
25///
26/// This is used only in fuzzing. `afl` automatically adds `--cfg fuzzing` to RUSTFLAGS which can
27/// be used to detect that build.
28#[allow(unexpected_cfgs)]
29const CHECKSUM_DISABLED: bool = cfg!(fuzzing);
30
31/// Kind of `u32` value that is being read via `State::U32`.
32#[derive(Debug)]
33enum U32ValueKind {
34    /// First 4 bytes of the PNG signature - see
35    /// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#PNG-file-signature
36    Signature1stU32,
37    /// Second 4 bytes of the PNG signature - see
38    /// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#PNG-file-signature
39    Signature2ndU32,
40    /// Chunk length - see
41    /// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#Chunk-layout
42    Length,
43    /// Chunk type - see
44    /// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#Chunk-layout
45    Type { length: u32 },
46    /// Chunk checksum - see
47    /// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html#Chunk-layout
48    Crc(ChunkType),
49    /// Sequence number from an `fdAT` chunk - see
50    /// https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk
51    ApngSequenceNumber,
52}
53
54#[derive(Debug)]
55enum State {
56    /// In this state we are reading a u32 value from external input.  We start with
57    /// `accumulated_count` set to `0`. After reading or accumulating the required 4 bytes we will
58    /// call `parse_32` which will then move onto the next state.
59    U32 {
60        kind: U32ValueKind,
61        bytes: [u8; 4],
62        accumulated_count: usize,
63    },
64    /// In this state we are reading chunk data from external input, and appending it to
65    /// `ChunkState::raw_bytes`. Then if all data has been read, we parse the chunk.
66    ReadChunkData(ChunkType),
67    /// In this state we are reading image data from external input and feeding it directly into
68    /// `StreamingDecoder::inflater`.
69    ImageData(ChunkType),
70}
71
72impl State {
73    fn new_u32(kind: U32ValueKind) -> Self {
74        Self::U32 {
75            kind,
76            bytes: [0; 4],
77            accumulated_count: 0,
78        }
79    }
80}
81
82#[derive(Debug)]
83/// Result of the decoding process
84pub enum Decoded {
85    /// Nothing decoded yet
86    Nothing,
87
88    /// A chunk header (length and type fields) has been read.
89    ChunkBegin(u32, ChunkType),
90
91    /// Chunk has been read successfully.
92    ChunkComplete(ChunkType),
93
94    /// An ancillary chunk has been read but it was in the wrong place, had corrupt contents, or had
95    /// an invalid CRC.
96    BadAncillaryChunk(ChunkType),
97
98    /// Skipped an ancillary chunk because it was unrecognized or the decoder was configured to skip
99    /// this type of chunk.
100    SkippedAncillaryChunk(ChunkType),
101
102    /// Decoded raw image data.
103    ImageData,
104
105    /// The last of a consecutive chunk of IDAT was done.
106    /// This is distinct from ChunkComplete which only marks that some IDAT chunk was completed but
107    /// not that no additional IDAT chunk follows.
108    ImageDataFlushed,
109}
110
111/// Any kind of error during PNG decoding.
112///
113/// This enumeration provides a very rough analysis on the origin of the failure. That is, each
114/// variant corresponds to one kind of actor causing the error. It should not be understood as a
115/// direct blame but can inform the search for a root cause or if such a search is required.
116#[derive(Debug)]
117pub enum DecodingError {
118    /// An error in IO of the underlying reader.
119    ///
120    /// Note that some IO errors may be recoverable - decoding may be retried after the
121    /// error is resolved.  For example, decoding from a slow stream of data (e.g. decoding from a
122    /// network stream) may occasionally result in [std::io::ErrorKind::UnexpectedEof] kind of
123    /// error, but decoding can resume when more data becomes available.
124    IoError(io::Error),
125    /// The input image was not a valid PNG.
126    ///
127    /// There isn't a lot that can be done here, except if the program itself was responsible for
128    /// creating this image then investigate the generator. This is internally implemented with a
129    /// large Enum. If You are interested in accessing some of the more exact information on the
130    /// variant then we can discuss in an issue.
131    Format(FormatError),
132    /// An interface was used incorrectly.
133    ///
134    /// This is used in cases where it's expected that the programmer might trip up and stability
135    /// could be affected. For example when:
136    ///
137    /// * The decoder is polled for more animation frames despite being done (or not being animated
138    ///   in the first place).
139    /// * The output buffer does not have the required size.
140    ///
141    /// As a rough guideline for introducing new variants parts of the requirements are dynamically
142    /// derived from the (untrusted) input data while the other half is from the caller. In the
143    /// above cases the number of frames respectively the size is determined by the file while the
144    /// number of calls
145    ///
146    /// If you're an application you might want to signal that a bug report is appreciated.
147    Parameter(ParameterError),
148    /// The image would have required exceeding the limits configured with the decoder.
149    ///
150    /// Note that Your allocations, e.g. when reading into a pre-allocated buffer, is __NOT__
151    /// considered part of the limits. Nevertheless, required intermediate buffers such as for
152    /// singular lines is checked against the limit.
153    ///
154    /// Note that this is a best-effort basis.
155    LimitsExceeded,
156}
157
158#[derive(Debug)]
159pub struct FormatError {
160    inner: FormatErrorInner,
161}
162
163#[derive(Debug)]
164pub(crate) enum FormatErrorInner {
165    /// Bad framing.
166    CrcMismatch {
167        /// Stored CRC32 value
168        crc_val: u32,
169        /// Calculated CRC32 sum
170        crc_sum: u32,
171        /// The chunk type that has the CRC mismatch.
172        chunk: ChunkType,
173    },
174    /// Not a PNG, the magic signature is missing.
175    InvalidSignature,
176    // Errors of chunk level ordering, missing etc.
177    /// Fctl must occur if an animated chunk occurs.
178    MissingFctl,
179    /// Image data that was indicated in IHDR or acTL is missing.
180    MissingImageData,
181    /// 4.3., Must be first.
182    ChunkBeforeIhdr {
183        kind: ChunkType,
184    },
185    /// 4.3., some chunks must be before IDAT.
186    AfterIdat {
187        kind: ChunkType,
188    },
189    // 4.3., Some chunks must be after PLTE.
190    BeforePlte {
191        kind: ChunkType,
192    },
193    /// 4.3., some chunks must be before PLTE.
194    AfterPlte {
195        kind: ChunkType,
196    },
197    /// 4.3., some chunks must be between PLTE and IDAT.
198    OutsidePlteIdat {
199        kind: ChunkType,
200    },
201    /// 4.3., some chunks must be unique.
202    DuplicateChunk {
203        kind: ChunkType,
204    },
205    /// Specifically for fdat there is an embedded sequence number for chunks.
206    ApngOrder {
207        /// The sequence number in the chunk.
208        present: u32,
209        /// The one that should have been present.
210        expected: u32,
211    },
212    // Errors specific to particular chunk data to be validated.
213    /// The palette did not even contain a single pixel data.
214    ShortPalette {
215        expected: usize,
216        len: usize,
217    },
218    /// sBIT chunk size based on color type.
219    InvalidSbitChunkSize {
220        color_type: ColorType,
221        expected: usize,
222        len: usize,
223    },
224    InvalidSbit {
225        sample_depth: BitDepth,
226        sbit: u8,
227    },
228    /// A palletized image did not have a palette.
229    PaletteRequired,
230    /// The color-depth combination is not valid according to Table 11.1.
231    InvalidColorBitDepth {
232        color_type: ColorType,
233        bit_depth: BitDepth,
234    },
235    ColorWithBadTrns(ColorType),
236    /// The image width or height is zero.
237    InvalidDimensions,
238    InvalidBitDepth(u8),
239    InvalidColorType(u8),
240    InvalidDisposeOp(u8),
241    InvalidBlendOp(u8),
242    InvalidUnit(u8),
243    /// The rendering intent of the sRGB chunk is invalid.
244    InvalidSrgbRenderingIntent(u8),
245    UnknownCompressionMethod(u8),
246    UnknownFilterMethod(u8),
247    UnknownInterlaceMethod(u8),
248    /// The subframe is not in bounds of the image.
249    /// TODO: fields with relevant data.
250    BadSubFrameBounds {},
251    // Errors specific to the IDAT/fdAT chunks.
252    /// The compression of the data stream was faulty.
253    CorruptFlateStream {
254        err: fdeflate::DecompressionError,
255    },
256    /// The image data chunk was too short for the expected pixel count.
257    NoMoreImageData,
258    /// Bad text encoding
259    BadTextEncoding(TextDecodingError),
260    /// fdAT shorter than 4 bytes
261    FdatShorterThanFourBytes,
262    /// "11.2.4 IDAT Image data" section of the PNG spec says: There may be multiple IDAT chunks;
263    /// if so, they shall appear consecutively with no other intervening chunks.
264    /// `UnexpectedRestartOfDataChunkSequence{kind: IDAT}` indicates that there were "intervening
265    /// chunks".
266    ///
267    /// The APNG spec doesn't directly describe an error similar to `CantInterleaveIdatChunks`,
268    /// but we require that a new sequence of consecutive `fdAT` chunks cannot appear unless we've
269    /// seen an `fcTL` chunk.
270    UnexpectedRestartOfDataChunkSequence {
271        kind: ChunkType,
272    },
273    /// Failure to parse a chunk, because the chunk had the wrong number of bytes.
274    ChunkLengthWrong {
275        kind: ChunkType,
276    },
277    UnrecognizedCriticalChunk {
278        /// The type of the unrecognized critical chunk.
279        type_str: ChunkType,
280    },
281    BadGammaValue,
282}
283
284impl error::Error for DecodingError {
285    fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
286        match self {
287            DecodingError::IoError(err) => Some(err),
288            _ => None,
289        }
290    }
291}
292
293impl fmt::Display for DecodingError {
294    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
295        use self::DecodingError::*;
296        match self {
297            IoError(err) => write!(fmt, "{}", err),
298            Parameter(desc) => write!(fmt, "{}", &desc),
299            Format(desc) => write!(fmt, "{}", desc),
300            LimitsExceeded => write!(fmt, "limits are exceeded"),
301        }
302    }
303}
304
305impl fmt::Display for FormatError {
306    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
307        use FormatErrorInner::*;
308        match &self.inner {
309            CrcMismatch {
310                crc_val,
311                crc_sum,
312                chunk,
313                ..
314            } => write!(
315                fmt,
316                "CRC error: expected 0x{:x} have 0x{:x} while decoding {:?} chunk.",
317                crc_val, crc_sum, chunk
318            ),
319            MissingFctl => write!(fmt, "fcTL chunk missing before fdAT chunk."),
320            MissingImageData => write!(fmt, "IDAT or fdAT chunk is missing."),
321            ChunkBeforeIhdr { kind } => write!(fmt, "{:?} chunk appeared before IHDR chunk", kind),
322            AfterIdat { kind } => write!(fmt, "Chunk {:?} is invalid after IDAT chunk.", kind),
323            BeforePlte { kind } => write!(fmt, "Chunk {:?} is invalid before PLTE chunk.", kind),
324            AfterPlte { kind } => write!(fmt, "Chunk {:?} is invalid after PLTE chunk.", kind),
325            OutsidePlteIdat { kind } => write!(
326                fmt,
327                "Chunk {:?} must appear between PLTE and IDAT chunks.",
328                kind
329            ),
330            DuplicateChunk { kind } => write!(fmt, "Chunk {:?} must appear at most once.", kind),
331            ApngOrder { present, expected } => write!(
332                fmt,
333                "Sequence is not in order, expected #{} got #{}.",
334                expected, present,
335            ),
336            ShortPalette { expected, len } => write!(
337                fmt,
338                "Not enough palette entries, expect {} got {}.",
339                expected, len
340            ),
341            InvalidSbitChunkSize {color_type, expected, len} => write!(
342                fmt,
343                "The size of the sBIT chunk should be {} byte(s), but {} byte(s) were provided for the {:?} color type.",
344                expected, len, color_type
345            ),
346            InvalidSbit {sample_depth, sbit} => write!(
347                fmt,
348                "Invalid sBIT value {}. It must be greater than zero and less than the sample depth {:?}.",
349                sbit, sample_depth
350            ),
351            PaletteRequired => write!(fmt, "Missing palette of indexed image."),
352            InvalidDimensions => write!(fmt, "Invalid image dimensions"),
353            InvalidColorBitDepth {
354                color_type,
355                bit_depth,
356            } => write!(
357                fmt,
358                "Invalid color/depth combination in header: {:?}/{:?}",
359                color_type, bit_depth,
360            ),
361            ColorWithBadTrns(color_type) => write!(
362                fmt,
363                "Transparency chunk found for color type {:?}.",
364                color_type
365            ),
366            InvalidBitDepth(nr) => write!(fmt, "Invalid bit depth {}.", nr),
367            InvalidColorType(nr) => write!(fmt, "Invalid color type {}.", nr),
368            InvalidDisposeOp(nr) => write!(fmt, "Invalid dispose op {}.", nr),
369            InvalidBlendOp(nr) => write!(fmt, "Invalid blend op {}.", nr),
370            InvalidUnit(nr) => write!(fmt, "Invalid physical pixel size unit {}.", nr),
371            InvalidSrgbRenderingIntent(nr) => write!(fmt, "Invalid sRGB rendering intent {}.", nr),
372            UnknownCompressionMethod(nr) => write!(fmt, "Unknown compression method {}.", nr),
373            UnknownFilterMethod(nr) => write!(fmt, "Unknown filter method {}.", nr),
374            UnknownInterlaceMethod(nr) => write!(fmt, "Unknown interlace method {}.", nr),
375            BadSubFrameBounds {} => write!(fmt, "Sub frame is out-of-bounds."),
376            InvalidSignature => write!(fmt, "Invalid PNG signature."),
377            NoMoreImageData => write!(
378                fmt,
379                "IDAT or fDAT chunk does not have enough data for image."
380            ),
381            CorruptFlateStream { err } => {
382                write!(fmt, "Corrupt deflate stream. ")?;
383                write!(fmt, "{:?}", err)
384            }
385            // TODO: Wrap more info in the enum variant
386            BadTextEncoding(tde) => {
387                match tde {
388                    TextDecodingError::Unrepresentable => {
389                        write!(fmt, "Unrepresentable data in tEXt chunk.")
390                    }
391                    TextDecodingError::InvalidKeywordSize => {
392                        write!(fmt, "Keyword empty or longer than 79 bytes.")
393                    }
394                    TextDecodingError::MissingNullSeparator => {
395                        write!(fmt, "No null separator in tEXt chunk.")
396                    }
397                    TextDecodingError::InflationError => {
398                        write!(fmt, "Invalid compressed text data.")
399                    }
400                    TextDecodingError::OutOfDecompressionSpace => {
401                        write!(fmt, "Out of decompression space. Try with a larger limit.")
402                    }
403                    TextDecodingError::InvalidCompressionMethod => {
404                        write!(fmt, "Using an unrecognized byte as compression method.")
405                    }
406                    TextDecodingError::InvalidCompressionFlag => {
407                        write!(fmt, "Using a flag that is not 0 or 255 as a compression flag for iTXt chunk.")
408                    }
409                    TextDecodingError::MissingCompressionFlag => {
410                        write!(fmt, "No compression flag in the iTXt chunk.")
411                    }
412                }
413            }
414            FdatShorterThanFourBytes => write!(fmt, "fdAT chunk shorter than 4 bytes"),
415            UnexpectedRestartOfDataChunkSequence { kind } => {
416                write!(fmt, "Unexpected restart of {:?} chunk sequence", kind)
417            }
418            ChunkLengthWrong { kind } => {
419                write!(fmt, "Chunk length wrong: {:?}", kind)
420            }
421            UnrecognizedCriticalChunk { type_str } => {
422                write!(fmt, "Unrecognized critical chunk: {:?}", type_str)
423            }
424            BadGammaValue => write!(fmt, "Bad gamma value."),
425        }
426    }
427}
428
429impl From<io::Error> for DecodingError {
430    fn from(err: io::Error) -> DecodingError {
431        DecodingError::IoError(err)
432    }
433}
434
435impl From<FormatError> for DecodingError {
436    fn from(err: FormatError) -> DecodingError {
437        DecodingError::Format(err)
438    }
439}
440
441impl From<FormatErrorInner> for FormatError {
442    fn from(inner: FormatErrorInner) -> Self {
443        FormatError { inner }
444    }
445}
446
447impl From<DecodingError> for io::Error {
448    fn from(err: DecodingError) -> io::Error {
449        match err {
450            DecodingError::IoError(err) => err,
451            err => io::Error::new(io::ErrorKind::Other, err.to_string()),
452        }
453    }
454}
455
456impl From<TextDecodingError> for DecodingError {
457    fn from(tbe: TextDecodingError) -> Self {
458        DecodingError::Format(FormatError {
459            inner: FormatErrorInner::BadTextEncoding(tbe),
460        })
461    }
462}
463
464/// Decoder configuration options
465#[derive(Clone)]
466pub struct DecodeOptions {
467    ignore_adler32: bool,
468    ignore_crc: bool,
469    ignore_text_chunk: bool,
470    ignore_iccp_chunk: bool,
471    skip_ancillary_crc_failures: bool,
472}
473
474impl Default for DecodeOptions {
475    fn default() -> Self {
476        Self {
477            ignore_adler32: true,
478            ignore_crc: false,
479            ignore_text_chunk: false,
480            ignore_iccp_chunk: false,
481            skip_ancillary_crc_failures: true,
482        }
483    }
484}
485
486impl DecodeOptions {
487    /// When set, the decoder will not compute and verify the Adler-32 checksum.
488    ///
489    /// Defaults to `true`.
490    pub fn set_ignore_adler32(&mut self, ignore_adler32: bool) {
491        self.ignore_adler32 = ignore_adler32;
492    }
493
494    /// When set, the decoder will not compute and verify the CRC code.
495    ///
496    /// Defaults to `false`.
497    pub fn set_ignore_crc(&mut self, ignore_crc: bool) {
498        self.ignore_crc = ignore_crc;
499    }
500
501    /// Flag to ignore computing and verifying the Adler-32 checksum and CRC
502    /// code.
503    pub fn set_ignore_checksums(&mut self, ignore_checksums: bool) {
504        self.ignore_adler32 = ignore_checksums;
505        self.ignore_crc = ignore_checksums;
506    }
507
508    /// Ignore text chunks while decoding.
509    ///
510    /// Defaults to `false`.
511    pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
512        self.ignore_text_chunk = ignore_text_chunk;
513    }
514
515    /// Ignore ICCP chunks while decoding.
516    ///
517    /// Defaults to `false`.
518    pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
519        self.ignore_iccp_chunk = ignore_iccp_chunk;
520    }
521
522    /// Ignore ancillary chunks if CRC fails
523    ///
524    /// Defaults to `true`
525    pub fn set_skip_ancillary_crc_failures(&mut self, skip_ancillary_crc_failures: bool) {
526        self.skip_ancillary_crc_failures = skip_ancillary_crc_failures;
527    }
528}
529
530/// PNG StreamingDecoder (low-level interface)
531///
532/// By default, the decoder does not verify Adler-32 checksum computation. To
533/// enable checksum verification, set it with [`StreamingDecoder::set_ignore_adler32`]
534/// before starting decompression.
535pub struct StreamingDecoder {
536    state: Option<State>,
537    current_chunk: ChunkState,
538    /// The inflater state handling consecutive `IDAT` and `fdAT` chunks.
539    inflater: ZlibStream,
540    /// The complete image info read from all prior chunks.
541    pub(crate) info: Option<Info<'static>>,
542    /// The animation chunk sequence number.
543    current_seq_no: Option<u32>,
544    /// Whether we have already seen a start of an IDAT chunk.  (Used to validate chunk ordering -
545    /// some chunk types can only appear before or after an IDAT chunk.)
546    have_idat: bool,
547    /// Whether we are ready for a start of an `IDAT` chunk sequence.  Initially `true` and set to
548    /// `false` when the first sequence of consecutive `IDAT` chunks ends.
549    ready_for_idat_chunks: bool,
550    /// Whether we are ready for a start of an `fdAT` chunk sequence.  Initially `false`.  Set to
551    /// `true` after encountering an `fcTL` chunk. Set to `false` when a sequence of consecutive
552    /// `fdAT` chunks ends.
553    ready_for_fdat_chunks: bool,
554    /// Whether we have already seen an iCCP chunk. Used to prevent parsing of duplicate iCCP chunks.
555    have_iccp: bool,
556    decode_options: DecodeOptions,
557    pub(crate) limits: Limits,
558}
559
560struct ChunkState {
561    /// The type of the current chunk.
562    /// Relevant for `IDAT` and `fdAT` which aggregate consecutive chunks of their own type.
563    type_: ChunkType,
564
565    /// Partial crc until now.
566    crc: Crc32,
567
568    /// Remaining bytes to be read.
569    remaining: u32,
570
571    /// Non-decoded bytes in the chunk.
572    raw_bytes: Vec<u8>,
573
574    /// Whether this chunk should be skipped or decoded.
575    action: ChunkAction,
576}
577
578#[derive(Debug, PartialEq)]
579enum ChunkAction {
580    Process,
581    Skip,
582    Reject,
583}
584
585impl StreamingDecoder {
586    /// Creates a new StreamingDecoder
587    ///
588    /// Allocates the internal buffers.
589    pub fn new() -> StreamingDecoder {
590        StreamingDecoder::new_with_options(DecodeOptions::default())
591    }
592
593    pub fn new_with_options(decode_options: DecodeOptions) -> StreamingDecoder {
594        let mut inflater = ZlibStream::new();
595        inflater.set_ignore_adler32(decode_options.ignore_adler32);
596
597        StreamingDecoder {
598            state: Some(State::new_u32(U32ValueKind::Signature1stU32)),
599            current_chunk: ChunkState {
600                type_: ChunkType([0; 4]),
601                crc: Crc32::new(),
602                remaining: 0,
603                raw_bytes: Vec::with_capacity(CHUNK_BUFFER_SIZE),
604                action: ChunkAction::Process,
605            },
606            inflater,
607            info: None,
608            current_seq_no: None,
609            have_idat: false,
610            have_iccp: false,
611            ready_for_idat_chunks: true,
612            ready_for_fdat_chunks: false,
613            decode_options,
614            limits: Limits { bytes: usize::MAX },
615        }
616    }
617
618    /// Resets the StreamingDecoder
619    pub fn reset(&mut self) {
620        self.state = Some(State::new_u32(U32ValueKind::Signature1stU32));
621        self.current_chunk.crc = Crc32::new();
622        self.current_chunk.remaining = 0;
623        self.current_chunk.raw_bytes.clear();
624        self.inflater.reset();
625        self.info = None;
626        self.current_seq_no = None;
627        self.have_idat = false;
628    }
629
630    /// Provides access to the inner `info` field
631    pub fn info(&self) -> Option<&Info<'static>> {
632        self.info.as_ref()
633    }
634
635    pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
636        self.decode_options.set_ignore_text_chunk(ignore_text_chunk);
637    }
638
639    pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
640        self.decode_options.set_ignore_iccp_chunk(ignore_iccp_chunk);
641    }
642
643    /// Return whether the decoder is set to ignore the Adler-32 checksum.
644    pub fn ignore_adler32(&self) -> bool {
645        self.inflater.ignore_adler32()
646    }
647
648    /// Set whether to compute and verify the Adler-32 checksum during
649    /// decompression. Return `true` if the flag was successfully set.
650    ///
651    /// The decoder defaults to `true`.
652    ///
653    /// This flag cannot be modified after decompression has started until the
654    /// [`StreamingDecoder`] is reset.
655    pub fn set_ignore_adler32(&mut self, ignore_adler32: bool) -> bool {
656        self.inflater.set_ignore_adler32(ignore_adler32)
657    }
658
659    /// Set whether to compute and verify the Adler-32 checksum during
660    /// decompression.
661    ///
662    /// The decoder defaults to `false`.
663    pub fn set_ignore_crc(&mut self, ignore_crc: bool) {
664        self.decode_options.set_ignore_crc(ignore_crc)
665    }
666
667    /// Ignore ancillary chunks if CRC fails
668    ///
669    /// Defaults to `true`
670    pub fn set_skip_ancillary_crc_failures(&mut self, skip_ancillary_crc_failures: bool) {
671        self.decode_options
672            .set_skip_ancillary_crc_failures(skip_ancillary_crc_failures)
673    }
674
675    /// Low level StreamingDecoder interface.
676    ///
677    /// Allows to stream partial data to the encoder. Returns a tuple containing the bytes that have
678    /// been consumed from the input buffer and the current decoding result. If the decoded chunk
679    /// was an image data chunk, it also appends the read data to `image_data`.
680    pub fn update(
681        &mut self,
682        mut buf: &[u8],
683        mut image_data: Option<&mut UnfilterBuf<'_>>,
684    ) -> Result<(usize, Decoded), DecodingError> {
685        if self.state.is_none() {
686            return Err(DecodingError::Parameter(
687                ParameterErrorKind::PolledAfterFatalError.into(),
688            ));
689        }
690
691        let len = buf.len();
692        while !buf.is_empty() {
693            let image_data = image_data.as_deref_mut();
694
695            match self.next_state(buf, image_data) {
696                Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..],
697                Ok((bytes, result)) => {
698                    buf = &buf[bytes..];
699                    return Ok((len - buf.len(), result));
700                }
701                Err(err) => {
702                    debug_assert!(self.state.is_none());
703                    return Err(err);
704                }
705            }
706        }
707        Ok((len - buf.len(), Decoded::Nothing))
708    }
709
710    fn next_state(
711        &mut self,
712        buf: &[u8],
713        image_data: Option<&mut UnfilterBuf<'_>>,
714    ) -> Result<(usize, Decoded), DecodingError> {
715        use self::State::*;
716
717        // Driver should ensure that state is never None
718        let state = self.state.take().unwrap();
719
720        match state {
721            U32 {
722                kind,
723                mut bytes,
724                mut accumulated_count,
725            } => {
726                debug_assert!(accumulated_count <= 4);
727                if accumulated_count == 0 && buf.len() >= 4 {
728                    // Handling these `accumulated_count` and `buf.len()` values in a separate `if`
729                    // branch is not strictly necessary - the `else` statement below is already
730                    // capable of handling these values.  The main reason for special-casing these
731                    // values is that they occur fairly frequently and special-casing them results
732                    // in performance gains.
733                    const CONSUMED_BYTES: usize = 4;
734                    self.parse_u32(kind, &buf[0..4], image_data, CONSUMED_BYTES)
735                } else {
736                    let remaining_count = 4 - accumulated_count;
737                    let consumed_bytes = {
738                        let available_count = min(remaining_count, buf.len());
739                        bytes[accumulated_count..accumulated_count + available_count]
740                            .copy_from_slice(&buf[0..available_count]);
741                        accumulated_count += available_count;
742                        available_count
743                    };
744
745                    if accumulated_count < 4 {
746                        self.state = Some(U32 {
747                            kind,
748                            bytes,
749                            accumulated_count,
750                        });
751                        Ok((consumed_bytes, Decoded::Nothing))
752                    } else {
753                        debug_assert_eq!(accumulated_count, 4);
754                        self.parse_u32(kind, &bytes, image_data, consumed_bytes)
755                    }
756                }
757            }
758            ReadChunkData(type_str) => {
759                debug_assert!(type_str != IDAT && type_str != chunk::fdAT);
760                if self.current_chunk.remaining == 0 {
761                    self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
762                    Ok((0, Decoded::Nothing))
763                } else {
764                    let ChunkState {
765                        crc,
766                        remaining,
767                        raw_bytes,
768                        type_: _,
769                        action,
770                    } = &mut self.current_chunk;
771
772                    let buf_avail = raw_bytes.capacity() - raw_bytes.len();
773                    let bytes_avail = min(buf.len(), buf_avail);
774                    let n = min(*remaining, bytes_avail as u32);
775                    let buf = &buf[..n as usize];
776
777                    if !self.decode_options.ignore_crc {
778                        crc.update(buf);
779                    }
780
781                    if *action == ChunkAction::Process {
782                        if raw_bytes.len() == raw_bytes.capacity() {
783                            if self.limits.bytes == 0 {
784                                return Err(DecodingError::LimitsExceeded);
785                            }
786
787                            // Double the size of the Vec, but not beyond the allocation limit.
788                            debug_assert!(raw_bytes.capacity() > 0);
789                            let reserve_size = raw_bytes.capacity().min(self.limits.bytes);
790
791                            self.limits.reserve_bytes(reserve_size)?;
792                            raw_bytes.reserve_exact(reserve_size);
793                        }
794                        raw_bytes.extend_from_slice(buf);
795                    }
796
797                    *remaining -= n;
798                    if *remaining == 0 {
799                        debug_assert!(type_str != IDAT && type_str != chunk::fdAT);
800                        self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
801                    } else {
802                        self.state = Some(ReadChunkData(type_str));
803                    }
804                    Ok((n as usize, Decoded::Nothing))
805                }
806            }
807            ImageData(type_str) => {
808                debug_assert!(type_str == IDAT || type_str == chunk::fdAT);
809                let len = std::cmp::min(buf.len(), self.current_chunk.remaining as usize);
810                let buf = &buf[..len];
811
812                let consumed = if let Some(image_data) = image_data {
813                    self.inflater.decompress(buf, image_data)?
814                } else {
815                    len
816                };
817
818                if !self.decode_options.ignore_crc {
819                    self.current_chunk.crc.update(&buf[..consumed]);
820                }
821
822                self.current_chunk.remaining -= consumed as u32;
823                if self.current_chunk.remaining == 0 {
824                    self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
825                } else {
826                    self.state = Some(ImageData(type_str));
827                }
828                Ok((consumed, Decoded::ImageData))
829            }
830        }
831    }
832
833    fn parse_u32(
834        &mut self,
835        kind: U32ValueKind,
836        u32_be_bytes: &[u8],
837        image_data: Option<&mut UnfilterBuf<'_>>,
838        consumed_bytes: usize,
839    ) -> Result<(usize, Decoded), DecodingError> {
840        debug_assert_eq!(u32_be_bytes.len(), 4);
841        let bytes = u32_be_bytes.try_into().unwrap();
842        let val = u32::from_be_bytes(bytes);
843
844        match kind {
845            U32ValueKind::Signature1stU32 => {
846                if bytes == [137, 80, 78, 71] {
847                    self.state = Some(State::new_u32(U32ValueKind::Signature2ndU32));
848                    Ok((consumed_bytes, Decoded::Nothing))
849                } else {
850                    Err(DecodingError::Format(
851                        FormatErrorInner::InvalidSignature.into(),
852                    ))
853                }
854            }
855            U32ValueKind::Signature2ndU32 => {
856                if bytes == [13, 10, 26, 10] {
857                    self.state = Some(State::new_u32(U32ValueKind::Length));
858                    Ok((consumed_bytes, Decoded::Nothing))
859                } else {
860                    Err(DecodingError::Format(
861                        FormatErrorInner::InvalidSignature.into(),
862                    ))
863                }
864            }
865            U32ValueKind::Length => {
866                self.state = Some(State::new_u32(U32ValueKind::Type { length: val }));
867                Ok((consumed_bytes, Decoded::Nothing))
868            }
869            U32ValueKind::Type { length } => {
870                let type_str = ChunkType(bytes);
871                if self.info.is_none() && type_str != IHDR {
872                    return Err(DecodingError::Format(
873                        FormatErrorInner::ChunkBeforeIhdr { kind: type_str }.into(),
874                    ));
875                }
876                if type_str != self.current_chunk.type_
877                    && (self.current_chunk.type_ == IDAT || self.current_chunk.type_ == chunk::fdAT)
878                {
879                    let finished = match image_data {
880                        Some(image_data) => self.inflater.finish(image_data)?,
881                        None => true,
882                    };
883
884                    // We ended up handling IDAT/fdAT data rather than the chunk
885                    // type header atually received. Thus rewind `self.state` to
886                    // what it was before this function was called.
887                    self.state = Some(State::U32 {
888                        kind,
889                        bytes,
890                        accumulated_count: 4 - consumed_bytes,
891                    });
892
893                    if finished {
894                        // We've processed all the image data necessary. Update
895                        // `current_chunk.type_`so this codepath isn't taken
896                        // again next time.
897                        self.current_chunk.type_ = type_str;
898                        self.ready_for_idat_chunks = false;
899                        self.ready_for_fdat_chunks = false;
900                        return Ok((0, Decoded::ImageDataFlushed));
901                    } else {
902                        // Report that we processed some image data without
903                        // consuming any input. This gives the caller a chance
904                        // to grow the output buffer and call us again.
905                        return Ok((0, Decoded::ImageData));
906                    }
907                }
908
909                self.current_chunk.type_ = type_str;
910                if !self.decode_options.ignore_crc {
911                    self.current_chunk.crc.reset();
912                    self.current_chunk.crc.update(&type_str.0);
913                }
914                self.current_chunk.remaining = length;
915                self.current_chunk.raw_bytes.clear();
916
917                self.state = match type_str {
918                    chunk::fdAT => {
919                        if !self.ready_for_fdat_chunks {
920                            return Err(DecodingError::Format(
921                                FormatErrorInner::UnexpectedRestartOfDataChunkSequence {
922                                    kind: chunk::fdAT,
923                                }
924                                .into(),
925                            ));
926                        }
927                        if length < 4 {
928                            return Err(DecodingError::Format(
929                                FormatErrorInner::FdatShorterThanFourBytes.into(),
930                            ));
931                        }
932                        self.current_chunk.action = ChunkAction::Process;
933                        Some(State::new_u32(U32ValueKind::ApngSequenceNumber))
934                    }
935                    IDAT => {
936                        if !self.ready_for_idat_chunks {
937                            return Err(DecodingError::Format(
938                                FormatErrorInner::UnexpectedRestartOfDataChunkSequence {
939                                    kind: IDAT,
940                                }
941                                .into(),
942                            ));
943                        }
944                        self.have_idat = true;
945                        self.current_chunk.action = ChunkAction::Process;
946                        Some(State::ImageData(type_str))
947                    }
948                    _ => Some(self.start_chunk(type_str, length)?),
949                };
950                Ok((consumed_bytes, Decoded::ChunkBegin(length, type_str)))
951            }
952            U32ValueKind::Crc(type_str) => {
953                // If ignore_crc is set, do not calculate CRC. We set
954                // sum=val so that it short-circuits to true in the next
955                // if-statement block
956                let sum = if self.decode_options.ignore_crc {
957                    val
958                } else {
959                    self.current_chunk.crc.clone().finalize()
960                };
961
962                if val == sum || CHECKSUM_DISABLED {
963                    match self.current_chunk.action {
964                        ChunkAction::Process => {
965                            // A fatal error in chunk parsing leaves the decoder in state 'None' to enforce
966                            // that parsing can't continue after an error.
967                            debug_assert!(self.state.is_none());
968                            let decoded = self.parse_chunk(type_str)?;
969
970                            if type_str != IEND {
971                                self.state = Some(State::new_u32(U32ValueKind::Length));
972                            }
973                            Ok((consumed_bytes, decoded))
974                        }
975                        ChunkAction::Skip => {
976                            self.state = Some(State::new_u32(U32ValueKind::Length));
977                            Ok((
978                                consumed_bytes,
979                                Decoded::SkippedAncillaryChunk(self.current_chunk.type_),
980                            ))
981                        }
982                        ChunkAction::Reject => {
983                            self.state = Some(State::new_u32(U32ValueKind::Length));
984                            Ok((consumed_bytes, Decoded::BadAncillaryChunk(type_str)))
985                        }
986                    }
987                } else if self.decode_options.skip_ancillary_crc_failures
988                    && !chunk::is_critical(type_str)
989                {
990                    // Ignore ancillary chunk with invalid CRC
991                    self.state = Some(State::new_u32(U32ValueKind::Length));
992                    Ok((consumed_bytes, Decoded::BadAncillaryChunk(type_str)))
993                } else {
994                    Err(DecodingError::Format(
995                        FormatErrorInner::CrcMismatch {
996                            crc_val: val,
997                            crc_sum: sum,
998                            chunk: type_str,
999                        }
1000                        .into(),
1001                    ))
1002                }
1003            }
1004            U32ValueKind::ApngSequenceNumber => {
1005                debug_assert_eq!(self.current_chunk.type_, chunk::fdAT);
1006                let next_seq_no = val;
1007
1008                // Should be verified by the FdatShorterThanFourBytes check earlier.
1009                debug_assert!(self.current_chunk.remaining >= 4);
1010                self.current_chunk.remaining -= 4;
1011
1012                if let Some(seq_no) = self.current_seq_no {
1013                    if next_seq_no != seq_no + 1 {
1014                        return Err(DecodingError::Format(
1015                            FormatErrorInner::ApngOrder {
1016                                present: next_seq_no,
1017                                expected: seq_no + 1,
1018                            }
1019                            .into(),
1020                        ));
1021                    }
1022                    self.current_seq_no = Some(next_seq_no);
1023                } else {
1024                    return Err(DecodingError::Format(FormatErrorInner::MissingFctl.into()));
1025                }
1026
1027                if !self.decode_options.ignore_crc {
1028                    let data = next_seq_no.to_be_bytes();
1029                    self.current_chunk.crc.update(&data);
1030                }
1031
1032                self.state = Some(State::ImageData(chunk::fdAT));
1033                Ok((consumed_bytes, Decoded::Nothing))
1034            }
1035        }
1036    }
1037
1038    fn start_chunk(&mut self, type_str: ChunkType, length: u32) -> Result<State, DecodingError> {
1039        let target_length = match type_str {
1040            IHDR => 13..=13,
1041            chunk::PLTE => 3..=768,
1042            chunk::IEND => 0..=0,
1043            chunk::sBIT => 1..=4,
1044            chunk::tRNS => 1..=256,
1045            chunk::pHYs => 9..=9,
1046            chunk::gAMA => 4..=4,
1047            chunk::acTL => 8..=8,
1048            chunk::fcTL => 26..=26,
1049            chunk::cHRM => 32..=32,
1050            chunk::sRGB => 1..=1,
1051            chunk::cICP => 4..=4,
1052            chunk::mDCV => 24..=24,
1053            chunk::cLLI => 8..=8,
1054            chunk::bKGD => 1..=6,
1055
1056            // Unbounded size chunks
1057            chunk::eXIf => 0..=u32::MAX >> 1, // TODO: allow skipping.
1058            chunk::iCCP if !self.decode_options.ignore_iccp_chunk => 0..=u32::MAX >> 1,
1059            chunk::tEXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1,
1060            chunk::zTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1,
1061            chunk::iTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1,
1062
1063            chunk::IDAT | chunk::fdAT => unreachable!(),
1064
1065            _ if is_critical(type_str) => {
1066                return Err(DecodingError::Format(
1067                    FormatErrorInner::UnrecognizedCriticalChunk { type_str }.into(),
1068                ));
1069            }
1070            _ => {
1071                self.current_chunk.action = ChunkAction::Skip;
1072                return Ok(State::ReadChunkData(type_str));
1073            }
1074        };
1075
1076        if !target_length.contains(&length) {
1077            // Uncomment to detect unexpected chunk lengths during testing.
1078            // panic!("chunk type_str={type_str:?} has length={length}, target_length={target_length:?}");
1079            match type_str {
1080                IHDR | chunk::PLTE | chunk::IEND | chunk::fcTL => {
1081                    return Err(DecodingError::Format(
1082                        FormatErrorInner::ChunkLengthWrong { kind: type_str }.into(),
1083                    ));
1084                }
1085                _ => {
1086                    self.current_chunk.action = ChunkAction::Reject;
1087                }
1088            }
1089        } else {
1090            self.current_chunk.action = ChunkAction::Process;
1091        }
1092
1093        Ok(State::ReadChunkData(type_str))
1094    }
1095
1096    fn parse_chunk(&mut self, type_str: ChunkType) -> Result<Decoded, DecodingError> {
1097        let mut parse_result = match type_str {
1098            // Critical non-data chunks.
1099            IHDR => self.parse_ihdr(),
1100            chunk::PLTE => self.parse_plte(),
1101            chunk::IEND => Ok(()), // TODO: Check chunk size.
1102
1103            // Data chunks handled separately.
1104            chunk::IDAT => Ok(()),
1105            chunk::fdAT => Ok(()),
1106
1107            // Recognized bounded-size ancillary chunks.
1108            chunk::sBIT => self.parse_sbit(),
1109            chunk::tRNS => self.parse_trns(),
1110            chunk::pHYs => self.parse_phys(),
1111            chunk::gAMA => self.parse_gama(),
1112            chunk::acTL => self.parse_actl(),
1113            chunk::fcTL => self.parse_fctl(),
1114            chunk::cHRM => self.parse_chrm(),
1115            chunk::sRGB => self.parse_srgb(),
1116            chunk::cICP => self.parse_cicp(),
1117            chunk::mDCV => self.parse_mdcv(),
1118            chunk::cLLI => self.parse_clli(),
1119            chunk::bKGD => self.parse_bkgd(),
1120
1121            // Ancillary chunks with unbounded size.
1122            chunk::eXIf => self.parse_exif(),
1123            chunk::iCCP => self.parse_iccp(),
1124            chunk::tEXt => self.parse_text(),
1125            chunk::zTXt => self.parse_ztxt(),
1126            chunk::iTXt => self.parse_itxt(),
1127
1128            // Unrecognized chunks.
1129            _ => unreachable!(
1130                "Unrecognized chunk {type_str:?} should have been caught in start_chunk"
1131            ),
1132        };
1133
1134        parse_result = parse_result.map_err(|e| {
1135            match e {
1136                // `parse_chunk` is invoked after gathering **all** bytes of a chunk, so
1137                // `UnexpectedEof` from something like `read_be` is permanent and indicates an
1138                // invalid PNG that should be represented as a `FormatError`, rather than as a
1139                // (potentially recoverable) `IoError` / `UnexpectedEof`.
1140                DecodingError::IoError(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
1141                    let fmt_err: FormatError =
1142                        FormatErrorInner::ChunkLengthWrong { kind: type_str }.into();
1143                    fmt_err.into()
1144                }
1145                e => e,
1146            }
1147        });
1148
1149        match parse_result {
1150            Ok(()) => Ok(Decoded::ChunkComplete(type_str)),
1151            Err(DecodingError::Format(_))
1152                if type_str != chunk::fcTL && !chunk::is_critical(type_str) =>
1153            {
1154                // Ignore benign errors in most auxiliary chunks. `LimitsExceeded`, `Parameter` and
1155                // other error kinds are *not* treated as benign. We don't ignore errors in `fcTL`
1156                // chunks because the fallback to the static/non-animated image has to be
1157                // implemented *on top* of the `StreamingDecoder` API.
1158                //
1159                // TODO: Consider supporting a strict mode where even benign errors are reported up.
1160                // See https://github.com/image-rs/image-png/pull/569#issuecomment-2642062285
1161                Ok(Decoded::BadAncillaryChunk(type_str))
1162            }
1163            Err(e) => Err(e),
1164        }
1165    }
1166
1167    fn parse_fctl(&mut self) -> Result<(), DecodingError> {
1168        let mut buf = &self.current_chunk.raw_bytes[..];
1169        let next_seq_no = buf.read_be()?;
1170
1171        // Assuming that fcTL is required before *every* fdAT-sequence
1172        self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no {
1173            if next_seq_no != seq_no + 1 {
1174                return Err(DecodingError::Format(
1175                    FormatErrorInner::ApngOrder {
1176                        expected: seq_no + 1,
1177                        present: next_seq_no,
1178                    }
1179                    .into(),
1180                ));
1181            }
1182            next_seq_no
1183        } else {
1184            if next_seq_no != 0 {
1185                return Err(DecodingError::Format(
1186                    FormatErrorInner::ApngOrder {
1187                        expected: 0,
1188                        present: next_seq_no,
1189                    }
1190                    .into(),
1191                ));
1192            }
1193            0
1194        });
1195        self.inflater.reset();
1196        self.ready_for_fdat_chunks = self.have_idat;
1197        let fc = FrameControl {
1198            sequence_number: next_seq_no,
1199            width: buf.read_be()?,
1200            height: buf.read_be()?,
1201            x_offset: buf.read_be()?,
1202            y_offset: buf.read_be()?,
1203            delay_num: buf.read_be()?,
1204            delay_den: buf.read_be()?,
1205            dispose_op: {
1206                let dispose_op = buf.read_be()?;
1207                match DisposeOp::from_u8(dispose_op) {
1208                    Some(dispose_op) => dispose_op,
1209                    None => {
1210                        return Err(DecodingError::Format(
1211                            FormatErrorInner::InvalidDisposeOp(dispose_op).into(),
1212                        ))
1213                    }
1214                }
1215            },
1216            blend_op: {
1217                let blend_op = buf.read_be()?;
1218                match BlendOp::from_u8(blend_op) {
1219                    Some(blend_op) => blend_op,
1220                    None => {
1221                        return Err(DecodingError::Format(
1222                            FormatErrorInner::InvalidBlendOp(blend_op).into(),
1223                        ))
1224                    }
1225                }
1226            },
1227        };
1228        self.info.as_ref().unwrap().validate(&fc)?;
1229        if !self.have_idat {
1230            self.info.as_ref().unwrap().validate_default_image(&fc)?;
1231        }
1232        self.info.as_mut().unwrap().frame_control = Some(fc);
1233        Ok(())
1234    }
1235
1236    fn parse_actl(&mut self) -> Result<(), DecodingError> {
1237        let info = self.info.as_mut().unwrap();
1238        if self.have_idat {
1239            Err(DecodingError::Format(
1240                FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(),
1241            ))
1242        } else if info.animation_control.is_some() {
1243            Err(DecodingError::Format(
1244                FormatErrorInner::DuplicateChunk { kind: chunk::acTL }.into(),
1245            ))
1246        } else {
1247            let mut buf = &self.current_chunk.raw_bytes[..];
1248            let actl = AnimationControl {
1249                num_frames: buf.read_be()?,
1250                num_plays: buf.read_be()?,
1251            };
1252            // The spec says that "0 is not a valid value" for `num_frames`.
1253            // So let's ignore such malformed `acTL` chunks.
1254            if actl.num_frames == 0 {
1255                return Ok(());
1256            }
1257
1258            // The spec also says that the number of frames and number of plays should be limited
1259            // to (2^31)-1. Same as the other condition we enforce it by ignoring the chunk.
1260            // Another option may be saturation which would lose us some frames but encourage
1261            // rather dubious handling.
1262            if actl.num_frames > 0x7FFFFFFF || actl.num_plays > 0x7FFFFFFF {
1263                return Ok(());
1264            }
1265
1266            info.animation_control = Some(actl);
1267            Ok(())
1268        }
1269    }
1270
1271    fn parse_plte(&mut self) -> Result<(), DecodingError> {
1272        let info = self.info.as_mut().unwrap();
1273        if info.palette.is_some() {
1274            // Only one palette is allowed
1275            Err(DecodingError::Format(
1276                FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(),
1277            ))
1278        } else {
1279            info.palette = Some(Cow::Owned(self.current_chunk.raw_bytes.clone()));
1280            Ok(())
1281        }
1282    }
1283
1284    fn parse_sbit(&mut self) -> Result<(), DecodingError> {
1285        let info = self.info.as_mut().unwrap();
1286        if info.palette.is_some() {
1287            return Err(DecodingError::Format(
1288                FormatErrorInner::AfterPlte { kind: chunk::sBIT }.into(),
1289            ));
1290        }
1291
1292        if self.have_idat {
1293            return Err(DecodingError::Format(
1294                FormatErrorInner::AfterIdat { kind: chunk::sBIT }.into(),
1295            ));
1296        }
1297
1298        if info.sbit.is_some() {
1299            return Err(DecodingError::Format(
1300                FormatErrorInner::DuplicateChunk { kind: chunk::sBIT }.into(),
1301            ));
1302        }
1303
1304        let (color_type, bit_depth) = { (info.color_type, info.bit_depth) };
1305        // The sample depth for color type 3 is fixed at eight bits.
1306        let sample_depth = if color_type == ColorType::Indexed {
1307            BitDepth::Eight
1308        } else {
1309            bit_depth
1310        };
1311        let vec = self.current_chunk.raw_bytes.clone();
1312        let len = vec.len();
1313
1314        // expected lenth of the chunk
1315        let expected = match color_type {
1316            ColorType::Grayscale => 1,
1317            ColorType::Rgb | ColorType::Indexed => 3,
1318            ColorType::GrayscaleAlpha => 2,
1319            ColorType::Rgba => 4,
1320        };
1321
1322        // Check if the sbit chunk size is valid.
1323        if expected != len {
1324            return Err(DecodingError::Format(
1325                FormatErrorInner::InvalidSbitChunkSize {
1326                    color_type,
1327                    expected,
1328                    len,
1329                }
1330                .into(),
1331            ));
1332        }
1333
1334        for sbit in &vec {
1335            if *sbit < 1 || *sbit > sample_depth as u8 {
1336                return Err(DecodingError::Format(
1337                    FormatErrorInner::InvalidSbit {
1338                        sample_depth,
1339                        sbit: *sbit,
1340                    }
1341                    .into(),
1342                ));
1343            }
1344        }
1345        info.sbit = Some(Cow::Owned(vec));
1346        Ok(())
1347    }
1348
1349    fn parse_trns(&mut self) -> Result<(), DecodingError> {
1350        let info = self.info.as_mut().unwrap();
1351        if info.trns.is_some() {
1352            return Err(DecodingError::Format(
1353                FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(),
1354            ));
1355        }
1356        let (color_type, bit_depth) = { (info.color_type, info.bit_depth as u8) };
1357        let mut vec = self.current_chunk.raw_bytes.clone();
1358        let len = vec.len();
1359        match color_type {
1360            ColorType::Grayscale => {
1361                if len < 2 {
1362                    return Err(DecodingError::Format(
1363                        FormatErrorInner::ShortPalette { expected: 2, len }.into(),
1364                    ));
1365                }
1366                if bit_depth < 16 {
1367                    vec[0] = vec[1];
1368                    vec.truncate(1);
1369                }
1370                info.trns = Some(Cow::Owned(vec));
1371                Ok(())
1372            }
1373            ColorType::Rgb => {
1374                if len < 6 {
1375                    return Err(DecodingError::Format(
1376                        FormatErrorInner::ShortPalette { expected: 6, len }.into(),
1377                    ));
1378                }
1379                if bit_depth < 16 {
1380                    vec[0] = vec[1];
1381                    vec[1] = vec[3];
1382                    vec[2] = vec[5];
1383                    vec.truncate(3);
1384                }
1385                info.trns = Some(Cow::Owned(vec));
1386                Ok(())
1387            }
1388            ColorType::Indexed => {
1389                // The transparency chunk must be after the palette chunk and
1390                // before the data chunk.
1391                if info.palette.is_none() {
1392                    return Err(DecodingError::Format(
1393                        FormatErrorInner::BeforePlte { kind: chunk::tRNS }.into(),
1394                    ));
1395                } else if self.have_idat {
1396                    return Err(DecodingError::Format(
1397                        FormatErrorInner::OutsidePlteIdat { kind: chunk::tRNS }.into(),
1398                    ));
1399                }
1400
1401                info.trns = Some(Cow::Owned(vec));
1402                Ok(())
1403            }
1404            c => Err(DecodingError::Format(
1405                FormatErrorInner::ColorWithBadTrns(c).into(),
1406            )),
1407        }
1408    }
1409
1410    fn parse_phys(&mut self) -> Result<(), DecodingError> {
1411        let info = self.info.as_mut().unwrap();
1412        if self.have_idat {
1413            Err(DecodingError::Format(
1414                FormatErrorInner::AfterIdat { kind: chunk::pHYs }.into(),
1415            ))
1416        } else if info.pixel_dims.is_some() {
1417            Err(DecodingError::Format(
1418                FormatErrorInner::DuplicateChunk { kind: chunk::pHYs }.into(),
1419            ))
1420        } else {
1421            let mut buf = &self.current_chunk.raw_bytes[..];
1422            let xppu = buf.read_be()?;
1423            let yppu = buf.read_be()?;
1424            let unit = buf.read_be()?;
1425            let unit = match Unit::from_u8(unit) {
1426                Some(unit) => unit,
1427                None => {
1428                    return Err(DecodingError::Format(
1429                        FormatErrorInner::InvalidUnit(unit).into(),
1430                    ))
1431                }
1432            };
1433            let pixel_dims = PixelDimensions { xppu, yppu, unit };
1434            info.pixel_dims = Some(pixel_dims);
1435            Ok(())
1436        }
1437    }
1438
1439    fn parse_chrm(&mut self) -> Result<(), DecodingError> {
1440        let info = self.info.as_mut().unwrap();
1441        if self.have_idat {
1442            Err(DecodingError::Format(
1443                FormatErrorInner::AfterIdat { kind: chunk::cHRM }.into(),
1444            ))
1445        } else if info.chrm_chunk.is_some() {
1446            Err(DecodingError::Format(
1447                FormatErrorInner::DuplicateChunk { kind: chunk::cHRM }.into(),
1448            ))
1449        } else {
1450            let mut buf = &self.current_chunk.raw_bytes[..];
1451            let white_x: u32 = buf.read_be()?;
1452            let white_y: u32 = buf.read_be()?;
1453            let red_x: u32 = buf.read_be()?;
1454            let red_y: u32 = buf.read_be()?;
1455            let green_x: u32 = buf.read_be()?;
1456            let green_y: u32 = buf.read_be()?;
1457            let blue_x: u32 = buf.read_be()?;
1458            let blue_y: u32 = buf.read_be()?;
1459
1460            let source_chromaticities = SourceChromaticities {
1461                white: (
1462                    ScaledFloat::from_scaled(white_x),
1463                    ScaledFloat::from_scaled(white_y),
1464                ),
1465                red: (
1466                    ScaledFloat::from_scaled(red_x),
1467                    ScaledFloat::from_scaled(red_y),
1468                ),
1469                green: (
1470                    ScaledFloat::from_scaled(green_x),
1471                    ScaledFloat::from_scaled(green_y),
1472                ),
1473                blue: (
1474                    ScaledFloat::from_scaled(blue_x),
1475                    ScaledFloat::from_scaled(blue_y),
1476                ),
1477            };
1478
1479            info.chrm_chunk = Some(source_chromaticities);
1480            Ok(())
1481        }
1482    }
1483
1484    fn parse_gama(&mut self) -> Result<(), DecodingError> {
1485        let info = self.info.as_mut().unwrap();
1486        if self.have_idat {
1487            Err(DecodingError::Format(
1488                FormatErrorInner::AfterIdat { kind: chunk::gAMA }.into(),
1489            ))
1490        } else if info.gama_chunk.is_some() {
1491            Err(DecodingError::Format(
1492                FormatErrorInner::DuplicateChunk { kind: chunk::gAMA }.into(),
1493            ))
1494        } else {
1495            let mut buf = &self.current_chunk.raw_bytes[..];
1496            let source_gamma: u32 = buf.read_be()?;
1497            if source_gamma == 0 {
1498                return Err(DecodingError::Format(
1499                    FormatErrorInner::BadGammaValue.into(),
1500                ));
1501            }
1502
1503            let source_gamma = ScaledFloat::from_scaled(source_gamma);
1504            info.gama_chunk = Some(source_gamma);
1505            Ok(())
1506        }
1507    }
1508
1509    fn parse_srgb(&mut self) -> Result<(), DecodingError> {
1510        let info = self.info.as_mut().unwrap();
1511        if self.have_idat {
1512            Err(DecodingError::Format(
1513                FormatErrorInner::AfterIdat { kind: chunk::sRGB }.into(),
1514            ))
1515        } else if info.srgb.is_some() {
1516            Err(DecodingError::Format(
1517                FormatErrorInner::DuplicateChunk { kind: chunk::sRGB }.into(),
1518            ))
1519        } else {
1520            let mut buf = &self.current_chunk.raw_bytes[..];
1521            let raw: u8 = buf.read_be()?; // BE is is nonsense for single bytes, but this way the size is checked.
1522            let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| {
1523                FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw))
1524            })?;
1525
1526            // Set srgb and override source gamma and chromaticities.
1527            info.srgb = Some(rendering_intent);
1528            Ok(())
1529        }
1530    }
1531
1532    fn parse_cicp(&mut self) -> Result<(), DecodingError> {
1533        let info = self.info.as_mut().unwrap();
1534
1535        // The spec requires that the cICP chunk MUST come before the PLTE and IDAT chunks.
1536        if info.coding_independent_code_points.is_some() {
1537            return Err(DecodingError::Format(
1538                FormatErrorInner::DuplicateChunk { kind: chunk::cICP }.into(),
1539            ));
1540        } else if info.palette.is_some() {
1541            return Err(DecodingError::Format(
1542                FormatErrorInner::AfterPlte { kind: chunk::cICP }.into(),
1543            ));
1544        } else if self.have_idat {
1545            return Err(DecodingError::Format(
1546                FormatErrorInner::AfterIdat { kind: chunk::cICP }.into(),
1547            ));
1548        }
1549
1550        let mut buf = &*self.current_chunk.raw_bytes;
1551        let color_primaries: u8 = buf.read_be()?;
1552        let transfer_function: u8 = buf.read_be()?;
1553        let matrix_coefficients: u8 = buf.read_be()?;
1554        let is_video_full_range_image = {
1555            let flag: u8 = buf.read_be()?;
1556            match flag {
1557                0 => false,
1558                1 => true,
1559                _ => {
1560                    return Err(DecodingError::IoError(
1561                        std::io::ErrorKind::InvalidData.into(),
1562                    ));
1563                }
1564            }
1565        };
1566
1567        // RGB is currently the only supported color model in PNG, and as
1568        // such Matrix Coefficients shall be set to 0.
1569        if matrix_coefficients != 0 {
1570            return Err(DecodingError::IoError(
1571                std::io::ErrorKind::InvalidData.into(),
1572            ));
1573        }
1574
1575        if !buf.is_empty() {
1576            return Err(DecodingError::IoError(
1577                std::io::ErrorKind::InvalidData.into(),
1578            ));
1579        }
1580
1581        info.coding_independent_code_points = Some(CodingIndependentCodePoints {
1582            color_primaries,
1583            transfer_function,
1584            matrix_coefficients,
1585            is_video_full_range_image,
1586        });
1587
1588        Ok(())
1589    }
1590
1591    fn parse_mdcv(&mut self) -> Result<(), DecodingError> {
1592        let info = self.info.as_mut().unwrap();
1593
1594        // The spec requires that the mDCV chunk MUST come before the PLTE and IDAT chunks.
1595        if info.mastering_display_color_volume.is_some() {
1596            return Err(DecodingError::Format(
1597                FormatErrorInner::DuplicateChunk { kind: chunk::mDCV }.into(),
1598            ));
1599        } else if info.palette.is_some() {
1600            return Err(DecodingError::Format(
1601                FormatErrorInner::AfterPlte { kind: chunk::mDCV }.into(),
1602            ));
1603        } else if self.have_idat {
1604            return Err(DecodingError::Format(
1605                FormatErrorInner::AfterIdat { kind: chunk::mDCV }.into(),
1606            ));
1607        }
1608
1609        let mut buf = &*self.current_chunk.raw_bytes;
1610        let red_x: u16 = buf.read_be()?;
1611        let red_y: u16 = buf.read_be()?;
1612        let green_x: u16 = buf.read_be()?;
1613        let green_y: u16 = buf.read_be()?;
1614        let blue_x: u16 = buf.read_be()?;
1615        let blue_y: u16 = buf.read_be()?;
1616        let white_x: u16 = buf.read_be()?;
1617        let white_y: u16 = buf.read_be()?;
1618        fn scale(chunk: u16) -> ScaledFloat {
1619            // `ScaledFloat::SCALING` is hardcoded to 100_000, which works
1620            // well for the `cHRM` chunk where the spec says that "a value
1621            // of 0.3127 would be stored as the integer 31270".  In the
1622            // `mDCV` chunk the spec says that "0.708, 0.292)" is stored as
1623            // "{ 35400, 14600 }", using a scaling factor of 50_000, so we
1624            // multiply by 2 before converting.
1625            ScaledFloat::from_scaled((chunk as u32) * 2)
1626        }
1627        let chromaticities = SourceChromaticities {
1628            white: (scale(white_x), scale(white_y)),
1629            red: (scale(red_x), scale(red_y)),
1630            green: (scale(green_x), scale(green_y)),
1631            blue: (scale(blue_x), scale(blue_y)),
1632        };
1633        let max_luminance: u32 = buf.read_be()?;
1634        let min_luminance: u32 = buf.read_be()?;
1635        if !buf.is_empty() {
1636            return Err(DecodingError::IoError(
1637                std::io::ErrorKind::InvalidData.into(),
1638            ));
1639        }
1640        info.mastering_display_color_volume = Some(MasteringDisplayColorVolume {
1641            chromaticities,
1642            max_luminance,
1643            min_luminance,
1644        });
1645
1646        Ok(())
1647    }
1648
1649    fn parse_clli(&mut self) -> Result<(), DecodingError> {
1650        let info = self.info.as_mut().unwrap();
1651        if info.content_light_level.is_some() {
1652            return Err(DecodingError::Format(
1653                FormatErrorInner::DuplicateChunk { kind: chunk::cLLI }.into(),
1654            ));
1655        }
1656
1657        let mut buf = &*self.current_chunk.raw_bytes;
1658        let max_content_light_level: u32 = buf.read_be()?;
1659        let max_frame_average_light_level: u32 = buf.read_be()?;
1660        if !buf.is_empty() {
1661            return Err(DecodingError::IoError(
1662                std::io::ErrorKind::InvalidData.into(),
1663            ));
1664        }
1665        info.content_light_level = Some(ContentLightLevelInfo {
1666            max_content_light_level,
1667            max_frame_average_light_level,
1668        });
1669
1670        Ok(())
1671    }
1672
1673    fn parse_exif(&mut self) -> Result<(), DecodingError> {
1674        let info = self.info.as_mut().unwrap();
1675        if info.exif_metadata.is_some() {
1676            return Err(DecodingError::Format(
1677                FormatErrorInner::DuplicateChunk { kind: chunk::eXIf }.into(),
1678            ));
1679        }
1680
1681        info.exif_metadata = Some(self.current_chunk.raw_bytes.clone().into());
1682        Ok(())
1683    }
1684
1685    fn parse_iccp(&mut self) -> Result<(), DecodingError> {
1686        if self.have_idat {
1687            Err(DecodingError::Format(
1688                FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(),
1689            ))
1690        } else if self.have_iccp {
1691            Err(DecodingError::Format(
1692                FormatErrorInner::DuplicateChunk { kind: chunk::iCCP }.into(),
1693            ))
1694        } else {
1695            self.have_iccp = true;
1696            let _ = self.parse_iccp_raw();
1697            Ok(())
1698        }
1699    }
1700
1701    fn parse_iccp_raw(&mut self) -> Result<(), DecodingError> {
1702        let info = self.info.as_mut().unwrap();
1703        let mut buf = &self.current_chunk.raw_bytes[..];
1704
1705        // read profile name
1706        for len in 0..=80 {
1707            let raw: u8 = buf.read_be()?;
1708            if (raw == 0 && len == 0) || (raw != 0 && len == 80) {
1709                return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize));
1710            }
1711            if raw == 0 {
1712                break;
1713            }
1714        }
1715
1716        match buf.read_be()? {
1717            // compression method
1718            0u8 => (),
1719            n => {
1720                return Err(DecodingError::Format(
1721                    FormatErrorInner::UnknownCompressionMethod(n).into(),
1722                ))
1723            }
1724        }
1725
1726        match fdeflate::decompress_to_vec_bounded(buf, self.limits.bytes) {
1727            Ok(profile) => {
1728                self.limits.reserve_bytes(profile.len())?;
1729                info.icc_profile = Some(Cow::Owned(profile));
1730            }
1731            Err(fdeflate::BoundedDecompressionError::DecompressionError { inner: err }) => {
1732                return Err(DecodingError::Format(
1733                    FormatErrorInner::CorruptFlateStream { err }.into(),
1734                ))
1735            }
1736            Err(fdeflate::BoundedDecompressionError::OutputTooLarge { .. }) => {
1737                return Err(DecodingError::LimitsExceeded);
1738            }
1739        }
1740
1741        Ok(())
1742    }
1743
1744    fn parse_ihdr(&mut self) -> Result<(), DecodingError> {
1745        if self.info.is_some() {
1746            return Err(DecodingError::Format(
1747                FormatErrorInner::DuplicateChunk { kind: IHDR }.into(),
1748            ));
1749        }
1750        let mut buf = &self.current_chunk.raw_bytes[..];
1751        let width = buf.read_be()?;
1752        let height = buf.read_be()?;
1753        if width == 0 || height == 0 {
1754            return Err(DecodingError::Format(
1755                FormatErrorInner::InvalidDimensions.into(),
1756            ));
1757        }
1758        let bit_depth = buf.read_be()?;
1759        let bit_depth = match BitDepth::from_u8(bit_depth) {
1760            Some(bits) => bits,
1761            None => {
1762                return Err(DecodingError::Format(
1763                    FormatErrorInner::InvalidBitDepth(bit_depth).into(),
1764                ))
1765            }
1766        };
1767        let color_type = buf.read_be()?;
1768        let color_type = match ColorType::from_u8(color_type) {
1769            Some(color_type) => {
1770                if color_type.is_combination_invalid(bit_depth) {
1771                    return Err(DecodingError::Format(
1772                        FormatErrorInner::InvalidColorBitDepth {
1773                            color_type,
1774                            bit_depth,
1775                        }
1776                        .into(),
1777                    ));
1778                } else {
1779                    color_type
1780                }
1781            }
1782            None => {
1783                return Err(DecodingError::Format(
1784                    FormatErrorInner::InvalidColorType(color_type).into(),
1785                ))
1786            }
1787        };
1788        match buf.read_be()? {
1789            // compression method
1790            0u8 => (),
1791            n => {
1792                return Err(DecodingError::Format(
1793                    FormatErrorInner::UnknownCompressionMethod(n).into(),
1794                ))
1795            }
1796        }
1797        match buf.read_be()? {
1798            // filter method
1799            0u8 => (),
1800            n => {
1801                return Err(DecodingError::Format(
1802                    FormatErrorInner::UnknownFilterMethod(n).into(),
1803                ))
1804            }
1805        }
1806        let interlaced = match buf.read_be()? {
1807            0u8 => false,
1808            1 => true,
1809            n => {
1810                return Err(DecodingError::Format(
1811                    FormatErrorInner::UnknownInterlaceMethod(n).into(),
1812                ))
1813            }
1814        };
1815
1816        self.info = Some(Info {
1817            width,
1818            height,
1819            bit_depth,
1820            color_type,
1821            interlaced,
1822            ..Default::default()
1823        });
1824
1825        Ok(())
1826    }
1827
1828    fn split_keyword(buf: &[u8]) -> Result<(&[u8], &[u8]), DecodingError> {
1829        let null_byte_index = buf
1830            .iter()
1831            .position(|&b| b == 0)
1832            .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?;
1833
1834        if null_byte_index == 0 || null_byte_index > 79 {
1835            return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize));
1836        }
1837
1838        Ok((&buf[..null_byte_index], &buf[null_byte_index + 1..]))
1839    }
1840
1841    fn parse_text(&mut self) -> Result<(), DecodingError> {
1842        let buf = &self.current_chunk.raw_bytes[..];
1843        self.limits.reserve_bytes(buf.len())?;
1844
1845        let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1846
1847        self.info
1848            .as_mut()
1849            .unwrap()
1850            .uncompressed_latin1_text
1851            .push(TEXtChunk::decode(keyword_slice, value_slice).map_err(DecodingError::from)?);
1852
1853        Ok(())
1854    }
1855
1856    fn parse_ztxt(&mut self) -> Result<(), DecodingError> {
1857        let buf = &self.current_chunk.raw_bytes[..];
1858        self.limits.reserve_bytes(buf.len())?;
1859
1860        let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1861
1862        let compression_method = *value_slice
1863            .first()
1864            .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?;
1865
1866        let text_slice = &value_slice[1..];
1867
1868        self.info.as_mut().unwrap().compressed_latin1_text.push(
1869            ZTXtChunk::decode(keyword_slice, compression_method, text_slice)
1870                .map_err(DecodingError::from)?,
1871        );
1872
1873        Ok(())
1874    }
1875
1876    fn parse_itxt(&mut self) -> Result<(), DecodingError> {
1877        let buf = &self.current_chunk.raw_bytes[..];
1878        self.limits.reserve_bytes(buf.len())?;
1879
1880        let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1881
1882        let compression_flag = *value_slice
1883            .first()
1884            .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?;
1885
1886        let compression_method = *value_slice
1887            .get(1)
1888            .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?;
1889
1890        let second_null_byte_index = value_slice[2..]
1891            .iter()
1892            .position(|&b| b == 0)
1893            .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?
1894            + 2;
1895
1896        let language_tag_slice = &value_slice[2..second_null_byte_index];
1897
1898        let third_null_byte_index = value_slice[second_null_byte_index + 1..]
1899            .iter()
1900            .position(|&b| b == 0)
1901            .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?
1902            + (second_null_byte_index + 1);
1903
1904        let translated_keyword_slice =
1905            &value_slice[second_null_byte_index + 1..third_null_byte_index];
1906
1907        let text_slice = &value_slice[third_null_byte_index + 1..];
1908
1909        self.info.as_mut().unwrap().utf8_text.push(
1910            ITXtChunk::decode(
1911                keyword_slice,
1912                compression_flag,
1913                compression_method,
1914                language_tag_slice,
1915                translated_keyword_slice,
1916                text_slice,
1917            )
1918            .map_err(DecodingError::from)?,
1919        );
1920
1921        Ok(())
1922    }
1923
1924    fn parse_bkgd(&mut self) -> Result<(), DecodingError> {
1925        let info = self.info.as_mut().unwrap();
1926        if info.bkgd.is_some() {
1927            // Only one bKGD chunk is allowed
1928            return Err(DecodingError::Format(
1929                FormatErrorInner::DuplicateChunk { kind: chunk::bKGD }.into(),
1930            ));
1931        } else if self.have_idat {
1932            return Err(DecodingError::Format(
1933                FormatErrorInner::AfterIdat { kind: chunk::bKGD }.into(),
1934            ));
1935        }
1936
1937        let expected = match info.color_type {
1938            ColorType::Indexed => {
1939                if info.palette.is_none() {
1940                    return Err(DecodingError::IoError(
1941                        std::io::ErrorKind::InvalidData.into(),
1942                    ));
1943                };
1944                1
1945            }
1946            ColorType::Grayscale | ColorType::GrayscaleAlpha => 2,
1947            ColorType::Rgb | ColorType::Rgba => 6,
1948        };
1949        let vec = self.current_chunk.raw_bytes.clone();
1950        if vec.len() != expected {
1951            return Err(DecodingError::Format(
1952                FormatErrorInner::ChunkLengthWrong { kind: chunk::bKGD }.into(),
1953            ));
1954        }
1955
1956        info.bkgd = Some(Cow::Owned(vec));
1957        Ok(())
1958    }
1959}
1960
1961impl Info<'_> {
1962    fn validate_default_image(&self, fc: &FrameControl) -> Result<(), DecodingError> {
1963        // https://www.w3.org/TR/png-3/#fcTL-chunk says that:
1964        //
1965        // > The fcTL chunk corresponding to the default image, if it exists, has these
1966        // > restrictions:
1967        // >
1968        // > * The x_offset and y_offset fields must be 0.
1969        // > * The width and height fields must equal
1970        // >   the corresponding fields from the IHDR chunk.
1971        if fc.x_offset != 0
1972            || fc.y_offset != 0
1973            || fc.width != self.width
1974            || fc.height != self.height
1975        {
1976            return Err(DecodingError::Format(
1977                FormatErrorInner::BadSubFrameBounds {}.into(),
1978            ));
1979        }
1980        Ok(())
1981    }
1982
1983    fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> {
1984        if fc.width == 0 || fc.height == 0 {
1985            return Err(DecodingError::Format(
1986                FormatErrorInner::InvalidDimensions.into(),
1987            ));
1988        }
1989
1990        // Validate mathematically: fc.width + fc.x_offset <= self.width
1991        let in_x_bounds = Some(fc.width) <= self.width.checked_sub(fc.x_offset);
1992        // Validate mathematically: fc.height + fc.y_offset <= self.height
1993        let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset);
1994
1995        if !in_x_bounds || !in_y_bounds {
1996            return Err(DecodingError::Format(
1997                // TODO: do we want to display the bad bounds?
1998                FormatErrorInner::BadSubFrameBounds {}.into(),
1999            ));
2000        }
2001
2002        Ok(())
2003    }
2004}
2005
2006impl Default for StreamingDecoder {
2007    fn default() -> Self {
2008        Self::new()
2009    }
2010}
2011
2012#[cfg(test)]
2013mod tests {
2014    use super::ScaledFloat;
2015    use super::SourceChromaticities;
2016    use crate::test_utils::*;
2017    use crate::{Decoder, DecodingError, Reader, SrgbRenderingIntent, Unit};
2018    use approx::assert_relative_eq;
2019    use byteorder::WriteBytesExt;
2020    use std::borrow::Cow;
2021    use std::cell::RefCell;
2022
2023    use std::fs::File;
2024    use std::io::BufRead;
2025    use std::io::Cursor;
2026    use std::io::Seek;
2027    use std::io::{BufReader, ErrorKind, Read, Write};
2028    use std::rc::Rc;
2029
2030    #[test]
2031    fn image_gamma() -> Result<(), ()> {
2032        fn trial(path: &str, expected: Option<ScaledFloat>) {
2033            let decoder = crate::Decoder::new(BufReader::new(File::open(path).unwrap()));
2034            let reader = decoder.read_info().unwrap();
2035            let actual: Option<ScaledFloat> = reader.info().gamma();
2036            assert!(actual == expected);
2037        }
2038        trial("tests/pngsuite/f00n0g08.png", None);
2039        trial("tests/pngsuite/f00n2c08.png", None);
2040        trial("tests/pngsuite/f01n0g08.png", None);
2041        trial("tests/pngsuite/f01n2c08.png", None);
2042        trial("tests/pngsuite/f02n0g08.png", None);
2043        trial("tests/pngsuite/f02n2c08.png", None);
2044        trial("tests/pngsuite/f03n0g08.png", None);
2045        trial("tests/pngsuite/f03n2c08.png", None);
2046        trial("tests/pngsuite/f04n0g08.png", None);
2047        trial("tests/pngsuite/f04n2c08.png", None);
2048        trial("tests/pngsuite/f99n0g04.png", None);
2049        trial("tests/pngsuite/tm3n3p02.png", None);
2050        trial("tests/pngsuite/g03n0g16.png", Some(ScaledFloat::new(0.35)));
2051        trial("tests/pngsuite/g03n2c08.png", Some(ScaledFloat::new(0.35)));
2052        trial("tests/pngsuite/g03n3p04.png", Some(ScaledFloat::new(0.35)));
2053        trial("tests/pngsuite/g04n0g16.png", Some(ScaledFloat::new(0.45)));
2054        trial("tests/pngsuite/g04n2c08.png", Some(ScaledFloat::new(0.45)));
2055        trial("tests/pngsuite/g04n3p04.png", Some(ScaledFloat::new(0.45)));
2056        trial("tests/pngsuite/g05n0g16.png", Some(ScaledFloat::new(0.55)));
2057        trial("tests/pngsuite/g05n2c08.png", Some(ScaledFloat::new(0.55)));
2058        trial("tests/pngsuite/g05n3p04.png", Some(ScaledFloat::new(0.55)));
2059        trial("tests/pngsuite/g07n0g16.png", Some(ScaledFloat::new(0.7)));
2060        trial("tests/pngsuite/g07n2c08.png", Some(ScaledFloat::new(0.7)));
2061        trial("tests/pngsuite/g07n3p04.png", Some(ScaledFloat::new(0.7)));
2062        trial("tests/pngsuite/g10n0g16.png", Some(ScaledFloat::new(1.0)));
2063        trial("tests/pngsuite/g10n2c08.png", Some(ScaledFloat::new(1.0)));
2064        trial("tests/pngsuite/g10n3p04.png", Some(ScaledFloat::new(1.0)));
2065        trial("tests/pngsuite/g25n0g16.png", Some(ScaledFloat::new(2.5)));
2066        trial("tests/pngsuite/g25n2c08.png", Some(ScaledFloat::new(2.5)));
2067        trial("tests/pngsuite/g25n3p04.png", Some(ScaledFloat::new(2.5)));
2068        Ok(())
2069    }
2070
2071    #[test]
2072    fn image_source_chromaticities() -> Result<(), ()> {
2073        fn trial(path: &str, expected: Option<SourceChromaticities>) {
2074            let decoder = crate::Decoder::new(BufReader::new(File::open(path).unwrap()));
2075            let reader = decoder.read_info().unwrap();
2076            let actual: Option<SourceChromaticities> = reader.info().chromaticities();
2077            assert!(actual == expected);
2078        }
2079        trial(
2080            "tests/pngsuite/ccwn2c08.png",
2081            Some(SourceChromaticities::new(
2082                (0.3127, 0.3290),
2083                (0.64, 0.33),
2084                (0.30, 0.60),
2085                (0.15, 0.06),
2086            )),
2087        );
2088        trial(
2089            "tests/pngsuite/ccwn3p08.png",
2090            Some(SourceChromaticities::new(
2091                (0.3127, 0.3290),
2092                (0.64, 0.33),
2093                (0.30, 0.60),
2094                (0.15, 0.06),
2095            )),
2096        );
2097        trial("tests/pngsuite/basi0g01.png", None);
2098        trial("tests/pngsuite/basi0g02.png", None);
2099        trial("tests/pngsuite/basi0g04.png", None);
2100        trial("tests/pngsuite/basi0g08.png", None);
2101        trial("tests/pngsuite/basi0g16.png", None);
2102        trial("tests/pngsuite/basi2c08.png", None);
2103        trial("tests/pngsuite/basi2c16.png", None);
2104        trial("tests/pngsuite/basi3p01.png", None);
2105        trial("tests/pngsuite/basi3p02.png", None);
2106        trial("tests/pngsuite/basi3p04.png", None);
2107        trial("tests/pngsuite/basi3p08.png", None);
2108        trial("tests/pngsuite/basi4a08.png", None);
2109        trial("tests/pngsuite/basi4a16.png", None);
2110        trial("tests/pngsuite/basi6a08.png", None);
2111        trial("tests/pngsuite/basi6a16.png", None);
2112        trial("tests/pngsuite/basn0g01.png", None);
2113        trial("tests/pngsuite/basn0g02.png", None);
2114        trial("tests/pngsuite/basn0g04.png", None);
2115        trial("tests/pngsuite/basn0g08.png", None);
2116        trial("tests/pngsuite/basn0g16.png", None);
2117        trial("tests/pngsuite/basn2c08.png", None);
2118        trial("tests/pngsuite/basn2c16.png", None);
2119        trial("tests/pngsuite/basn3p01.png", None);
2120        trial("tests/pngsuite/basn3p02.png", None);
2121        trial("tests/pngsuite/basn3p04.png", None);
2122        trial("tests/pngsuite/basn3p08.png", None);
2123        trial("tests/pngsuite/basn4a08.png", None);
2124        trial("tests/pngsuite/basn4a16.png", None);
2125        trial("tests/pngsuite/basn6a08.png", None);
2126        trial("tests/pngsuite/basn6a16.png", None);
2127        trial("tests/pngsuite/bgai4a08.png", None);
2128        trial("tests/pngsuite/bgai4a16.png", None);
2129        trial("tests/pngsuite/bgan6a08.png", None);
2130        trial("tests/pngsuite/bgan6a16.png", None);
2131        trial("tests/pngsuite/bgbn4a08.png", None);
2132        trial("tests/pngsuite/bggn4a16.png", None);
2133        trial("tests/pngsuite/bgwn6a08.png", None);
2134        trial("tests/pngsuite/bgyn6a16.png", None);
2135        trial("tests/pngsuite/cdfn2c08.png", None);
2136        trial("tests/pngsuite/cdhn2c08.png", None);
2137        trial("tests/pngsuite/cdsn2c08.png", None);
2138        trial("tests/pngsuite/cdun2c08.png", None);
2139        trial("tests/pngsuite/ch1n3p04.png", None);
2140        trial("tests/pngsuite/ch2n3p08.png", None);
2141        trial("tests/pngsuite/cm0n0g04.png", None);
2142        trial("tests/pngsuite/cm7n0g04.png", None);
2143        trial("tests/pngsuite/cm9n0g04.png", None);
2144        trial("tests/pngsuite/cs3n2c16.png", None);
2145        trial("tests/pngsuite/cs3n3p08.png", None);
2146        trial("tests/pngsuite/cs5n2c08.png", None);
2147        trial("tests/pngsuite/cs5n3p08.png", None);
2148        trial("tests/pngsuite/cs8n2c08.png", None);
2149        trial("tests/pngsuite/cs8n3p08.png", None);
2150        trial("tests/pngsuite/ct0n0g04.png", None);
2151        trial("tests/pngsuite/ct1n0g04.png", None);
2152        trial("tests/pngsuite/cten0g04.png", None);
2153        trial("tests/pngsuite/ctfn0g04.png", None);
2154        trial("tests/pngsuite/ctgn0g04.png", None);
2155        trial("tests/pngsuite/cthn0g04.png", None);
2156        trial("tests/pngsuite/ctjn0g04.png", None);
2157        trial("tests/pngsuite/ctzn0g04.png", None);
2158        trial("tests/pngsuite/f00n0g08.png", None);
2159        trial("tests/pngsuite/f00n2c08.png", None);
2160        trial("tests/pngsuite/f01n0g08.png", None);
2161        trial("tests/pngsuite/f01n2c08.png", None);
2162        trial("tests/pngsuite/f02n0g08.png", None);
2163        trial("tests/pngsuite/f02n2c08.png", None);
2164        trial("tests/pngsuite/f03n0g08.png", None);
2165        trial("tests/pngsuite/f03n2c08.png", None);
2166        trial("tests/pngsuite/f04n0g08.png", None);
2167        trial("tests/pngsuite/f04n2c08.png", None);
2168        trial("tests/pngsuite/f99n0g04.png", None);
2169        trial("tests/pngsuite/g03n0g16.png", None);
2170        trial("tests/pngsuite/g03n2c08.png", None);
2171        trial("tests/pngsuite/g03n3p04.png", None);
2172        trial("tests/pngsuite/g04n0g16.png", None);
2173        trial("tests/pngsuite/g04n2c08.png", None);
2174        trial("tests/pngsuite/g04n3p04.png", None);
2175        trial("tests/pngsuite/g05n0g16.png", None);
2176        trial("tests/pngsuite/g05n2c08.png", None);
2177        trial("tests/pngsuite/g05n3p04.png", None);
2178        trial("tests/pngsuite/g07n0g16.png", None);
2179        trial("tests/pngsuite/g07n2c08.png", None);
2180        trial("tests/pngsuite/g07n3p04.png", None);
2181        trial("tests/pngsuite/g10n0g16.png", None);
2182        trial("tests/pngsuite/g10n2c08.png", None);
2183        trial("tests/pngsuite/g10n3p04.png", None);
2184        trial("tests/pngsuite/g25n0g16.png", None);
2185        trial("tests/pngsuite/g25n2c08.png", None);
2186        trial("tests/pngsuite/g25n3p04.png", None);
2187        trial("tests/pngsuite/oi1n0g16.png", None);
2188        trial("tests/pngsuite/oi1n2c16.png", None);
2189        trial("tests/pngsuite/oi2n0g16.png", None);
2190        trial("tests/pngsuite/oi2n2c16.png", None);
2191        trial("tests/pngsuite/oi4n0g16.png", None);
2192        trial("tests/pngsuite/oi4n2c16.png", None);
2193        trial("tests/pngsuite/oi9n0g16.png", None);
2194        trial("tests/pngsuite/oi9n2c16.png", None);
2195        trial("tests/pngsuite/PngSuite.png", None);
2196        trial("tests/pngsuite/pp0n2c16.png", None);
2197        trial("tests/pngsuite/pp0n6a08.png", None);
2198        trial("tests/pngsuite/ps1n0g08.png", None);
2199        trial("tests/pngsuite/ps1n2c16.png", None);
2200        trial("tests/pngsuite/ps2n0g08.png", None);
2201        trial("tests/pngsuite/ps2n2c16.png", None);
2202        trial("tests/pngsuite/s01i3p01.png", None);
2203        trial("tests/pngsuite/s01n3p01.png", None);
2204        trial("tests/pngsuite/s02i3p01.png", None);
2205        trial("tests/pngsuite/s02n3p01.png", None);
2206        trial("tests/pngsuite/s03i3p01.png", None);
2207        trial("tests/pngsuite/s03n3p01.png", None);
2208        trial("tests/pngsuite/s04i3p01.png", None);
2209        trial("tests/pngsuite/s04n3p01.png", None);
2210        trial("tests/pngsuite/s05i3p02.png", None);
2211        trial("tests/pngsuite/s05n3p02.png", None);
2212        trial("tests/pngsuite/s06i3p02.png", None);
2213        trial("tests/pngsuite/s06n3p02.png", None);
2214        trial("tests/pngsuite/s07i3p02.png", None);
2215        trial("tests/pngsuite/s07n3p02.png", None);
2216        trial("tests/pngsuite/s08i3p02.png", None);
2217        trial("tests/pngsuite/s08n3p02.png", None);
2218        trial("tests/pngsuite/s09i3p02.png", None);
2219        trial("tests/pngsuite/s09n3p02.png", None);
2220        trial("tests/pngsuite/s32i3p04.png", None);
2221        trial("tests/pngsuite/s32n3p04.png", None);
2222        trial("tests/pngsuite/s33i3p04.png", None);
2223        trial("tests/pngsuite/s33n3p04.png", None);
2224        trial("tests/pngsuite/s34i3p04.png", None);
2225        trial("tests/pngsuite/s34n3p04.png", None);
2226        trial("tests/pngsuite/s35i3p04.png", None);
2227        trial("tests/pngsuite/s35n3p04.png", None);
2228        trial("tests/pngsuite/s36i3p04.png", None);
2229        trial("tests/pngsuite/s36n3p04.png", None);
2230        trial("tests/pngsuite/s37i3p04.png", None);
2231        trial("tests/pngsuite/s37n3p04.png", None);
2232        trial("tests/pngsuite/s38i3p04.png", None);
2233        trial("tests/pngsuite/s38n3p04.png", None);
2234        trial("tests/pngsuite/s39i3p04.png", None);
2235        trial("tests/pngsuite/s39n3p04.png", None);
2236        trial("tests/pngsuite/s40i3p04.png", None);
2237        trial("tests/pngsuite/s40n3p04.png", None);
2238        trial("tests/pngsuite/tbbn0g04.png", None);
2239        trial("tests/pngsuite/tbbn2c16.png", None);
2240        trial("tests/pngsuite/tbbn3p08.png", None);
2241        trial("tests/pngsuite/tbgn2c16.png", None);
2242        trial("tests/pngsuite/tbgn3p08.png", None);
2243        trial("tests/pngsuite/tbrn2c08.png", None);
2244        trial("tests/pngsuite/tbwn0g16.png", None);
2245        trial("tests/pngsuite/tbwn3p08.png", None);
2246        trial("tests/pngsuite/tbyn3p08.png", None);
2247        trial("tests/pngsuite/tm3n3p02.png", None);
2248        trial("tests/pngsuite/tp0n0g08.png", None);
2249        trial("tests/pngsuite/tp0n2c08.png", None);
2250        trial("tests/pngsuite/tp0n3p08.png", None);
2251        trial("tests/pngsuite/tp1n3p08.png", None);
2252        trial("tests/pngsuite/z00n2c08.png", None);
2253        trial("tests/pngsuite/z03n2c08.png", None);
2254        trial("tests/pngsuite/z06n2c08.png", None);
2255        Ok(())
2256    }
2257
2258    #[test]
2259    fn image_source_sbit() {
2260        fn trial(path: &str, expected: Option<Cow<[u8]>>) {
2261            let decoder = crate::Decoder::new(BufReader::new(File::open(path).unwrap()));
2262            let reader = decoder.read_info().unwrap();
2263            let actual: Option<Cow<[u8]>> = reader.info().sbit.clone();
2264            assert!(actual == expected);
2265        }
2266
2267        trial("tests/sbit/g.png", Some(Cow::Owned(vec![5u8])));
2268        trial("tests/sbit/ga.png", Some(Cow::Owned(vec![5u8, 3u8])));
2269        trial(
2270            "tests/sbit/indexed.png",
2271            Some(Cow::Owned(vec![5u8, 6u8, 5u8])),
2272        );
2273        trial("tests/sbit/rgb.png", Some(Cow::Owned(vec![5u8, 6u8, 5u8])));
2274        trial(
2275            "tests/sbit/rgba.png",
2276            Some(Cow::Owned(vec![5u8, 6u8, 5u8, 8u8])),
2277        );
2278    }
2279
2280    /// Test handling of a PNG file that contains *two* iCCP chunks.
2281    /// This is a regression test for https://github.com/image-rs/image/issues/1825.
2282    #[test]
2283    fn test_two_iccp_chunks() {
2284        // The test file has been taken from
2285        // https://github.com/image-rs/image/issues/1825#issuecomment-1321798639,
2286        // but the 2nd iCCP chunk has been altered manually (see the 2nd comment below for more
2287        // details).
2288        let decoder = crate::Decoder::new(BufReader::new(
2289            File::open("tests/bugfixes/issue#1825.png").unwrap(),
2290        ));
2291        let reader = decoder.read_info().unwrap();
2292        let icc_profile = reader.info().icc_profile.clone().unwrap().into_owned();
2293
2294        // Assert that the contents of the *first* iCCP chunk are returned.
2295        //
2296        // Note that the 2nd chunk in the test file has been manually altered to have a different
2297        // content (`b"test iccp contents"`) which would have a different CRC (797351983).
2298        assert_eq!(4070462061, crc32fast::hash(&icc_profile));
2299    }
2300
2301    #[test]
2302    fn test_iccp_roundtrip() {
2303        let dummy_icc = b"I'm a profile";
2304
2305        let mut info = crate::Info::with_size(1, 1);
2306        info.icc_profile = Some(dummy_icc.into());
2307        let mut encoded_image = Vec::new();
2308        let enc = crate::Encoder::with_info(&mut encoded_image, info).unwrap();
2309        let mut enc = enc.write_header().unwrap();
2310        enc.write_image_data(&[0]).unwrap();
2311        enc.finish().unwrap();
2312
2313        let dec = crate::Decoder::new(Cursor::new(&encoded_image));
2314        let dec = dec.read_info().unwrap();
2315        assert_eq!(dummy_icc, &**dec.info().icc_profile.as_ref().unwrap());
2316    }
2317
2318    #[test]
2319    fn test_phys_roundtrip() {
2320        let mut info = crate::Info::with_size(1, 1);
2321        info.pixel_dims = Some(crate::PixelDimensions {
2322            xppu: 12,
2323            yppu: 34,
2324            unit: Unit::Meter,
2325        });
2326        let mut encoded_image = Vec::new();
2327        let enc = crate::Encoder::with_info(&mut encoded_image, info).unwrap();
2328        let mut enc = enc.write_header().unwrap();
2329        enc.write_image_data(&[0]).unwrap();
2330        enc.finish().unwrap();
2331
2332        let dec = crate::Decoder::new(Cursor::new(&encoded_image));
2333        let dec = dec.read_info().unwrap();
2334        let phys = dec.info().pixel_dims.as_ref().unwrap();
2335        assert_eq!(phys.xppu, 12);
2336        assert_eq!(phys.yppu, 34);
2337        assert_eq!(phys.unit, Unit::Meter);
2338    }
2339
2340    #[test]
2341    fn test_srgb_roundtrip() {
2342        let mut info = crate::Info::with_size(1, 1);
2343        info.srgb = Some(SrgbRenderingIntent::Saturation);
2344        let mut encoded_image = Vec::new();
2345        let enc = crate::Encoder::with_info(&mut encoded_image, info).unwrap();
2346        let mut enc = enc.write_header().unwrap();
2347        enc.write_image_data(&[0]).unwrap();
2348        enc.finish().unwrap();
2349
2350        let dec = crate::Decoder::new(Cursor::new(&encoded_image));
2351        let dec = dec.read_info().unwrap();
2352        assert_eq!(dec.info().srgb.unwrap(), SrgbRenderingIntent::Saturation);
2353    }
2354
2355    #[test]
2356    fn test_png_with_broken_iccp() {
2357        let decoder = crate::Decoder::new(BufReader::new(
2358            File::open("tests/iccp/broken_iccp.png").unwrap(),
2359        ));
2360        assert!(decoder.read_info().is_ok());
2361        let mut decoder = crate::Decoder::new(BufReader::new(
2362            File::open("tests/iccp/broken_iccp.png").unwrap(),
2363        ));
2364        decoder.set_ignore_iccp_chunk(true);
2365        assert!(decoder.read_info().is_ok());
2366    }
2367
2368    /// Test handling of `cICP`, `mDCV`, and `cLLI` chunks.
2369    #[test]
2370    fn test_cicp_mdcv_and_clli_chunks() {
2371        let mut decoder = crate::Decoder::new(BufReader::new(
2372            File::open("tests/bugfixes/cicp_pq.png").unwrap(),
2373        ));
2374        decoder.ignore_checksums(true);
2375        let reader = decoder.read_info().unwrap();
2376        let info = reader.info();
2377
2378        let cicp = info.coding_independent_code_points.unwrap();
2379        assert_eq!(cicp.color_primaries, 9);
2380        assert_eq!(cicp.transfer_function, 16);
2381        assert_eq!(cicp.matrix_coefficients, 0);
2382        assert!(cicp.is_video_full_range_image);
2383
2384        let mdcv = info.mastering_display_color_volume.unwrap();
2385        assert_relative_eq!(mdcv.chromaticities.red.0.into_value(), 0.680);
2386        assert_relative_eq!(mdcv.chromaticities.red.1.into_value(), 0.320);
2387        assert_relative_eq!(mdcv.chromaticities.green.0.into_value(), 0.265);
2388        assert_relative_eq!(mdcv.chromaticities.green.1.into_value(), 0.690);
2389        assert_relative_eq!(mdcv.chromaticities.blue.0.into_value(), 0.150);
2390        assert_relative_eq!(mdcv.chromaticities.blue.1.into_value(), 0.060);
2391        assert_relative_eq!(mdcv.chromaticities.white.0.into_value(), 0.3127);
2392        assert_relative_eq!(mdcv.chromaticities.white.1.into_value(), 0.3290);
2393        assert_relative_eq!(mdcv.min_luminance as f32 / 10_000.0, 0.01);
2394        assert_relative_eq!(mdcv.max_luminance as f32 / 10_000.0, 5000.0);
2395
2396        let clli = info.content_light_level.unwrap();
2397        assert_relative_eq!(clli.max_content_light_level as f32 / 10_000.0, 4000.0);
2398        assert_relative_eq!(clli.max_frame_average_light_level as f32 / 10_000.0, 2627.0);
2399    }
2400
2401    /// Test handling of `eXIf` chunk.
2402    #[test]
2403    fn test_exif_chunk() {
2404        let decoder = crate::Decoder::new(BufReader::new(
2405            File::open("tests/bugfixes/F-exif-chunk-early.png").unwrap(),
2406        ));
2407        let reader = decoder.read_info().unwrap();
2408        let info = reader.info();
2409        let exif = info.exif_metadata.as_ref().unwrap().as_ref();
2410        assert_eq!(exif.len(), 90);
2411    }
2412
2413    /// Tests what happens then [`Reader.finish`] is called twice.
2414    #[test]
2415    fn test_finishing_twice() {
2416        let mut png = Vec::new();
2417        write_noncompressed_png(&mut png, 16, 1024);
2418        let decoder = Decoder::new(Cursor::new(&png));
2419        let mut reader = decoder.read_info().unwrap();
2420
2421        // First call to `finish` - expecting success.
2422        reader.finish().unwrap();
2423
2424        // Second call to `finish` - expecting an error.
2425        let err = reader.finish().unwrap_err();
2426        assert!(matches!(&err, DecodingError::Parameter(_)));
2427        assert_eq!("End of image has been reached", format!("{err}"));
2428    }
2429
2430    /// Writes an acTL chunk.
2431    /// See https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk
2432    fn write_actl(w: &mut impl Write, animation: &crate::AnimationControl) {
2433        let mut data = Vec::new();
2434        data.write_u32::<byteorder::BigEndian>(animation.num_frames)
2435            .unwrap();
2436        data.write_u32::<byteorder::BigEndian>(animation.num_plays)
2437            .unwrap();
2438        write_chunk(w, b"acTL", &data);
2439    }
2440
2441    /// Writes an fcTL chunk.
2442    /// See https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
2443    fn write_fctl(w: &mut impl Write, frame: &crate::FrameControl) {
2444        let mut data = Vec::new();
2445        data.write_u32::<byteorder::BigEndian>(frame.sequence_number)
2446            .unwrap();
2447        data.write_u32::<byteorder::BigEndian>(frame.width).unwrap();
2448        data.write_u32::<byteorder::BigEndian>(frame.height)
2449            .unwrap();
2450        data.write_u32::<byteorder::BigEndian>(frame.x_offset)
2451            .unwrap();
2452        data.write_u32::<byteorder::BigEndian>(frame.y_offset)
2453            .unwrap();
2454        data.write_u16::<byteorder::BigEndian>(frame.delay_num)
2455            .unwrap();
2456        data.write_u16::<byteorder::BigEndian>(frame.delay_den)
2457            .unwrap();
2458        data.write_u8(frame.dispose_op as u8).unwrap();
2459        data.write_u8(frame.blend_op as u8).unwrap();
2460        write_chunk(w, b"fcTL", &data);
2461    }
2462
2463    /// Writes an fdAT chunk.
2464    /// See https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk
2465    fn write_fdat(w: &mut impl Write, sequence_number: u32, image_data: &[u8]) {
2466        let mut data = Vec::new();
2467        data.write_u32::<byteorder::BigEndian>(sequence_number)
2468            .unwrap();
2469        data.write_all(image_data).unwrap();
2470        write_chunk(w, b"fdAT", &data);
2471    }
2472
2473    /// Writes PNG signature and chunks that can precede an fdAT chunk that is expected
2474    /// to have
2475    /// - `sequence_number` set to 0
2476    /// - image data with rgba8 pixels in a `width` by `width` image
2477    fn write_fdat_prefix(w: &mut impl Write, num_frames: u32, width: u32) {
2478        write_png_sig(w);
2479        write_rgba8_ihdr_with_width(w, width);
2480        write_actl(
2481            w,
2482            &crate::AnimationControl {
2483                num_frames,
2484                num_plays: 0,
2485            },
2486        );
2487
2488        let mut fctl = crate::FrameControl {
2489            width,
2490            height: width,
2491            ..Default::default()
2492        };
2493        write_fctl(w, &fctl);
2494        write_rgba8_idats(w, width, 0x7fffffff);
2495
2496        fctl.sequence_number += 1;
2497        write_fctl(w, &fctl);
2498    }
2499
2500    #[test]
2501    fn test_fdat_chunk_without_idat() {
2502        let png = {
2503            let width = 1;
2504            let mut png = Vec::new();
2505            write_png_sig(&mut png);
2506            write_rgba8_ihdr_with_width(&mut png, width);
2507            let image_data = generate_rgba8_with_width_and_height(width, width);
2508            write_actl(
2509                &mut png,
2510                &crate::AnimationControl {
2511                    num_frames: 2,
2512                    num_plays: 1,
2513                },
2514            );
2515            let mut fctl = crate::FrameControl {
2516                sequence_number: 0,
2517                width,
2518                height: width,
2519                ..Default::default()
2520            };
2521            write_fctl(&mut png, &fctl);
2522            fctl.sequence_number = 1;
2523            write_fctl(&mut png, &fctl);
2524            write_fdat(&mut png, 1, &image_data[..]);
2525            write_iend(&mut png);
2526            png
2527        };
2528        let decoder = Decoder::new(Cursor::new(&png));
2529        let Err(err) = decoder.read_info() else {
2530            panic!("Expected an error")
2531        };
2532        assert!(matches!(&err, DecodingError::Format(_)));
2533        assert_eq!(
2534            "Unexpected restart of ChunkType { type: fdAT, \
2535                         critical: false, \
2536                         private: true, \
2537                         reserved: false, \
2538                         safecopy: false \
2539             } chunk sequence",
2540            format!("{err}"),
2541        );
2542    }
2543
2544    #[test]
2545    fn test_fdat_chunk_payload_length_0() {
2546        let mut png = Vec::new();
2547        write_fdat_prefix(&mut png, 2, 8);
2548        write_chunk(&mut png, b"fdAT", &[]);
2549
2550        let decoder = Decoder::new(Cursor::new(&png));
2551        let mut reader = decoder.read_info().unwrap();
2552        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
2553        reader.next_frame(&mut buf).unwrap();
2554
2555        // 0-length fdAT should result in an error.
2556        let err = reader.next_frame(&mut buf).unwrap_err();
2557        assert!(matches!(&err, DecodingError::Format(_)));
2558        assert_eq!("fdAT chunk shorter than 4 bytes", format!("{err}"));
2559
2560        // Calling `next_frame` again should return an error.  Same error as above would be nice,
2561        // but it is probably unnecessary and infeasible (`DecodingError` can't derive `Clone`
2562        // because `std::io::Error` doesn't implement `Clone`)..  But it definitely shouldn't enter
2563        // an infinite loop.
2564        let err2 = reader.next_frame(&mut buf).unwrap_err();
2565        assert!(matches!(&err2, DecodingError::Parameter(_)));
2566        assert_eq!(
2567            "A fatal decoding error has been encounted earlier",
2568            format!("{err2}")
2569        );
2570    }
2571
2572    #[test]
2573    fn test_fdat_chunk_payload_length_3() {
2574        let mut png = Vec::new();
2575        write_fdat_prefix(&mut png, 2, 8);
2576        write_chunk(&mut png, b"fdAT", &[1, 0, 0]);
2577
2578        let decoder = Decoder::new(Cursor::new(&png));
2579        let mut reader = decoder.read_info().unwrap();
2580        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
2581        reader.next_frame(&mut buf).unwrap();
2582
2583        // 3-bytes-long fdAT should result in an error.
2584        let err = reader.next_frame(&mut buf).unwrap_err();
2585        assert!(matches!(&err, DecodingError::Format(_)));
2586        assert_eq!("fdAT chunk shorter than 4 bytes", format!("{err}"));
2587    }
2588
2589    #[test]
2590    fn test_frame_split_across_two_fdat_chunks() {
2591        // Generate test data where the 2nd animation frame is split across 2 fdAT chunks.
2592        //
2593        // This is similar to the example given in
2594        // https://wiki.mozilla.org/APNG_Specification#Chunk_Sequence_Numbers:
2595        //
2596        // ```
2597        //    Sequence number    Chunk
2598        //    (none)             `acTL`
2599        //    0                  `fcTL` first frame
2600        //    (none)             `IDAT` first frame / default image
2601        //    1                  `fcTL` second frame
2602        //    2                  first `fdAT` for second frame
2603        //    3                  second `fdAT` for second frame
2604        // ```
2605        let png = {
2606            let mut png = Vec::new();
2607            write_fdat_prefix(&mut png, 2, 8);
2608            let image_data = generate_rgba8_with_width_and_height(8, 8);
2609            write_fdat(&mut png, 2, &image_data[..30]);
2610            write_fdat(&mut png, 3, &image_data[30..]);
2611            write_iend(&mut png);
2612            png
2613        };
2614
2615        // Start decoding.
2616        let decoder = Decoder::new(Cursor::new(&png));
2617        let mut reader = decoder.read_info().unwrap();
2618        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
2619        let Some(animation_control) = reader.info().animation_control else {
2620            panic!("No acTL");
2621        };
2622        assert_eq!(animation_control.num_frames, 2);
2623
2624        // Process the 1st animation frame.
2625        let first_frame: Vec<u8>;
2626        {
2627            reader.next_frame(&mut buf).unwrap();
2628            first_frame = buf.clone();
2629
2630            // Note that the doc comment of `Reader::next_frame` says that "[...]
2631            // can be checked afterwards by calling `info` **after** a successful call and
2632            // inspecting the `frame_control` data.".  (Note the **emphasis** on "after".)
2633            let Some(frame_control) = reader.info().frame_control else {
2634                panic!("No fcTL (1st frame)");
2635            };
2636            // The sequence number is taken from the `fcTL` chunk that comes before the `IDAT`
2637            // chunk.
2638            assert_eq!(frame_control.sequence_number, 0);
2639        }
2640
2641        // Process the 2nd animation frame.
2642        let second_frame: Vec<u8>;
2643        {
2644            reader.next_frame(&mut buf).unwrap();
2645            second_frame = buf.clone();
2646
2647            // Same as above - updated `frame_control` is available *after* the `next_frame` call.
2648            let Some(frame_control) = reader.info().frame_control else {
2649                panic!("No fcTL (2nd frame)");
2650            };
2651            // The sequence number is taken from the `fcTL` chunk that comes before the two `fdAT`
2652            // chunks.  Note that sequence numbers inside `fdAT` chunks are not publicly exposed
2653            // (but they are still checked when decoding to verify that they are sequential).
2654            assert_eq!(frame_control.sequence_number, 1);
2655        }
2656
2657        assert_eq!(first_frame, second_frame);
2658    }
2659
2660    #[test]
2661    fn test_idat_bigger_than_image_size_from_ihdr() {
2662        let png = {
2663            let mut png = Vec::new();
2664            write_png_sig(&mut png);
2665            write_rgba8_ihdr_with_width(&mut png, 8);
2666
2667            // Here we want to test an invalid image where the `IDAT` chunk contains more data
2668            // (data for 8x256 image) than declared in the `IHDR` chunk (which only describes an
2669            // 8x8 image).
2670            write_chunk(
2671                &mut png,
2672                b"IDAT",
2673                &generate_rgba8_with_width_and_height(8, 256),
2674            );
2675
2676            write_iend(&mut png);
2677            png
2678        };
2679        let decoder = Decoder::new(Cursor::new(&png));
2680        let mut reader = decoder.read_info().unwrap();
2681        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
2682
2683        // TODO: Should this return an error instead?  For now let's just have test assertions for
2684        // the current behavior.
2685        reader.next_frame(&mut buf).unwrap();
2686        assert_eq!(3093270825, crc32fast::hash(&buf));
2687    }
2688
2689    #[test]
2690    fn test_only_idat_chunk_in_input_stream() {
2691        let png = {
2692            let mut png = Vec::new();
2693            write_png_sig(&mut png);
2694            write_chunk(&mut png, b"IDAT", &[]);
2695            png
2696        };
2697        let decoder = Decoder::new(Cursor::new(&png));
2698        let Err(err) = decoder.read_info() else {
2699            panic!("Expected an error")
2700        };
2701        assert!(matches!(&err, DecodingError::Format(_)));
2702        assert_eq!(
2703            "ChunkType { type: IDAT, \
2704                         critical: true, \
2705                         private: false, \
2706                         reserved: false, \
2707                         safecopy: false \
2708             } chunk appeared before IHDR chunk",
2709            format!("{err}"),
2710        );
2711    }
2712
2713    /// `StreamingInput` can be used by tests to simulate a streaming input
2714    /// (e.g. a slow http response, where all bytes are not immediately available).
2715    #[derive(Clone)]
2716    struct StreamingInput {
2717        full_input: Vec<u8>,
2718        state: Rc<RefCell<StreamingInputState>>,
2719    }
2720
2721    struct StreamingInputState {
2722        current_pos: usize,
2723        available_len: usize,
2724    }
2725
2726    impl StreamingInput {
2727        fn new(full_input: Vec<u8>) -> Self {
2728            Self {
2729                full_input,
2730                state: Rc::new(RefCell::new(StreamingInputState {
2731                    current_pos: 0,
2732                    available_len: 0,
2733                })),
2734            }
2735        }
2736
2737        fn with_noncompressed_png(width: u32, idat_size: usize) -> Self {
2738            let mut png = Vec::new();
2739            write_noncompressed_png(&mut png, width, idat_size);
2740            Self::new(png)
2741        }
2742
2743        fn expose_next_byte(&self) {
2744            let mut state = self.state.borrow_mut();
2745            assert!(state.available_len < self.full_input.len());
2746            state.available_len += 1;
2747        }
2748
2749        fn stream_input_until_reader_is_available(&self) -> Reader<StreamingInput> {
2750            loop {
2751                self.state.borrow_mut().current_pos = 0;
2752                match Decoder::new(self.clone()).read_info() {
2753                    Ok(reader) => {
2754                        break reader;
2755                    }
2756                    Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2757                        self.expose_next_byte();
2758                    }
2759                    _ => panic!("Unexpected error"),
2760                }
2761            }
2762        }
2763
2764        fn decode_full_input<F, R>(&self, f: F) -> R
2765        where
2766            F: FnOnce(Reader<Cursor<&[u8]>>) -> R,
2767        {
2768            let decoder = Decoder::new(Cursor::new(&*self.full_input));
2769            f(decoder.read_info().unwrap())
2770        }
2771    }
2772
2773    impl Read for StreamingInput {
2774        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
2775            let mut state = self.state.borrow_mut();
2776            let mut available_bytes = &self.full_input[state.current_pos..state.available_len];
2777            let number_of_read_bytes = available_bytes.read(buf)?;
2778            state.current_pos += number_of_read_bytes;
2779            assert!(state.current_pos <= state.available_len);
2780            Ok(number_of_read_bytes)
2781        }
2782    }
2783    impl BufRead for StreamingInput {
2784        fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
2785            let state = self.state.borrow();
2786            Ok(&self.full_input[state.current_pos..state.available_len])
2787        }
2788
2789        fn consume(&mut self, amt: usize) {
2790            let mut state = self.state.borrow_mut();
2791            state.current_pos += amt;
2792            assert!(state.current_pos <= state.available_len);
2793        }
2794    }
2795    impl Seek for StreamingInput {
2796        fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
2797            let mut state = self.state.borrow_mut();
2798            state.current_pos = match pos {
2799                std::io::SeekFrom::Start(n) => n as usize,
2800                std::io::SeekFrom::End(n) => (self.full_input.len() as i64 + n) as usize,
2801                std::io::SeekFrom::Current(n) => (state.current_pos as i64 + n) as usize,
2802            } as usize;
2803            Ok(state.current_pos as u64)
2804        }
2805        fn stream_position(&mut self) -> std::io::Result<u64> {
2806            Ok(self.state.borrow().current_pos as u64)
2807        }
2808    }
2809
2810    /// Test resuming/retrying `Reader.next_frame` after `UnexpectedEof`.
2811    #[test]
2812    fn test_streaming_input_and_decoding_via_next_frame() {
2813        const WIDTH: u32 = 16;
2814        const IDAT_SIZE: usize = 512;
2815        let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2816
2817        let (whole_output_info, decoded_from_whole_input) =
2818            streaming_input.decode_full_input(|mut r| {
2819                let mut buf = vec![0; r.output_buffer_size().unwrap()];
2820                let output_info = r.next_frame(&mut buf).unwrap();
2821                (output_info, buf)
2822            });
2823
2824        let mut png_reader = streaming_input.stream_input_until_reader_is_available();
2825        let mut decoded_from_streaming_input = vec![0; png_reader.output_buffer_size().unwrap()];
2826        let streaming_output_info = loop {
2827            match png_reader.next_frame(decoded_from_streaming_input.as_mut_slice()) {
2828                Ok(output_info) => break output_info,
2829                Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2830                    streaming_input.expose_next_byte()
2831                }
2832                e => panic!("Unexpected error: {:?}", e),
2833            }
2834        };
2835        assert_eq!(whole_output_info, streaming_output_info);
2836        assert_eq!(
2837            crc32fast::hash(&decoded_from_whole_input),
2838            crc32fast::hash(&decoded_from_streaming_input)
2839        );
2840    }
2841
2842    /// Test resuming/retrying `Reader.next_row` after `UnexpectedEof`.
2843    #[test]
2844    fn test_streaming_input_and_decoding_via_next_row() {
2845        const WIDTH: u32 = 16;
2846        const IDAT_SIZE: usize = 512;
2847        let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2848
2849        let decoded_from_whole_input = streaming_input.decode_full_input(|mut r| {
2850            let mut buf = vec![0; r.output_buffer_size().unwrap()];
2851            r.next_frame(&mut buf).unwrap();
2852            buf
2853        });
2854
2855        let mut png_reader = streaming_input.stream_input_until_reader_is_available();
2856        let mut decoded_from_streaming_input = Vec::new();
2857        loop {
2858            match png_reader.next_row() {
2859                Ok(None) => break,
2860                Ok(Some(row)) => decoded_from_streaming_input.extend_from_slice(row.data()),
2861                Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2862                    streaming_input.expose_next_byte()
2863                }
2864                e => panic!("Unexpected error: {:?}", e),
2865            }
2866        }
2867        assert_eq!(
2868            crc32fast::hash(&decoded_from_whole_input),
2869            crc32fast::hash(&decoded_from_streaming_input)
2870        );
2871    }
2872
2873    /// Test resuming/retrying `Decoder.read_header_info` after `UnexpectedEof`.
2874    #[test]
2875    fn test_streaming_input_and_reading_header_info() {
2876        const WIDTH: u32 = 16;
2877        const IDAT_SIZE: usize = 512;
2878        let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2879
2880        let info_from_whole_input = streaming_input.decode_full_input(|r| r.info().clone());
2881
2882        let mut decoder = Decoder::new(streaming_input.clone());
2883        let info_from_streaming_input = loop {
2884            match decoder.read_header_info() {
2885                Ok(info) => break info.clone(),
2886                Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2887                    streaming_input.expose_next_byte()
2888                }
2889                e => panic!("Unexpected error: {:?}", e),
2890            }
2891        };
2892
2893        assert_eq!(info_from_whole_input.width, info_from_streaming_input.width);
2894        assert_eq!(
2895            info_from_whole_input.height,
2896            info_from_streaming_input.height
2897        );
2898        assert_eq!(
2899            info_from_whole_input.bit_depth,
2900            info_from_streaming_input.bit_depth
2901        );
2902        assert_eq!(
2903            info_from_whole_input.color_type,
2904            info_from_streaming_input.color_type
2905        );
2906        assert_eq!(
2907            info_from_whole_input.interlaced,
2908            info_from_streaming_input.interlaced
2909        );
2910    }
2911
2912    /// Creates a ready-to-test [`Reader`] which decodes a PNG that contains:
2913    /// IHDR, IDAT, IEND.
2914    fn create_reader_of_ihdr_idat() -> Reader<Cursor<Vec<u8>>> {
2915        let mut png = Vec::new();
2916        write_noncompressed_png(&mut png, /* width = */ 16, /* idat_size = */ 1024);
2917        Decoder::new(Cursor::new(png)).read_info().unwrap()
2918    }
2919
2920    /// Creates a ready-to-test [`Reader`] which decodes an animated PNG that contains:
2921    /// IHDR, acTL, fcTL, IDAT, fcTL, fdAT, IEND.  (i.e. IDAT is part of the animation)
2922    fn create_reader_of_ihdr_actl_fctl_idat_fctl_fdat() -> Reader<Cursor<Vec<u8>>> {
2923        let width = 16;
2924        let mut fctl = crate::FrameControl {
2925            width,
2926            height: width,
2927            ..Default::default()
2928        };
2929
2930        let mut png = Vec::new();
2931        write_png_sig(&mut png);
2932        write_rgba8_ihdr_with_width(&mut png, width);
2933        write_actl(
2934            &mut png,
2935            &crate::AnimationControl {
2936                num_frames: 2,
2937                num_plays: 0,
2938            },
2939        );
2940        fctl.sequence_number = 0;
2941        write_fctl(&mut png, &fctl);
2942        // Using `fctl.height + 1` means that the `IDAT` will have "left-over" data after
2943        // processing.  This helps to verify that `Reader.read_until_image_data` discards the
2944        // left-over data when resetting `UnfilteredRowsBuffer`.
2945        let idat_data = generate_rgba8_with_width_and_height(fctl.width, fctl.height + 1);
2946        write_chunk(&mut png, b"IDAT", &idat_data);
2947
2948        let fdat_width = 10;
2949        fctl.sequence_number = 1;
2950        // Using different width in `IDAT` and `fDAT` frames helps to catch problems that
2951        // may arise when `Reader.read_until_image_data` doesn't properly reset
2952        // `UnfilteredRowsBuffer`.
2953        fctl.width = fdat_width;
2954        write_fctl(&mut png, &fctl);
2955        let fdat_data = generate_rgba8_with_width_and_height(fctl.width, fctl.height);
2956        write_fdat(&mut png, 2, &fdat_data);
2957        write_iend(&mut png);
2958
2959        Decoder::new(Cursor::new(png)).read_info().unwrap()
2960    }
2961
2962    /// Creates a ready-to-test [`Reader`] which decodes an animated PNG that contains: IHDR, acTL,
2963    /// IDAT, fcTL, fdAT, fcTL, fdAT, IEND.  (i.e. IDAT is *not* part of the animation)
2964    fn create_reader_of_ihdr_actl_idat_fctl_fdat_fctl_fdat() -> Reader<Cursor<Vec<u8>>> {
2965        let width = 16;
2966        let frame_data = generate_rgba8_with_width_and_height(width, width);
2967        let mut fctl = crate::FrameControl {
2968            width,
2969            height: width,
2970            ..Default::default()
2971        };
2972
2973        let mut png = Vec::new();
2974        write_png_sig(&mut png);
2975        write_rgba8_ihdr_with_width(&mut png, width);
2976        write_actl(
2977            &mut png,
2978            &crate::AnimationControl {
2979                num_frames: 2,
2980                num_plays: 0,
2981            },
2982        );
2983        write_chunk(&mut png, b"IDAT", &frame_data);
2984        fctl.sequence_number = 0;
2985        write_fctl(&mut png, &fctl);
2986        write_fdat(&mut png, 1, &frame_data);
2987        fctl.sequence_number = 2;
2988        write_fctl(&mut png, &fctl);
2989        write_fdat(&mut png, 3, &frame_data);
2990        write_iend(&mut png);
2991
2992        Decoder::new(Cursor::new(png)).read_info().unwrap()
2993    }
2994
2995    fn get_fctl_sequence_number(reader: &Reader<impl BufRead + Seek>) -> u32 {
2996        reader
2997            .info()
2998            .frame_control
2999            .as_ref()
3000            .unwrap()
3001            .sequence_number
3002    }
3003
3004    /// Tests that [`Reader.next_frame`] will report a `PolledAfterEndOfImage` error when called
3005    /// after already decoding a single frame in a non-animated PNG.
3006    #[test]
3007    fn test_next_frame_polling_after_end_non_animated() {
3008        let mut reader = create_reader_of_ihdr_idat();
3009        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3010        reader
3011            .next_frame(&mut buf)
3012            .expect("Expecting no error for IDAT frame");
3013
3014        let err = reader
3015            .next_frame(&mut buf)
3016            .expect_err("Main test - expecting error");
3017        assert!(
3018            matches!(&err, DecodingError::Parameter(_)),
3019            "Unexpected kind of error: {:?}",
3020            &err,
3021        );
3022    }
3023
3024    /// Tests that [`Reader.next_frame_info`] will report a `PolledAfterEndOfImage` error when
3025    /// called when decoding a PNG that only contains a single frame.
3026    #[test]
3027    fn test_next_frame_info_polling_after_end_non_animated() {
3028        let mut reader = create_reader_of_ihdr_idat();
3029
3030        let err = reader
3031            .next_frame_info()
3032            .expect_err("Main test - expecting error");
3033        assert!(
3034            matches!(&err, DecodingError::Parameter(_)),
3035            "Unexpected kind of error: {:?}",
3036            &err,
3037        );
3038    }
3039
3040    /// Tests that [`Reader.next_frame`] will report a `PolledAfterEndOfImage` error when called
3041    /// after already decoding a single frame in an animated PNG where IDAT is part of the
3042    /// animation.
3043    #[test]
3044    fn test_next_frame_polling_after_end_idat_part_of_animation() {
3045        let mut reader = create_reader_of_ihdr_actl_fctl_idat_fctl_fdat();
3046        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3047
3048        assert_eq!(get_fctl_sequence_number(&reader), 0);
3049        reader
3050            .next_frame(&mut buf)
3051            .expect("Expecting no error for IDAT frame");
3052
3053        // `next_frame` doesn't advance to the next `fcTL`.
3054        assert_eq!(get_fctl_sequence_number(&reader), 0);
3055
3056        reader
3057            .next_frame(&mut buf)
3058            .expect("Expecting no error for fdAT frame");
3059        assert_eq!(get_fctl_sequence_number(&reader), 1);
3060
3061        let err = reader
3062            .next_frame(&mut buf)
3063            .expect_err("Main test - expecting error");
3064        assert!(
3065            matches!(&err, DecodingError::Parameter(_)),
3066            "Unexpected kind of error: {:?}",
3067            &err,
3068        );
3069    }
3070
3071    /// Tests that [`Reader.next_frame`] will report a `PolledAfterEndOfImage` error when called
3072    /// after already decoding a single frame in an animated PNG where IDAT is *not* part of the
3073    /// animation.
3074    #[test]
3075    fn test_next_frame_polling_after_end_idat_not_part_of_animation() {
3076        let mut reader = create_reader_of_ihdr_actl_idat_fctl_fdat_fctl_fdat();
3077        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3078
3079        assert!(reader.info().frame_control.is_none());
3080        reader
3081            .next_frame(&mut buf)
3082            .expect("Expecting no error for IDAT frame");
3083
3084        // `next_frame` doesn't advance to the next `fcTL`.
3085        assert!(reader.info().frame_control.is_none());
3086
3087        reader
3088            .next_frame(&mut buf)
3089            .expect("Expecting no error for 1st fdAT frame");
3090        assert_eq!(get_fctl_sequence_number(&reader), 0);
3091
3092        reader
3093            .next_frame(&mut buf)
3094            .expect("Expecting no error for 2nd fdAT frame");
3095        assert_eq!(get_fctl_sequence_number(&reader), 2);
3096
3097        let err = reader
3098            .next_frame(&mut buf)
3099            .expect_err("Main test - expecting error");
3100        assert!(
3101            matches!(&err, DecodingError::Parameter(_)),
3102            "Unexpected kind of error: {:?}",
3103            &err,
3104        );
3105    }
3106
3107    /// Tests that after decoding a whole frame via [`Reader.next_row`] the call to
3108    /// [`Reader.next_frame`] will decode the **next** frame.
3109    #[test]
3110    fn test_row_by_row_then_next_frame() {
3111        let mut reader = create_reader_of_ihdr_actl_fctl_idat_fctl_fdat();
3112        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3113
3114        assert_eq!(get_fctl_sequence_number(&reader), 0);
3115        while let Some(_) = reader.next_row().unwrap() {}
3116        assert_eq!(get_fctl_sequence_number(&reader), 0);
3117
3118        buf.fill(0x0f);
3119        reader
3120            .next_frame(&mut buf)
3121            .expect("Expecting no error from next_frame call");
3122
3123        // Verify if we have read the next `fcTL` chunk + repopulated `buf`:
3124        assert_eq!(get_fctl_sequence_number(&reader), 1);
3125        assert!(buf.iter().any(|byte| *byte != 0x0f));
3126    }
3127
3128    /// Tests that after decoding a whole frame via [`Reader.next_row`] it is possible
3129    /// to use [`Reader.next_row`] to decode the next frame (by using the `next_frame_info` API to
3130    /// advance to the next frame when `next_row` returns `None`).
3131    #[test]
3132    fn test_row_by_row_of_two_frames() {
3133        let mut reader = create_reader_of_ihdr_actl_fctl_idat_fctl_fdat();
3134
3135        let mut rows_of_frame1 = 0;
3136        assert_eq!(get_fctl_sequence_number(&reader), 0);
3137        while let Some(_) = reader.next_row().unwrap() {
3138            rows_of_frame1 += 1;
3139        }
3140        assert_eq!(rows_of_frame1, 16);
3141        assert_eq!(get_fctl_sequence_number(&reader), 0);
3142
3143        let mut rows_of_frame2 = 0;
3144        assert_eq!(reader.next_frame_info().unwrap().sequence_number, 1);
3145        assert_eq!(get_fctl_sequence_number(&reader), 1);
3146        while let Some(_) = reader.next_row().unwrap() {
3147            rows_of_frame2 += 1;
3148        }
3149        assert_eq!(rows_of_frame2, 16);
3150        assert_eq!(get_fctl_sequence_number(&reader), 1);
3151
3152        let err = reader
3153            .next_frame_info()
3154            .expect_err("No more frames - expecting error");
3155        assert!(
3156            matches!(&err, DecodingError::Parameter(_)),
3157            "Unexpected kind of error: {:?}",
3158            &err,
3159        );
3160    }
3161
3162    /// This test is similar to `test_next_frame_polling_after_end_idat_part_of_animation`, but it
3163    /// uses `next_frame_info` calls to read to the next `fcTL` earlier - before the next call to
3164    /// `next_frame` (knowing `fcTL` before calling `next_frame` may be helpful to determine the
3165    /// size of the output buffer and/or to prepare the buffer based on the `DisposeOp` of the
3166    /// previous frames).
3167    #[test]
3168    fn test_next_frame_info_after_next_frame() {
3169        let mut reader = create_reader_of_ihdr_actl_fctl_idat_fctl_fdat();
3170        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3171
3172        assert_eq!(get_fctl_sequence_number(&reader), 0);
3173        reader
3174            .next_frame(&mut buf)
3175            .expect("Expecting no error for IDAT frame");
3176
3177        // `next_frame` doesn't advance to the next `fcTL`.
3178        assert_eq!(get_fctl_sequence_number(&reader), 0);
3179
3180        // But `next_frame_info` can be used to go to the next `fcTL`.
3181        assert_eq!(reader.next_frame_info().unwrap().sequence_number, 1);
3182        assert_eq!(get_fctl_sequence_number(&reader), 1);
3183
3184        reader
3185            .next_frame(&mut buf)
3186            .expect("Expecting no error for fdAT frame");
3187        assert_eq!(get_fctl_sequence_number(&reader), 1);
3188
3189        let err = reader
3190            .next_frame_info()
3191            .expect_err("Main test - expecting error");
3192        assert!(
3193            matches!(&err, DecodingError::Parameter(_)),
3194            "Unexpected kind of error: {:?}",
3195            &err,
3196        );
3197    }
3198
3199    /// This test is similar to `test_next_frame_polling_after_end_idat_not_part_of_animation`, but
3200    /// it uses `next_frame_info` to skip the `IDAT` frame entirely + to move between frames.
3201    #[test]
3202    fn test_next_frame_info_to_skip_first_frame() {
3203        let mut reader = create_reader_of_ihdr_actl_idat_fctl_fdat_fctl_fdat();
3204        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3205
3206        // First (IDAT) frame doesn't have frame control info, which means
3207        // that it is not part of the animation.
3208        assert!(reader.info().frame_control.is_none());
3209
3210        // `next_frame_info` can be used to skip the IDAT frame (without first having to separately
3211        // discard the image data - e.g. by also calling `next_frame` first).
3212        assert_eq!(reader.next_frame_info().unwrap().sequence_number, 0);
3213        assert_eq!(get_fctl_sequence_number(&reader), 0);
3214        reader
3215            .next_frame(&mut buf)
3216            .expect("Expecting no error for 1st fdAT frame");
3217        assert_eq!(get_fctl_sequence_number(&reader), 0);
3218
3219        // Get the `fcTL` for the 2nd frame.
3220        assert_eq!(reader.next_frame_info().unwrap().sequence_number, 2);
3221        reader
3222            .next_frame(&mut buf)
3223            .expect("Expecting no error for 2nd fdAT frame");
3224        assert_eq!(get_fctl_sequence_number(&reader), 2);
3225
3226        let err = reader
3227            .next_frame_info()
3228            .expect_err("Main test - expecting error");
3229        assert!(
3230            matches!(&err, DecodingError::Parameter(_)),
3231            "Unexpected kind of error: {:?}",
3232            &err,
3233        );
3234    }
3235
3236    #[test]
3237    fn test_incorrect_trns_chunk_is_ignored() {
3238        let png = {
3239            let mut png = Vec::new();
3240            write_png_sig(&mut png);
3241            write_rgba8_ihdr_with_width(&mut png, 8);
3242            write_chunk(&mut png, b"tRNS", &[12, 34, 56]);
3243            write_chunk(
3244                &mut png,
3245                b"IDAT",
3246                &generate_rgba8_with_width_and_height(8, 8),
3247            );
3248            write_iend(&mut png);
3249            png
3250        };
3251        let decoder = Decoder::new(Cursor::new(&png));
3252        let mut reader = decoder.read_info().unwrap();
3253        let mut buf = vec![0; reader.output_buffer_size().unwrap()];
3254        assert!(reader.info().trns.is_none());
3255        reader.next_frame(&mut buf).unwrap();
3256        assert_eq!(3093270825, crc32fast::hash(&buf));
3257        assert!(reader.info().trns.is_none());
3258    }
3259
3260    /// This is a regression test for https://crbug.com/422421347
3261    #[test]
3262    fn test_actl_num_frames_zero() {
3263        let width = 16;
3264        let frame_data = generate_rgba8_with_width_and_height(width, width);
3265
3266        let mut png = Vec::new();
3267        write_png_sig(&mut png);
3268        write_rgba8_ihdr_with_width(&mut png, width);
3269        write_actl(
3270            &mut png,
3271            &crate::AnimationControl {
3272                num_frames: 0, // <= spec violation needed by this test
3273                num_plays: 0,
3274            },
3275        );
3276        // Presence of an `fcTL` chunk will prevent incrementing
3277        // `num_frames` when calculating `remaining_frames` in
3278        // `Decoder::read_info`.  So the test writes an `fcTL` chunk
3279        // to end up with `remaining_frames == 0` if `parse_actl` allows
3280        // `num_frames == 0`.
3281        write_fctl(
3282            &mut png,
3283            &crate::FrameControl {
3284                width,
3285                height: width,
3286                ..Default::default()
3287            },
3288        );
3289        write_chunk(&mut png, b"IDAT", &frame_data);
3290        write_iend(&mut png);
3291
3292        let mut reader = Decoder::new(Cursor::new(png)).read_info().unwrap();
3293
3294        // Using `next_interlaced_row` in the test, because it doesn't check
3295        // `Reader::remaining_frames` (unlike `next_frame`), because it assumes that either
3296        // `read_info` or `next_frame` leave `Reader` in a valid state.
3297        //
3298        // The test passes if these `next_interlaced_row` calls don't hit any `assert!` failures.
3299        while let Some(_row) = reader.next_interlaced_row().unwrap() {}
3300    }
3301
3302    #[test]
3303    fn test_small_fctl() {
3304        const FCTL_SIZE: u32 = 30;
3305        const IHDR_SIZE: u32 = 50;
3306        let mut png = Vec::new();
3307        write_png_sig(&mut png);
3308        write_rgba8_ihdr_with_width(&mut png, IHDR_SIZE);
3309        write_actl(
3310            &mut png,
3311            &crate::AnimationControl {
3312                num_frames: 1,
3313                num_plays: 1,
3314            },
3315        );
3316        write_fctl(
3317            &mut png,
3318            &crate::FrameControl {
3319                width: FCTL_SIZE,
3320                height: FCTL_SIZE,
3321                x_offset: 10,
3322                y_offset: 10,
3323                sequence_number: 0,
3324                ..Default::default()
3325            },
3326        );
3327        write_chunk(
3328            &mut png,
3329            b"IDAT",
3330            &generate_rgba8_with_width_and_height(IHDR_SIZE, IHDR_SIZE),
3331        );
3332        write_iend(&mut png);
3333
3334        let reader = Decoder::new(Cursor::new(png)).read_info();
3335        let err = reader.err().unwrap();
3336        assert!(matches!(&err, DecodingError::Format(_)));
3337        assert_eq!("Sub frame is out-of-bounds.", format!("{err}"));
3338    }
3339
3340    #[test]
3341    fn test_invalid_text_chunk() {
3342        // The spec requires a NUL character (separating keyword from text) within the first 80
3343        // bytes of the chunk.  Here there is no NUL character in the first 100 bytes, so this
3344        // chunk is invalid and should trigger an error in `parse_text`.
3345        let invalid_text_chunk = vec![b'A'; 100];
3346
3347        const SIZE: u32 = 20;
3348        let mut png = Vec::new();
3349        write_png_sig(&mut png);
3350        write_rgba8_ihdr_with_width(&mut png, SIZE);
3351        write_chunk(&mut png, b"tEXt", invalid_text_chunk.as_slice());
3352        write_chunk(
3353            &mut png,
3354            b"IDAT",
3355            &generate_rgba8_with_width_and_height(SIZE, SIZE),
3356        );
3357        write_iend(&mut png);
3358
3359        let reader = Decoder::new(Cursor::new(png)).read_info().unwrap();
3360        let info = reader.info();
3361        assert_eq!(info.width, SIZE);
3362        assert_eq!(info.uncompressed_latin1_text.len(), 0);
3363    }
3364
3365    /// This is a regression test for https://crbug.com/451710590.
3366    #[test]
3367    fn test_duplicate_actl_chunk() {
3368        let width = 16;
3369        let frame_data = generate_rgba8_with_width_and_height(width, width);
3370
3371        let mut png = Vec::new();
3372        write_png_sig(&mut png);
3373        write_rgba8_ihdr_with_width(&mut png, width);
3374        write_actl(
3375            &mut png,
3376            &crate::AnimationControl {
3377                num_frames: 2,
3378                num_plays: 123,
3379            },
3380        );
3381        write_actl(
3382            &mut png,
3383            &crate::AnimationControl {
3384                num_frames: 1, // <- should be ignored
3385                num_plays: 456,
3386            },
3387        );
3388        write_chunk(&mut png, b"IDAT", &frame_data);
3389        write_iend(&mut png);
3390
3391        let reader = Decoder::new(Cursor::new(png)).read_info().unwrap();
3392        let Some(actl) = reader.info().animation_control.as_ref() else {
3393            panic!("No `animation_control`?")
3394        };
3395        assert_eq!(actl.num_frames, 2);
3396        assert_eq!(actl.num_plays, 123);
3397    }
3398}