Coverage Report

Created: 2025-07-11 07:11

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