Coverage Report

Created: 2026-02-14 07:04

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