Make read_ifd and read_entry stateless
This commit is contained in:
1 parent
47080293db
commit
720e6586b9
1 file changed
+62
-36
+62
-36
@@ -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.
|
||||||
|
|||||||
Reference in new issue
Block a user