Coverage Report

Created: 2025-07-01 06:50

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