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[..] {
|
PhotometricInterpretation::RGB => match self.bits_per_sample[..] {
|
||||||
[r, g, b] if [r, r] == [g, b] => Ok(ColorType::RGB(r)),
|
[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)),
|
[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(
|
_ => Err(TiffError::UnsupportedError(
|
||||||
TiffUnsupportedError::InterpretationWithBits(
|
TiffUnsupportedError::InterpretationWithBits(
|
||||||
self.photometric_interpretation,
|
self.photometric_interpretation,
|
||||||
@@ -766,7 +771,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
buffer: DecodingBuffer<'a>,
|
buffer: DecodingBuffer<'a>,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
length: u64,
|
length: u64,
|
||||||
max_uncompressed_length: usize,
|
strip_sample_count: usize,
|
||||||
) -> TiffResult<usize> {
|
) -> TiffResult<usize> {
|
||||||
let color_type = self.colortype()?;
|
let color_type = self.colortype()?;
|
||||||
self.goto_offset_u64(offset)?;
|
self.goto_offset_u64(offset)?;
|
||||||
@@ -782,7 +787,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let (bytes, reader) = LZWReader::new(
|
let (bytes, reader) = LZWReader::new(
|
||||||
&mut self.reader,
|
&mut self.reader,
|
||||||
usize::try_from(length)?,
|
usize::try_from(length)?,
|
||||||
max_uncompressed_length * buffer.byte_len(),
|
strip_sample_count * buffer.byte_len(),
|
||||||
)?;
|
)?;
|
||||||
(bytes, Box::new(reader))
|
(bytes, Box::new(reader))
|
||||||
}
|
}
|
||||||
@@ -793,8 +798,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
(bytes, Box::new(reader))
|
(bytes, Box::new(reader))
|
||||||
}
|
}
|
||||||
CompressionMethod::OldDeflate => {
|
CompressionMethod::OldDeflate => {
|
||||||
let (bytes, reader) =
|
let (bytes, reader) = DeflateReader::new(&mut self.reader, strip_sample_count)?;
|
||||||
DeflateReader::new(&mut self.reader, max_uncompressed_length)?;
|
|
||||||
(bytes, Box::new(reader))
|
(bytes, Box::new(reader))
|
||||||
}
|
}
|
||||||
method => {
|
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(
|
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 {
|
if units_read < buffer_size {
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
TiffFormatError::InconsistentSizesEncountered,
|
TiffFormatError::InconsistentStripElements {
|
||||||
|
actual: units_read,
|
||||||
|
required: buffer_size,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if let Ok(predictor) = self.get_tag_unsigned(Tag::Predictor) {
|
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 uncompressed = Vec::with_capacity(max_uncompressed_length);
|
||||||
let mut decoder = weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
|
let mut decoder = weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
|
||||||
let mut bytes_read = 0;
|
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();
|
let bytes_written = uncompressed.len();
|
||||||
uncompressed.reserve(1 << 12);
|
uncompressed.reserve(1 << 12);
|
||||||
let buffer_space = uncompressed.capacity();
|
let buffer_space = uncompressed.capacity().min(max_uncompressed_length);
|
||||||
uncompressed.resize(buffer_space, 0u8);
|
uncompressed.resize(buffer_space, 0u8);
|
||||||
|
|
||||||
let result = decoder.decode_bytes(
|
let result = decoder.decode_bytes(
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ pub enum TiffFormatError {
|
|||||||
TiffSignatureInvalid,
|
TiffSignatureInvalid,
|
||||||
ImageFileDirectoryNotFound,
|
ImageFileDirectoryNotFound,
|
||||||
InconsistentSizesEncountered,
|
InconsistentSizesEncountered,
|
||||||
|
UnexpectedCompressedData {
|
||||||
|
actual: usize,
|
||||||
|
required: usize,
|
||||||
|
},
|
||||||
|
InconsistentStripElements {
|
||||||
|
actual: usize,
|
||||||
|
required: usize,
|
||||||
|
},
|
||||||
InvalidTag,
|
InvalidTag,
|
||||||
InvalidTagValueType(Tag),
|
InvalidTagValueType(Tag),
|
||||||
RequiredTagNotFound(Tag),
|
RequiredTagNotFound(Tag),
|
||||||
@@ -66,6 +74,20 @@ impl fmt::Display for TiffFormatError {
|
|||||||
TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."),
|
TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."),
|
||||||
ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."),
|
ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."),
|
||||||
InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."),
|
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."),
|
InvalidTag => write!(fmt, "Image contains invalid tag."),
|
||||||
InvalidTagValueType(ref tag) => {
|
InvalidTagValueType(ref tag) => {
|
||||||
write!(fmt, "Tag `{:?}` did not have the expected value type.", tag)
|
write!(fmt, "Tag `{:?}` did not have the expected value type.", tag)
|
||||||
|
|||||||
Reference in new issue
Block a user