@@ -975,7 +975,7 @@ impl StreamingDecoder {
975
975
976
976
fn parse_chunk ( & mut self , type_str : ChunkType ) -> Result < Decoded , DecodingError > {
977
977
self . state = Some ( State :: new_u32 ( U32ValueKind :: Crc ( type_str) ) ) ;
978
- let parse_result = match type_str {
978
+ let mut parse_result = match type_str {
979
979
IHDR => self . parse_ihdr ( ) ,
980
980
chunk:: sBIT => self . parse_sbit ( ) ,
981
981
chunk:: PLTE => self . parse_plte ( ) ,
@@ -998,8 +998,7 @@ impl StreamingDecoder {
998
998
_ => Ok ( Decoded :: PartialChunk ( type_str) ) ,
999
999
} ;
1000
1000
1001
- parse_result. map_err ( |e| {
1002
- self . state = None ;
1001
+ parse_result = parse_result. map_err ( |e| {
1003
1002
match e {
1004
1003
// `parse_chunk` is invoked after gathering **all** bytes of a chunk, so
1005
1004
// `UnexpectedEof` from something like `read_be` is permanent and indicates an
@@ -1012,7 +1011,37 @@ impl StreamingDecoder {
1012
1011
}
1013
1012
e => e,
1014
1013
}
1015
- } )
1014
+ } ) ;
1015
+
1016
+ // Ignore benign errors in some auxiliary chunks. `LimitsExceeded`, `Parameter`
1017
+ // and other error kinds are *not* treated as benign. We only ignore errors in *some*
1018
+ // auxiliary chunks (i.e. we don't use `chunk::is_critical`), because for chunks like
1019
+ // `fcTL` or `fdAT` the fallback to the static/non-animated image has to be implemented
1020
+ // *on top* of the `StreamingDecoder` API.
1021
+ //
1022
+ // TODO: Consider supporting a strict mode where even benign errors are reported up.
1023
+ // See https://github.com/image-rs/image-png/pull/569#issuecomment-2642062285
1024
+ if matches ! ( parse_result. as_ref( ) , Err ( DecodingError :: Format ( _) ) )
1025
+ && matches ! (
1026
+ type_str,
1027
+ chunk:: cHRM
1028
+ | chunk:: gAMA
1029
+ | chunk:: iCCP
1030
+ | chunk:: pHYs
1031
+ | chunk:: sBIT
1032
+ | chunk:: sRGB
1033
+ | chunk:: tRNS
1034
+ )
1035
+ {
1036
+ parse_result = Ok ( Decoded :: Nothing ) ;
1037
+ }
1038
+
1039
+ // Clear the parsing state to enforce that parsing can't continue after an error.
1040
+ if parse_result. is_err ( ) {
1041
+ self . state = None ;
1042
+ }
1043
+
1044
+ parse_result
1016
1045
}
1017
1046
1018
1047
fn parse_fctl ( & mut self ) -> Result < Decoded , DecodingError > {
@@ -1113,74 +1142,69 @@ impl StreamingDecoder {
1113
1142
}
1114
1143
1115
1144
fn parse_sbit ( & mut self ) -> Result < Decoded , DecodingError > {
1116
- let mut parse = || {
1117
- let info = self . info . as_mut ( ) . unwrap ( ) ;
1118
- if info. palette . is_some ( ) {
1119
- return Err ( DecodingError :: Format (
1120
- FormatErrorInner :: AfterPlte { kind : chunk:: sBIT } . into ( ) ,
1121
- ) ) ;
1122
- }
1145
+ let info = self . info . as_mut ( ) . unwrap ( ) ;
1146
+ if info. palette . is_some ( ) {
1147
+ return Err ( DecodingError :: Format (
1148
+ FormatErrorInner :: AfterPlte { kind : chunk:: sBIT } . into ( ) ,
1149
+ ) ) ;
1150
+ }
1123
1151
1124
- if self . have_idat {
1125
- return Err ( DecodingError :: Format (
1126
- FormatErrorInner :: AfterIdat { kind : chunk:: sBIT } . into ( ) ,
1127
- ) ) ;
1128
- }
1152
+ if self . have_idat {
1153
+ return Err ( DecodingError :: Format (
1154
+ FormatErrorInner :: AfterIdat { kind : chunk:: sBIT } . into ( ) ,
1155
+ ) ) ;
1156
+ }
1129
1157
1130
- if info. sbit . is_some ( ) {
1131
- return Err ( DecodingError :: Format (
1132
- FormatErrorInner :: DuplicateChunk { kind : chunk:: sBIT } . into ( ) ,
1133
- ) ) ;
1134
- }
1158
+ if info. sbit . is_some ( ) {
1159
+ return Err ( DecodingError :: Format (
1160
+ FormatErrorInner :: DuplicateChunk { kind : chunk:: sBIT } . into ( ) ,
1161
+ ) ) ;
1162
+ }
1135
1163
1136
- let ( color_type, bit_depth) = { ( info. color_type , info. bit_depth ) } ;
1137
- // The sample depth for color type 3 is fixed at eight bits.
1138
- let sample_depth = if color_type == ColorType :: Indexed {
1139
- BitDepth :: Eight
1140
- } else {
1141
- bit_depth
1142
- } ;
1143
- self . limits
1144
- . reserve_bytes ( self . current_chunk . raw_bytes . len ( ) ) ?;
1145
- let vec = self . current_chunk . raw_bytes . clone ( ) ;
1146
- let len = vec. len ( ) ;
1164
+ let ( color_type, bit_depth) = { ( info. color_type , info. bit_depth ) } ;
1165
+ // The sample depth for color type 3 is fixed at eight bits.
1166
+ let sample_depth = if color_type == ColorType :: Indexed {
1167
+ BitDepth :: Eight
1168
+ } else {
1169
+ bit_depth
1170
+ } ;
1171
+ self . limits
1172
+ . reserve_bytes ( self . current_chunk . raw_bytes . len ( ) ) ?;
1173
+ let vec = self . current_chunk . raw_bytes . clone ( ) ;
1174
+ let len = vec. len ( ) ;
1147
1175
1148
- // expected lenth of the chunk
1149
- let expected = match color_type {
1150
- ColorType :: Grayscale => 1 ,
1151
- ColorType :: Rgb | ColorType :: Indexed => 3 ,
1152
- ColorType :: GrayscaleAlpha => 2 ,
1153
- ColorType :: Rgba => 4 ,
1154
- } ;
1176
+ // expected lenth of the chunk
1177
+ let expected = match color_type {
1178
+ ColorType :: Grayscale => 1 ,
1179
+ ColorType :: Rgb | ColorType :: Indexed => 3 ,
1180
+ ColorType :: GrayscaleAlpha => 2 ,
1181
+ ColorType :: Rgba => 4 ,
1182
+ } ;
1183
+
1184
+ // Check if the sbit chunk size is valid.
1185
+ if expected != len {
1186
+ return Err ( DecodingError :: Format (
1187
+ FormatErrorInner :: InvalidSbitChunkSize {
1188
+ color_type,
1189
+ expected,
1190
+ len,
1191
+ }
1192
+ . into ( ) ,
1193
+ ) ) ;
1194
+ }
1155
1195
1156
- // Check if the sbit chunk size is valid.
1157
- if expected != len {
1196
+ for sbit in & vec {
1197
+ if * sbit < 1 || * sbit > sample_depth as u8 {
1158
1198
return Err ( DecodingError :: Format (
1159
- FormatErrorInner :: InvalidSbitChunkSize {
1160
- color_type,
1161
- expected,
1162
- len,
1199
+ FormatErrorInner :: InvalidSbit {
1200
+ sample_depth,
1201
+ sbit : * sbit,
1163
1202
}
1164
1203
. into ( ) ,
1165
1204
) ) ;
1166
1205
}
1167
-
1168
- for sbit in & vec {
1169
- if * sbit < 1 || * sbit > sample_depth as u8 {
1170
- return Err ( DecodingError :: Format (
1171
- FormatErrorInner :: InvalidSbit {
1172
- sample_depth,
1173
- sbit : * sbit,
1174
- }
1175
- . into ( ) ,
1176
- ) ) ;
1177
- }
1178
- }
1179
- info. sbit = Some ( Cow :: Owned ( vec) ) ;
1180
- Ok ( Decoded :: Nothing )
1181
- } ;
1182
-
1183
- parse ( ) . ok ( ) ;
1206
+ }
1207
+ info. sbit = Some ( Cow :: Owned ( vec) ) ;
1184
1208
Ok ( Decoded :: Nothing )
1185
1209
}
1186
1210
@@ -2963,4 +2987,28 @@ mod tests {
2963
2987
& err,
2964
2988
) ;
2965
2989
}
2990
+
2991
+ #[ test]
2992
+ fn test_incorrect_trns_chunk_is_ignored ( ) {
2993
+ let png = {
2994
+ let mut png = Vec :: new ( ) ;
2995
+ write_png_sig ( & mut png) ;
2996
+ write_rgba8_ihdr_with_width ( & mut png, 8 ) ;
2997
+ write_chunk ( & mut png, b"tRNS" , & [ 12 , 34 , 56 ] ) ;
2998
+ write_chunk (
2999
+ & mut png,
3000
+ b"IDAT" ,
3001
+ & generate_rgba8_with_width_and_height ( 8 , 8 ) ,
3002
+ ) ;
3003
+ write_iend ( & mut png) ;
3004
+ png
3005
+ } ;
3006
+ let decoder = Decoder :: new ( png. as_slice ( ) ) ;
3007
+ let mut reader = decoder. read_info ( ) . unwrap ( ) ;
3008
+ let mut buf = vec ! [ 0 ; reader. output_buffer_size( ) ] ;
3009
+ assert ! ( reader. info( ) . trns. is_none( ) ) ;
3010
+ reader. next_frame ( & mut buf) . unwrap ( ) ;
3011
+ assert_eq ! ( 3093270825 , crc32fast:: hash( & buf) ) ;
3012
+ assert ! ( reader. info( ) . trns. is_none( ) ) ;
3013
+ }
2966
3014
}
0 commit comments