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