Coverage Report

Created: 2026-01-22 07:28

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