@@ -524,6 +524,10 @@ pub struct StreamingDecoder {
524
524
inflater : ZlibStream ,
525
525
/// The complete image info read from all prior chunks.
526
526
pub ( crate ) info : Option < Info < ' static > > ,
527
+
528
+ /// Non-fatal errors during decoding
529
+ warnings : Vec < ( ChunkType , DecodingError ) > ,
530
+
527
531
/// The animation chunk sequence number.
528
532
current_seq_no : Option < u32 > ,
529
533
/// Whether we have already seen a start of an IDAT chunk. (Used to validate chunk ordering -
@@ -574,6 +578,7 @@ impl StreamingDecoder {
574
578
current_chunk : ChunkState :: default ( ) ,
575
579
inflater,
576
580
info : None ,
581
+ warnings : Vec :: new ( ) ,
577
582
current_seq_no : None ,
578
583
have_idat : false ,
579
584
have_iccp : false ,
@@ -592,6 +597,7 @@ impl StreamingDecoder {
592
597
self . current_chunk . raw_bytes . clear ( ) ;
593
598
self . inflater . reset ( ) ;
594
599
self . info = None ;
600
+ self . warnings . clear ( ) ;
595
601
self . current_seq_no = None ;
596
602
self . have_idat = false ;
597
603
}
@@ -641,6 +647,13 @@ impl StreamingDecoder {
641
647
. set_skip_ancillary_crc_failures ( skip_ancillary_crc_failures)
642
648
}
643
649
650
+ /// Non-fatal errors encoutered when parsing ancillary chunks
651
+ ///
652
+ /// Please also check getters on [`Info`], since some chunks may be parsed lazily
653
+ pub fn warnings ( & self ) -> & [ ( ChunkType , DecodingError ) ] {
654
+ & self . warnings
655
+ }
656
+
644
657
/// Low level StreamingDecoder interface.
645
658
///
646
659
/// Allows to stream partial data to the encoder. Returns a tuple containing the bytes that have
@@ -984,32 +997,42 @@ impl StreamingDecoder {
984
997
chunk:: fcTL => self . parse_fctl ( ) ,
985
998
chunk:: cHRM => self . parse_chrm ( ) ,
986
999
chunk:: sRGB => self . parse_srgb ( ) ,
987
- chunk:: cICP => Ok ( self . parse_cicp ( ) ) ,
988
- chunk:: mDCV => Ok ( self . parse_mdcv ( ) ) ,
989
- chunk:: cLLI => Ok ( self . parse_clli ( ) ) ,
990
- chunk:: bKGD => Ok ( self . parse_bkgd ( ) ) ,
1000
+ chunk:: cICP => self . parse_cicp ( ) ,
1001
+ chunk:: mDCV => self . parse_mdcv ( ) ,
1002
+ chunk:: cLLI => self . parse_clli ( ) ,
1003
+ chunk:: bKGD => self . parse_bkgd ( ) ,
991
1004
chunk:: iCCP if !self . decode_options . ignore_iccp_chunk => self . parse_iccp ( ) ,
992
1005
chunk:: tEXt if !self . decode_options . ignore_text_chunk => self . parse_text ( ) ,
993
1006
chunk:: zTXt if !self . decode_options . ignore_text_chunk => self . parse_ztxt ( ) ,
994
1007
chunk:: iTXt if !self . decode_options . ignore_text_chunk => self . parse_itxt ( ) ,
995
- _ => Ok ( Decoded :: PartialChunk ( type_str) ) ,
1008
+ _ => return Ok ( Decoded :: PartialChunk ( type_str) ) ,
996
1009
} ;
997
1010
998
- parse_result. map_err ( |e| {
999
- self . state = None ;
1000
- match e {
1011
+ match parse_result {
1012
+ Ok ( ok) => Ok ( ok) ,
1013
+ // ignore ancillary chunk failures (apng extensions are de-facto critical)
1014
+ Err ( err)
1015
+ if !chunk:: is_critical ( type_str)
1016
+ && type_str != chunk:: acTL
1017
+ && type_str != chunk:: fcTL =>
1018
+ {
1019
+ self . warnings . push ( ( type_str, err) ) ;
1020
+ Ok ( Decoded :: Nothing )
1021
+ }
1022
+ Err ( DecodingError :: IoError ( e) ) if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof => {
1001
1023
// `parse_chunk` is invoked after gathering **all** bytes of a chunk, so
1002
1024
// `UnexpectedEof` from something like `read_be` is permanent and indicates an
1003
1025
// invalid PNG that should be represented as a `FormatError`, rather than as a
1004
1026
// (potentially recoverable) `IoError` / `UnexpectedEof`.
1005
- DecodingError :: IoError ( e) if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof => {
1006
- let fmt_err: FormatError =
1007
- FormatErrorInner :: ChunkTooShort { kind : type_str } . into ( ) ;
1008
- fmt_err. into ( )
1009
- }
1010
- e => e,
1027
+ self . state = None ;
1028
+ let fmt_err = FormatError :: from ( FormatErrorInner :: ChunkTooShort { kind : type_str } ) ;
1029
+ Err ( fmt_err. into ( ) )
1011
1030
}
1012
- } )
1031
+ Err ( err) => {
1032
+ self . state = None ;
1033
+ Err ( err)
1034
+ }
1035
+ }
1013
1036
}
1014
1037
1015
1038
fn parse_fctl ( & mut self ) -> Result < Decoded , DecodingError > {
@@ -1108,32 +1131,27 @@ impl StreamingDecoder {
1108
1131
}
1109
1132
1110
1133
fn parse_sbit ( & mut self ) -> Result < Decoded , DecodingError > {
1111
- let mut parse = || {
1112
- let info = self . info . as_mut ( ) . unwrap ( ) ;
1113
- if info. palette . is_some ( ) {
1114
- return Err ( DecodingError :: Format (
1115
- FormatErrorInner :: AfterPlte { kind : chunk:: sBIT } . into ( ) ,
1116
- ) ) ;
1117
- }
1118
-
1119
- if self . have_idat {
1120
- return Err ( DecodingError :: Format (
1121
- FormatErrorInner :: AfterIdat { kind : chunk:: sBIT } . into ( ) ,
1122
- ) ) ;
1123
- }
1134
+ let info = self . info . as_mut ( ) . unwrap ( ) ;
1135
+ if info. palette . is_some ( ) {
1136
+ return Err ( DecodingError :: Format (
1137
+ FormatErrorInner :: AfterPlte { kind : chunk:: sBIT } . into ( ) ,
1138
+ ) ) ;
1139
+ }
1124
1140
1125
- if info . sbit . is_some ( ) {
1126
- return Err ( DecodingError :: Format (
1127
- FormatErrorInner :: DuplicateChunk { kind : chunk:: sBIT } . into ( ) ,
1128
- ) ) ;
1129
- }
1141
+ if self . have_idat {
1142
+ return Err ( DecodingError :: Format (
1143
+ FormatErrorInner :: AfterIdat { kind : chunk:: sBIT } . into ( ) ,
1144
+ ) ) ;
1145
+ }
1130
1146
1131
- let vec = mem:: take ( & mut self . current_chunk . raw_bytes ) ;
1132
- info. sbit = Some ( Cow :: Owned ( vec) ) ;
1133
- Ok ( Decoded :: Nothing )
1134
- } ;
1147
+ if info. sbit . is_some ( ) {
1148
+ return Err ( DecodingError :: Format (
1149
+ FormatErrorInner :: DuplicateChunk { kind : chunk:: sBIT } . into ( ) ,
1150
+ ) ) ;
1151
+ }
1135
1152
1136
- parse ( ) . ok ( ) ;
1153
+ let vec = mem:: take ( & mut self . current_chunk . raw_bytes ) ;
1154
+ info. sbit = Some ( Cow :: Owned ( vec) ) ;
1137
1155
Ok ( Decoded :: Nothing )
1138
1156
}
1139
1157
@@ -1315,10 +1333,7 @@ impl StreamingDecoder {
1315
1333
}
1316
1334
}
1317
1335
1318
- // NOTE: This function cannot return `DecodingError` and handles parsing
1319
- // errors or spec violations as-if the chunk was missing. See
1320
- // https://github.com/image-rs/image-png/issues/525 for more discussion.
1321
- fn parse_cicp ( & mut self ) -> Decoded {
1336
+ fn parse_cicp ( & mut self ) -> Result < Decoded , DecodingError > {
1322
1337
fn parse ( mut buf : & [ u8 ] ) -> Result < CodingIndependentCodePoints , std:: io:: Error > {
1323
1338
let color_primaries: u8 = buf. read_be ( ) ?;
1324
1339
let transfer_function: u8 = buf. read_be ( ) ?;
@@ -1357,16 +1372,13 @@ impl StreamingDecoder {
1357
1372
let info = self . info . as_mut ( ) . unwrap ( ) ;
1358
1373
let is_before_plte_and_idat = !self . have_idat && info. palette . is_none ( ) ;
1359
1374
if is_before_plte_and_idat && info. coding_independent_code_points . is_none ( ) {
1360
- info. coding_independent_code_points = parse ( & self . current_chunk . raw_bytes [ ..] ) . ok ( ) ;
1375
+ info. coding_independent_code_points = Some ( parse ( & self . current_chunk . raw_bytes [ ..] ) ? ) ;
1361
1376
}
1362
1377
1363
- Decoded :: Nothing
1378
+ Ok ( Decoded :: Nothing )
1364
1379
}
1365
1380
1366
- // NOTE: This function cannot return `DecodingError` and handles parsing
1367
- // errors or spec violations as-if the chunk was missing. See
1368
- // https://github.com/image-rs/image-png/issues/525 for more discussion.
1369
- fn parse_mdcv ( & mut self ) -> Decoded {
1381
+ fn parse_mdcv ( & mut self ) -> Result < Decoded , DecodingError > {
1370
1382
fn parse ( mut buf : & [ u8 ] ) -> Result < MasteringDisplayColorVolume , std:: io:: Error > {
1371
1383
let red_x: u16 = buf. read_be ( ) ?;
1372
1384
let red_y: u16 = buf. read_be ( ) ?;
@@ -1408,16 +1420,13 @@ impl StreamingDecoder {
1408
1420
let info = self . info . as_mut ( ) . unwrap ( ) ;
1409
1421
let is_before_plte_and_idat = !self . have_idat && info. palette . is_none ( ) ;
1410
1422
if is_before_plte_and_idat && info. mastering_display_color_volume . is_none ( ) {
1411
- info. mastering_display_color_volume = parse ( & self . current_chunk . raw_bytes [ ..] ) . ok ( ) ;
1423
+ info. mastering_display_color_volume = Some ( parse ( & self . current_chunk . raw_bytes [ ..] ) ? ) ;
1412
1424
}
1413
1425
1414
- Decoded :: Nothing
1426
+ Ok ( Decoded :: Nothing )
1415
1427
}
1416
1428
1417
- // NOTE: This function cannot return `DecodingError` and handles parsing
1418
- // errors or spec violations as-if the chunk was missing. See
1419
- // https://github.com/image-rs/image-png/issues/525 for more discussion.
1420
- fn parse_clli ( & mut self ) -> Decoded {
1429
+ fn parse_clli ( & mut self ) -> Result < Decoded , DecodingError > {
1421
1430
fn parse ( mut buf : & [ u8 ] ) -> Result < ContentLightLevelInfo , std:: io:: Error > {
1422
1431
let max_content_light_level: u32 = buf. read_be ( ) ?;
1423
1432
let max_frame_average_light_level: u32 = buf. read_be ( ) ?;
@@ -1433,10 +1442,10 @@ impl StreamingDecoder {
1433
1442
// We ignore a second, duplicated cLLI chunk (if any).
1434
1443
let info = self . info . as_mut ( ) . unwrap ( ) ;
1435
1444
if info. content_light_level . is_none ( ) {
1436
- info. content_light_level = parse ( & self . current_chunk . raw_bytes [ ..] ) . ok ( ) ;
1445
+ info. content_light_level = Some ( parse ( & self . current_chunk . raw_bytes [ ..] ) ? ) ;
1437
1446
}
1438
1447
1439
- Decoded :: Nothing
1448
+ Ok ( Decoded :: Nothing )
1440
1449
}
1441
1450
1442
1451
fn parse_iccp ( & mut self ) -> Result < Decoded , DecodingError > {
@@ -1459,7 +1468,7 @@ impl StreamingDecoder {
1459
1468
Ok ( Decoded :: Nothing )
1460
1469
} else {
1461
1470
self . have_iccp = true ;
1462
- let _ = self . parse_iccp_raw ( ) ;
1471
+ self . parse_iccp_raw ( ) ? ;
1463
1472
Ok ( Decoded :: Nothing )
1464
1473
}
1465
1474
}
@@ -1699,16 +1708,16 @@ impl StreamingDecoder {
1699
1708
Ok ( Decoded :: Nothing )
1700
1709
}
1701
1710
1702
- // NOTE: This function cannot return `DecodingError` and handles parsing
1703
- // errors or spec violations as-if the chunk was missing. See
1704
- // https://github.com/image-rs/image-png/issues/525 for more discussion.
1705
- fn parse_bkgd ( & mut self ) -> Decoded {
1711
+ fn parse_bkgd ( & mut self ) -> Result < Decoded , DecodingError > {
1706
1712
let info = self . info . as_mut ( ) . unwrap ( ) ;
1707
1713
if info. bkgd . is_none ( ) && !self . have_idat {
1708
1714
let expected = match info. color_type {
1709
1715
ColorType :: Indexed => {
1710
1716
if info. palette . is_none ( ) {
1711
- return Decoded :: Nothing ;
1717
+ return Err ( FormatError :: from ( FormatErrorInner :: InvalidColorType (
1718
+ ColorType :: Indexed as _ ,
1719
+ ) )
1720
+ . into ( ) ) ;
1712
1721
} ;
1713
1722
1
1714
1723
}
@@ -1719,10 +1728,15 @@ impl StreamingDecoder {
1719
1728
let len = vec. len ( ) ;
1720
1729
if len == expected {
1721
1730
info. bkgd = Some ( Cow :: Owned ( vec) ) ;
1731
+ } else {
1732
+ return Err ( FormatError :: from ( FormatErrorInner :: ChunkTooShort {
1733
+ kind : chunk:: bKGD,
1734
+ } )
1735
+ . into ( ) ) ;
1722
1736
}
1723
1737
}
1724
1738
1725
- Decoded :: Nothing
1739
+ Ok ( Decoded :: Nothing )
1726
1740
}
1727
1741
}
1728
1742
0 commit comments