1 extern crate crc32fast;
2
3 use std::borrow::Cow;
4 use std::cmp::min;
5 use std::convert::From;
6 use std::default::Default;
7 use std::error;
8 use std::fmt;
9 use std::io;
10
11 use crc32fast::Hasher as Crc32;
12
13 use super::zlib::ZlibStream;
14 use crate::chunk::{self, ChunkType, IDAT, IEND, IHDR};
15 use crate::common::{
16 AnimationControl, BitDepth, BlendOp, ColorType, DisposeOp, FrameControl, Info, PixelDimensions,
17 Unit,
18 };
19 use crate::traits::ReadBytesExt;
20
21 /// TODO check if these size are reasonable
22 pub const CHUNCK_BUFFER_SIZE: usize = 32 * 1024;
23
24 /// Determines if checksum checks should be disabled globally.
25 ///
26 /// This is used only in fuzzing. `afl` automatically adds `--cfg fuzzing` to RUSTFLAGS which can
27 /// be used to detect that build.
28 const CHECKSUM_DISABLED: bool = cfg!(fuzzing);
29
30 #[derive(Debug)]
31 enum U32Value {
32 // CHUNKS
33 Length,
34 Type(u32),
35 Crc(ChunkType),
36 }
37
38 #[derive(Debug)]
39 enum State {
40 Signature(u8, [u8; 7]),
41 U32Byte3(U32Value, u32),
42 U32Byte2(U32Value, u32),
43 U32Byte1(U32Value, u32),
44 U32(U32Value),
45 ReadChunk(ChunkType, bool),
46 PartialChunk(ChunkType),
47 DecodeData(ChunkType, usize),
48 }
49
50 #[derive(Debug)]
51 /// Result of the decoding process
52 pub enum Decoded {
53 /// Nothing decoded yet
54 Nothing,
55 Header(u32, u32, BitDepth, ColorType, bool),
56 ChunkBegin(u32, ChunkType),
57 ChunkComplete(u32, ChunkType),
58 PixelDimensions(PixelDimensions),
59 AnimationControl(AnimationControl),
60 FrameControl(FrameControl),
61 /// Decoded raw image data.
62 ImageData,
63 /// The last of a consecutive chunk of IDAT was done.
64 /// This is distinct from ChunkComplete which only marks that some IDAT chunk was completed but
65 /// not that no additional IDAT chunk follows.
66 ImageDataFlushed,
67 PartialChunk(ChunkType),
68 ImageEnd,
69 }
70
71 #[derive(Debug)]
72 pub enum DecodingError {
73 IoError(io::Error),
74 Format(Cow<'static, str>),
75 InvalidSignature,
76 CrcMismatch {
77 /// bytes to skip to try to recover from this error
78 recover: usize,
79 /// Stored CRC32 value
80 crc_val: u32,
81 /// Calculated CRC32 sum
82 crc_sum: u32,
83 chunk: ChunkType,
84 },
85 Other(Cow<'static, str>),
86 CorruptFlateStream,
87 LimitsExceeded,
88 }
89
90 impl error::Error for DecodingError {
cause(&self) -> Option<&(dyn error::Error + 'static)>91 fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
92 match self {
93 DecodingError::IoError(err) => Some(err),
94 _ => None,
95 }
96 }
97 }
98
99 impl fmt::Display for DecodingError {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>100 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
101 use self::DecodingError::*;
102 match self {
103 IoError(err) => write!(fmt, "{}", err),
104 Format(desc) | Other(desc) => write!(fmt, "{}", &desc),
105 InvalidSignature => write!(fmt, "invalid signature"),
106 CrcMismatch { .. } => write!(fmt, "CRC error"),
107 CorruptFlateStream => write!(fmt, "compressed data stream corrupted"),
108 LimitsExceeded => write!(fmt, "limits are exceeded"),
109 }
110 }
111 }
112
113 impl From<io::Error> for DecodingError {
from(err: io::Error) -> DecodingError114 fn from(err: io::Error) -> DecodingError {
115 DecodingError::IoError(err)
116 }
117 }
118
119 impl From<String> for DecodingError {
from(err: String) -> DecodingError120 fn from(err: String) -> DecodingError {
121 DecodingError::Other(err.into())
122 }
123 }
124
125 impl From<DecodingError> for io::Error {
from(err: DecodingError) -> io::Error126 fn from(err: DecodingError) -> io::Error {
127 match err {
128 DecodingError::IoError(err) => err,
129 err => io::Error::new(io::ErrorKind::Other, err.to_string()),
130 }
131 }
132 }
133
134 /// PNG StreamingDecoder (low-level interface)
135 pub struct StreamingDecoder {
136 state: Option<State>,
137 current_chunk: ChunkState,
138 /// The inflater state handling consecutive `IDAT` and `fdAT` chunks.
139 inflater: ZlibStream,
140 /// The complete image info read from all prior chunks.
141 info: Option<Info>,
142 /// The animation chunk sequence number.
143 current_seq_no: Option<u32>,
144 /// Stores where in decoding an `fdAT` chunk we are.
145 apng_seq_handled: bool,
146 have_idat: bool,
147 }
148
149 struct ChunkState {
150 /// The type of the current chunk.
151 /// Relevant for `IDAT` and `fdAT` which aggregate consecutive chunks of their own type.
152 type_: ChunkType,
153
154 /// Partial crc until now.
155 crc: Crc32,
156
157 /// Remanining bytes to be read.
158 remaining: u32,
159
160 /// Non-decoded bytes in the chunk.
161 raw_bytes: Vec<u8>,
162 }
163
164 impl StreamingDecoder {
165 /// Creates a new StreamingDecoder
166 ///
167 /// Allocates the internal buffers.
new() -> StreamingDecoder168 pub fn new() -> StreamingDecoder {
169 StreamingDecoder {
170 state: Some(State::Signature(0, [0; 7])),
171 current_chunk: ChunkState::default(),
172 inflater: ZlibStream::new(),
173 info: None,
174 current_seq_no: None,
175 apng_seq_handled: false,
176 have_idat: false,
177 }
178 }
179
180 /// Resets the StreamingDecoder
reset(&mut self)181 pub fn reset(&mut self) {
182 self.state = Some(State::Signature(0, [0; 7]));
183 self.current_chunk.crc = Crc32::new();
184 self.current_chunk.remaining = 0;
185 self.current_chunk.raw_bytes.clear();
186 self.inflater = ZlibStream::new();
187 self.info = None;
188 self.current_seq_no = None;
189 self.apng_seq_handled = false;
190 self.have_idat = false;
191 }
192
193 /// Low level StreamingDecoder interface.
194 ///
195 /// Allows to stream partial data to the encoder. Returns a tuple containing the bytes that have
196 /// been consumed from the input buffer and the current decoding result. If the decoded chunk
197 /// was an image data chunk, it also appends the read data to `image_data`.
update( &mut self, mut buf: &[u8], image_data: &mut Vec<u8>, ) -> Result<(usize, Decoded), DecodingError>198 pub fn update(
199 &mut self,
200 mut buf: &[u8],
201 image_data: &mut Vec<u8>,
202 ) -> Result<(usize, Decoded), DecodingError> {
203 let len = buf.len();
204 while !buf.is_empty() && self.state.is_some() {
205 match self.next_state(buf, image_data) {
206 Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..],
207 Ok((bytes, result)) => {
208 buf = &buf[bytes..];
209 return Ok((len - buf.len(), result));
210 }
211 Err(err) => return Err(err),
212 }
213 }
214 Ok((len - buf.len(), Decoded::Nothing))
215 }
216
next_state<'a>( &'a mut self, buf: &[u8], image_data: &mut Vec<u8>, ) -> Result<(usize, Decoded), DecodingError>217 fn next_state<'a>(
218 &'a mut self,
219 buf: &[u8],
220 image_data: &mut Vec<u8>,
221 ) -> Result<(usize, Decoded), DecodingError> {
222 use self::State::*;
223
224 macro_rules! goto (
225 ($n:expr, $state:expr) => ({
226 self.state = Some($state);
227 Ok(($n, Decoded::Nothing))
228 });
229 ($state:expr) => ({
230 self.state = Some($state);
231 Ok((1, Decoded::Nothing))
232 });
233 ($n:expr, $state:expr, emit $res:expr) => ({
234 self.state = Some($state);
235 Ok(($n, $res))
236 });
237 ($state:expr, emit $res:expr) => ({
238 self.state = Some($state);
239 Ok((1, $res))
240 })
241 );
242
243 let current_byte = buf[0];
244
245 // Driver should ensure that state is never None
246 let state = self.state.take().unwrap();
247
248 match state {
249 Signature(i, mut signature) if i < 7 => {
250 signature[i as usize] = current_byte;
251 goto!(Signature(i + 1, signature))
252 }
253 Signature(_, signature)
254 if signature == [137, 80, 78, 71, 13, 10, 26] && current_byte == 10 =>
255 {
256 goto!(U32(U32Value::Length))
257 }
258 Signature(..) => Err(DecodingError::InvalidSignature),
259 U32Byte3(type_, mut val) => {
260 use self::U32Value::*;
261 val |= u32::from(current_byte);
262 match type_ {
263 Length => goto!(U32(Type(val))),
264 Type(length) => {
265 let type_str = [
266 (val >> 24) as u8,
267 (val >> 16) as u8,
268 (val >> 8) as u8,
269 val as u8,
270 ];
271 if type_str != self.current_chunk.type_
272 && (self.current_chunk.type_ == IDAT
273 || self.current_chunk.type_ == chunk::fdAT)
274 {
275 self.current_chunk.type_ = type_str;
276 self.inflater.finish_compressed_chunks(image_data)?;
277 self.inflater.reset();
278 return goto!(
279 0,
280 U32Byte3(Type(length), val & !0xff),
281 emit Decoded::ImageDataFlushed
282 );
283 }
284 self.current_chunk.type_ = type_str;
285 self.current_chunk.crc.reset();
286 self.current_chunk.crc.update(&type_str);
287 self.current_chunk.remaining = length;
288 self.apng_seq_handled = false;
289 goto!(
290 ReadChunk(type_str, true),
291 emit Decoded::ChunkBegin(length, type_str)
292 )
293 }
294 Crc(type_str) => {
295 let sum = self.current_chunk.crc.clone().finalize();
296 if CHECKSUM_DISABLED || val == sum {
297 goto!(
298 State::U32(U32Value::Length),
299 emit if type_str == IEND {
300 Decoded::ImageEnd
301 } else {
302 Decoded::ChunkComplete(val, type_str)
303 }
304 )
305 } else {
306 Err(DecodingError::CrcMismatch {
307 recover: 1,
308 crc_val: val,
309 crc_sum: sum,
310 chunk: type_str,
311 })
312 }
313 }
314 }
315 }
316 U32Byte2(type_, val) => goto!(U32Byte3(type_, val | u32::from(current_byte) << 8)),
317 U32Byte1(type_, val) => goto!(U32Byte2(type_, val | u32::from(current_byte) << 16)),
318 U32(type_) => goto!(U32Byte1(type_, u32::from(current_byte) << 24)),
319 PartialChunk(type_str) => {
320 match type_str {
321 IDAT => {
322 self.have_idat = true;
323 goto!(
324 0,
325 DecodeData(type_str, 0),
326 emit Decoded::PartialChunk(type_str)
327 )
328 }
329 chunk::fdAT => {
330 let data_start;
331 if let Some(seq_no) = self.current_seq_no {
332 if !self.apng_seq_handled {
333 data_start = 4;
334 let mut buf = &self.current_chunk.raw_bytes[..];
335 let next_seq_no = buf.read_be()?;
336 if next_seq_no != seq_no + 1 {
337 return Err(DecodingError::Format(
338 format!(
339 "Sequence is not in order, expected #{} got #{}.",
340 seq_no + 1,
341 next_seq_no
342 )
343 .into(),
344 ));
345 }
346 self.current_seq_no = Some(next_seq_no);
347 self.apng_seq_handled = true;
348 } else {
349 data_start = 0;
350 }
351 } else {
352 return Err(DecodingError::Format(
353 "fcTL chunk missing before fdAT chunk.".into(),
354 ));
355 }
356 goto!(
357 0,
358 DecodeData(type_str, data_start),
359 emit Decoded::PartialChunk(type_str)
360 )
361 }
362 // Handle other chunks
363 _ => {
364 if self.current_chunk.remaining == 0 {
365 // complete chunk
366 Ok((0, self.parse_chunk(type_str)?))
367 } else {
368 goto!(
369 0, ReadChunk(type_str, true),
370 emit Decoded::PartialChunk(type_str)
371 )
372 }
373 }
374 }
375 }
376 ReadChunk(type_str, clear) => {
377 if clear {
378 self.current_chunk.raw_bytes.clear();
379 }
380 if self.current_chunk.remaining > 0 {
381 let ChunkState {
382 crc,
383 remaining,
384 raw_bytes,
385 type_: _,
386 } = &mut self.current_chunk;
387 let buf_avail = raw_bytes.capacity() - raw_bytes.len();
388 let bytes_avail = min(buf.len(), buf_avail);
389 let n = min(*remaining, bytes_avail as u32);
390 if buf_avail == 0 {
391 goto!(0, PartialChunk(type_str))
392 } else {
393 let buf = &buf[..n as usize];
394 crc.update(buf);
395 raw_bytes.extend_from_slice(buf);
396 *remaining -= n;
397 if *remaining == 0 {
398 goto!(n as usize, PartialChunk(type_str))
399 } else {
400 goto!(n as usize, ReadChunk(type_str, false))
401 }
402 }
403 } else {
404 goto!(0, U32(U32Value::Crc(type_str)))
405 }
406 }
407 DecodeData(type_str, mut n) => {
408 let chunk_len = self.current_chunk.raw_bytes.len();
409 let chunk_data = &self.current_chunk.raw_bytes[n..];
410 let c = self.inflater.decompress(chunk_data, image_data)?;
411 n += c;
412 if n == chunk_len && c == 0 {
413 goto!(
414 0,
415 ReadChunk(type_str, true),
416 emit Decoded::ImageData
417 )
418 } else {
419 goto!(
420 0,
421 DecodeData(type_str, n),
422 emit Decoded::ImageData
423 )
424 }
425 }
426 }
427 }
428
parse_chunk(&mut self, type_str: [u8; 4]) -> Result<Decoded, DecodingError>429 fn parse_chunk(&mut self, type_str: [u8; 4]) -> Result<Decoded, DecodingError> {
430 self.state = Some(State::U32(U32Value::Crc(type_str)));
431 if self.info.is_none() && type_str != IHDR {
432 return Err(DecodingError::Format(
433 format!(
434 "{} chunk appeared before IHDR chunk",
435 String::from_utf8_lossy(&type_str)
436 )
437 .into(),
438 ));
439 }
440 match match type_str {
441 IHDR => self.parse_ihdr(),
442 chunk::PLTE => self.parse_plte(),
443 chunk::tRNS => self.parse_trns(),
444 chunk::pHYs => self.parse_phys(),
445 chunk::acTL => self.parse_actl(),
446 chunk::fcTL => self.parse_fctl(),
447 _ => Ok(Decoded::PartialChunk(type_str)),
448 } {
449 Err(err) => {
450 // Borrow of self ends here, because Decoding error does not borrow self.
451 self.state = None;
452 Err(err)
453 }
454 ok => ok,
455 }
456 }
457
get_info_or_err(&self) -> Result<&Info, DecodingError>458 fn get_info_or_err(&self) -> Result<&Info, DecodingError> {
459 self.info
460 .as_ref()
461 .ok_or_else(|| DecodingError::Format("IHDR chunk missing".into()))
462 }
463
parse_fctl(&mut self) -> Result<Decoded, DecodingError>464 fn parse_fctl(&mut self) -> Result<Decoded, DecodingError> {
465 let mut buf = &self.current_chunk.raw_bytes[..];
466 let next_seq_no = buf.read_be()?;
467
468 // Asuming that fcTL is required before *every* fdAT-sequence
469 self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no {
470 if next_seq_no != seq_no + 1 {
471 return Err(DecodingError::Format(
472 format!(
473 "Sequence is not in order, expected #{} got #{}.",
474 seq_no + 1,
475 next_seq_no
476 )
477 .into(),
478 ));
479 }
480 next_seq_no
481 } else {
482 if next_seq_no != 0 {
483 return Err(DecodingError::Format(
484 format!(
485 "Sequence is not in order, expected #{} got #{}.",
486 0, next_seq_no
487 )
488 .into(),
489 ));
490 }
491 0
492 });
493 self.inflater = ZlibStream::new();
494 let fc = FrameControl {
495 sequence_number: next_seq_no,
496 width: buf.read_be()?,
497 height: buf.read_be()?,
498 x_offset: buf.read_be()?,
499 y_offset: buf.read_be()?,
500 delay_num: buf.read_be()?,
501 delay_den: buf.read_be()?,
502 dispose_op: match DisposeOp::from_u8(buf.read_be()?) {
503 Some(dispose_op) => dispose_op,
504 None => return Err(DecodingError::Format("invalid dispose operation".into())),
505 },
506 blend_op: match BlendOp::from_u8(buf.read_be()?) {
507 Some(blend_op) => blend_op,
508 None => return Err(DecodingError::Format("invalid blend operation".into())),
509 },
510 };
511 self.info.as_ref().unwrap().validate(&fc)?;
512 self.info.as_mut().unwrap().frame_control = Some(fc);
513 Ok(Decoded::FrameControl(fc))
514 }
515
parse_actl(&mut self) -> Result<Decoded, DecodingError>516 fn parse_actl(&mut self) -> Result<Decoded, DecodingError> {
517 if self.have_idat {
518 Err(DecodingError::Format(
519 "acTL chunk appeared after first IDAT chunk".into(),
520 ))
521 } else {
522 let mut buf = &self.current_chunk.raw_bytes[..];
523 let actl = AnimationControl {
524 num_frames: buf.read_be()?,
525 num_plays: buf.read_be()?,
526 };
527 self.info.as_mut().unwrap().animation_control = Some(actl);
528 Ok(Decoded::AnimationControl(actl))
529 }
530 }
531
parse_plte(&mut self) -> Result<Decoded, DecodingError>532 fn parse_plte(&mut self) -> Result<Decoded, DecodingError> {
533 if let Some(info) = self.info.as_mut() {
534 info.palette = Some(self.current_chunk.raw_bytes.clone())
535 }
536 Ok(Decoded::Nothing)
537 }
538
parse_trns(&mut self) -> Result<Decoded, DecodingError>539 fn parse_trns(&mut self) -> Result<Decoded, DecodingError> {
540 use crate::common::ColorType::*;
541 let (color_type, bit_depth) = {
542 let info = self.get_info_or_err()?;
543 (info.color_type, info.bit_depth as u8)
544 };
545 let vec = self.current_chunk.raw_bytes.clone();
546 let len = vec.len();
547 let info = match self.info {
548 Some(ref mut info) => info,
549 None => {
550 return Err(DecodingError::Format(
551 "tRNS chunk occured before IHDR chunk".into(),
552 ))
553 }
554 };
555 info.trns = Some(vec);
556 let vec = info.trns.as_mut().unwrap();
557 match color_type {
558 Grayscale => {
559 if len < 2 {
560 return Err(DecodingError::Format("not enough palette entries".into()));
561 }
562 if bit_depth < 16 {
563 vec[0] = vec[1];
564 vec.truncate(1);
565 }
566 Ok(Decoded::Nothing)
567 }
568 RGB => {
569 if len < 6 {
570 return Err(DecodingError::Format("not enough palette entries".into()));
571 }
572 if bit_depth < 16 {
573 vec[0] = vec[1];
574 vec[1] = vec[3];
575 vec[2] = vec[5];
576 vec.truncate(3);
577 }
578 Ok(Decoded::Nothing)
579 }
580 Indexed => {
581 let _ = info.palette.as_ref().ok_or_else(|| {
582 DecodingError::Format("tRNS chunk occured before PLTE chunk".into())
583 });
584 Ok(Decoded::Nothing)
585 }
586 c => Err(DecodingError::Format(
587 format!("tRNS chunk found for color type ({})", c as u8).into(),
588 )),
589 }
590 }
591
parse_phys(&mut self) -> Result<Decoded, DecodingError>592 fn parse_phys(&mut self) -> Result<Decoded, DecodingError> {
593 if self.have_idat {
594 Err(DecodingError::Format(
595 "pHYs chunk appeared after first IDAT chunk".into(),
596 ))
597 } else {
598 let mut buf = &self.current_chunk.raw_bytes[..];
599 let xppu = buf.read_be()?;
600 let yppu = buf.read_be()?;
601 let unit = buf.read_be()?;
602 let unit = match Unit::from_u8(unit) {
603 Some(unit) => unit,
604 None => {
605 return Err(DecodingError::Format(
606 format!("invalid unit ({})", unit).into(),
607 ))
608 }
609 };
610 let pixel_dims = PixelDimensions { xppu, yppu, unit };
611 self.info.as_mut().unwrap().pixel_dims = Some(pixel_dims);
612 Ok(Decoded::PixelDimensions(pixel_dims))
613 }
614 }
615
parse_ihdr(&mut self) -> Result<Decoded, DecodingError>616 fn parse_ihdr(&mut self) -> Result<Decoded, DecodingError> {
617 // TODO: check if color/bit depths combination is valid
618 let mut buf = &self.current_chunk.raw_bytes[..];
619 let width = buf.read_be()?;
620 let height = buf.read_be()?;
621 let bit_depth = buf.read_be()?;
622 let bit_depth = match BitDepth::from_u8(bit_depth) {
623 Some(bits) => bits,
624 None => {
625 return Err(DecodingError::Format(
626 format!("invalid bit depth ({})", bit_depth).into(),
627 ))
628 }
629 };
630 let color_type = buf.read_be()?;
631 let color_type = match ColorType::from_u8(color_type) {
632 Some(color_type) => color_type,
633 None => {
634 return Err(DecodingError::Format(
635 format!("invalid color type ({})", color_type).into(),
636 ))
637 }
638 };
639 match buf.read_be()? {
640 // compression method
641 0u8 => (),
642 n => {
643 return Err(DecodingError::Format(
644 format!("unknown compression method ({})", n).into(),
645 ))
646 }
647 }
648 match buf.read_be()? {
649 // filter method
650 0u8 => (),
651 n => {
652 return Err(DecodingError::Format(
653 format!("unknown filter method ({})", n).into(),
654 ))
655 }
656 }
657 let interlaced = match buf.read_be()? {
658 0u8 => false,
659 1 => true,
660 n => {
661 return Err(DecodingError::Format(
662 format!("unknown interlace method ({})", n).into(),
663 ))
664 }
665 };
666 let mut info = Info::default();
667
668 info.width = width;
669 info.height = height;
670 info.bit_depth = bit_depth;
671 info.color_type = color_type;
672 info.interlaced = interlaced;
673 self.info = Some(info);
674 Ok(Decoded::Header(
675 width, height, bit_depth, color_type, interlaced,
676 ))
677 }
678 }
679
680 impl Info {
validate(&self, fc: &FrameControl) -> Result<(), DecodingError>681 fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> {
682 // Validate mathematically: fc.width + fc.x_offset <= self.width
683 let in_x_bounds = Some(fc.width) <= self.width.checked_sub(fc.x_offset);
684 // Validate mathematically: fc.height + fc.y_offset <= self.height
685 let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset);
686
687 if !in_x_bounds || !in_y_bounds {
688 return Err(DecodingError::Format("Sub frame is out-of-bounds".into()));
689 }
690
691 Ok(())
692 }
693 }
694
695 impl Default for StreamingDecoder {
default() -> Self696 fn default() -> Self {
697 Self::new()
698 }
699 }
700
701 impl Default for ChunkState {
default() -> Self702 fn default() -> Self {
703 ChunkState {
704 type_: [0; 4],
705 crc: Crc32::new(),
706 remaining: 0,
707 raw_bytes: Vec::with_capacity(CHUNCK_BUFFER_SIZE),
708 }
709 }
710 }
711
712 #[inline(always)]
get_info(d: &StreamingDecoder) -> Option<&Info>713 pub fn get_info(d: &StreamingDecoder) -> Option<&Info> {
714 d.info.as_ref()
715 }
716