diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index ec12c04..15374ac 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -354,6 +354,11 @@ impl Decoder { PhotometricInterpretation::RGB => match self.bits_per_sample[..] { [r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)), [r, g, b, a] if [r, r, r] == [g, b, a] => Ok(ColorType::RGBA(r)), + // FIXME: We should _ignore_ other components. In particular: + // > Beware of extra components. Some TIFF files may have more components per pixel + // than you think. A Baseline TIFF reader must skip over them gracefully,using the + // values of the SamplesPerPixel and BitsPerSample fields. + // > -- TIFF 6.0 Specification, Section 7, Additional Baseline requirements. _ => Err(TiffError::UnsupportedError( TiffUnsupportedError::InterpretationWithBits( self.photometric_interpretation, @@ -766,7 +771,7 @@ impl Decoder { buffer: DecodingBuffer<'a>, offset: u64, length: u64, - max_uncompressed_length: usize, + strip_sample_count: usize, ) -> TiffResult { let color_type = self.colortype()?; self.goto_offset_u64(offset)?; @@ -782,7 +787,7 @@ impl Decoder { let (bytes, reader) = LZWReader::new( &mut self.reader, usize::try_from(length)?, - max_uncompressed_length * buffer.byte_len(), + strip_sample_count * buffer.byte_len(), )?; (bytes, Box::new(reader)) } @@ -793,8 +798,7 @@ impl Decoder { (bytes, Box::new(reader)) } CompressionMethod::OldDeflate => { - let (bytes, reader) = - DeflateReader::new(&mut self.reader, max_uncompressed_length)?; + let (bytes, reader) = DeflateReader::new(&mut self.reader, strip_sample_count)?; (bytes, Box::new(reader)) } method => { @@ -804,9 +808,14 @@ impl Decoder { } }; - if bytes / buffer.byte_len() > max_uncompressed_length { + // FIXME: this might be suboptimal. We might default remaining bits to ยด0`, which some + // other decoders might do. + if bytes / buffer.byte_len() > strip_sample_count { return Err(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, + TiffFormatError::UnexpectedCompressedData { + actual: bytes, + required: strip_sample_count * buffer.byte_len(), + }, )); } @@ -1039,7 +1048,10 @@ impl Decoder { if units_read < buffer_size { return Err(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, + TiffFormatError::InconsistentStripElements { + actual: units_read, + required: buffer_size, + }, )); } if let Ok(predictor) = self.get_tag_unsigned(Tag::Predictor) { diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 327e6de..9b89046 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -267,10 +267,11 @@ impl LZWReader { let mut uncompressed = Vec::with_capacity(max_uncompressed_length); let mut decoder = weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8); let mut bytes_read = 0; - while bytes_read < compressed_length && uncompressed.len() < max_uncompressed_length { + + while uncompressed.len() < max_uncompressed_length { let bytes_written = uncompressed.len(); uncompressed.reserve(1 << 12); - let buffer_space = uncompressed.capacity(); + let buffer_space = uncompressed.capacity().min(max_uncompressed_length); uncompressed.resize(buffer_space, 0u8); let result = decoder.decode_bytes( diff --git a/src/error.rs b/src/error.rs index f1af2fd..60be47f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,6 +43,14 @@ pub enum TiffFormatError { TiffSignatureInvalid, ImageFileDirectoryNotFound, InconsistentSizesEncountered, + UnexpectedCompressedData { + actual: usize, + required: usize, + }, + InconsistentStripElements { + actual: usize, + required: usize, + }, InvalidTag, InvalidTagValueType(Tag), RequiredTagNotFound(Tag), @@ -66,6 +74,20 @@ impl fmt::Display for TiffFormatError { TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."), ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."), InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."), + UnexpectedCompressedData { actual, required } => { + write!( + fmt, + "Decompression returned different amount of bytes than expected: got {}, expected {}.", + actual, required + ) + } + InconsistentStripElements { actual, required } => { + write!( + fmt, + "Inconsistent elements in strip: got {}, expected {}.", + actual, required + ) + } InvalidTag => write!(fmt, "Image contains invalid tag."), InvalidTagValueType(ref tag) => { write!(fmt, "Tag `{:?}` did not have the expected value type.", tag)