Fix lzw decoding stopping short of full decode
When the required amount of data was just a tiny bit larger than full a page size (one buffer increment), the decoder would stop since all compressed data had been read. However, the lzw decoder contains a small internal bit buffer for code decoding. That is, some remaining bytes had been retained and were still left to be decoded.
This commit is contained in:
1 parent
8ab9d30eff
commit
4d8c64bf1e
3 files changed
+44
-9
No files matched your search
+19
-7
@@ -354,6 +354,11 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
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<R: Read + Seek> Decoder<R> {
|
||||
buffer: DecodingBuffer<'a>,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
max_uncompressed_length: usize,
|
||||
strip_sample_count: usize,
|
||||
) -> TiffResult<usize> {
|
||||
let color_type = self.colortype()?;
|
||||
self.goto_offset_u64(offset)?;
|
||||
@@ -782,7 +787,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
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<R: Read + Seek> Decoder<R> {
|
||||
(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<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
};
|
||||
|
||||
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<R: Read + Seek> Decoder<R> {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user