Make read_ifd and read_entry stateless

This commit is contained in:
Jonathan Behrens committed 2022-01-12 19:56:08 -05:00
1 parent 47080293db
commit 720e6586b9
1 file changed
+62 -36
+62 -36
View File
@@ -595,15 +595,27 @@ impl<R: Read + Seek> Decoder<R> {
/// If there is no further image in the TIFF file a format error is returned. /// If there is no further image in the TIFF file a format error is returned.
/// To determine whether there are more images call `TIFFDecoder::more_images` instead. /// To determine whether there are more images call `TIFFDecoder::more_images` instead.
pub fn next_image(&mut self) -> TiffResult<()> { pub fn next_image(&mut self) -> TiffResult<()> {
let ifd = self.read_ifd()?; if self.next_ifd.is_none() {
return Err(TiffError::FormatError(
TiffFormatError::ImageFileDirectoryNotFound,
));
}
let (ifd, next_ifd) = Self::read_ifd(
&mut self.reader,
self.bigtiff,
self.next_ifd.take().unwrap(),
)?;
if let Some(next) = next_ifd {
if !self.seen_ifds.insert(next) {
return Err(TiffError::FormatError(TiffFormatError::CycleInOffsets));
}
self.next_ifd = Some(next);
}
self.current_chunk = 0; self.current_chunk = 0;
self.image = Image::from_reader( self.image = Image::from_reader(&mut self.reader, ifd, &self.limits, self.bigtiff)?;
&mut self.reader,
ifd,
&self.limits,
self.bigtiff
)?;
Ok(()) Ok(())
} }
@@ -731,43 +743,53 @@ impl<R: Read + Seek> Decoder<R> {
// Type 2 bytes // Type 2 bytes
// Count 4 bytes // Count 4 bytes
// Value 4 bytes either a pointer the value itself // Value 4 bytes either a pointer the value itself
fn read_entry(&mut self) -> TiffResult<Option<(Tag, ifd::Entry)>> { fn read_entry(
let tag = Tag::from_u16_exhaustive(self.read_short()?); reader: &mut SmartReader<R>,
let type_ = match Type::from_u16(self.read_short()?) { bigtiff: bool,
) -> TiffResult<Option<(Tag, ifd::Entry)>> {
let tag = Tag::from_u16_exhaustive(reader.read_u16()?);
let type_ = match Type::from_u16(reader.read_u16()?) {
Some(t) => t, Some(t) => t,
None => { None => {
// Unknown type. Skip this entry according to spec. // Unknown type. Skip this entry according to spec.
self.read_long()?; reader.read_u32()?;
self.read_long()?; reader.read_u32()?;
return Ok(None); return Ok(None);
} }
}; };
let entry = if self.bigtiff { let entry = if bigtiff {
ifd::Entry::new_u64(type_, self.read_long8()?, self.read_offset_u64()?) let mut offset = [0; 8];
let count = reader.read_u64()?;
reader.read_exact(&mut offset)?;
ifd::Entry::new_u64(type_, count, offset)
} else { } else {
ifd::Entry::new(type_, self.read_long()?, self.read_offset()?) let mut offset = [0; 4];
let count = reader.read_u32()?;
reader.read_exact(&mut offset)?;
ifd::Entry::new(type_, count, offset)
}; };
Ok(Some((tag, entry))) Ok(Some((tag, entry)))
} }
/// Reads the next IFD /// Reads the IFD starting at the indicated location.
fn read_ifd(&mut self) -> TiffResult<Directory> { fn read_ifd(
reader: &mut SmartReader<R>,
bigtiff: bool,
ifd_location: u64,
) -> TiffResult<(Directory, Option<u64>)> {
reader.goto_offset(ifd_location)?;
let mut dir: Directory = HashMap::new(); let mut dir: Directory = HashMap::new();
match self.next_ifd {
None => { let num_tags = if bigtiff {
return Err(TiffError::FormatError( reader.read_u64()?
TiffFormatError::ImageFileDirectoryNotFound,
))
}
Some(offset) => self.goto_offset_u64(offset)?,
}
let num_tags = if self.bigtiff {
self.read_long8()?
} else { } else {
self.read_short()?.into() reader.read_u16()?.into()
}; };
for _ in 0..num_tags { for _ in 0..num_tags {
let (tag, entry) = match self.read_entry()? { let (tag, entry) = match Self::read_entry(reader, bigtiff)? {
Some(val) => val, Some(val) => val,
None => { None => {
continue; continue;
@@ -776,14 +798,18 @@ impl<R: Read + Seek> Decoder<R> {
dir.insert(tag, entry); dir.insert(tag, entry);
} }
self.next_ifd = { let next_ifd = if bigtiff {
let result = self.read_ifd_offset()?; reader.read_u64()?
if !self.seen_ifds.insert(result) { } else {
return Err(TiffError::FormatError(TiffFormatError::CycleInOffsets)); reader.read_u32()?.into()
}
Some(result)
}; };
Ok(dir)
let next_ifd = match next_ifd {
0 => None,
1.. => Some(next_ifd),
};
Ok((dir, next_ifd))
} }
/// Tries to retrieve a tag. /// Tries to retrieve a tag.