Add Decoder::restart_ifd
This serves two purposes: reliably resetting the state of the decoder after kinds of failure; and moving the decoder to a SubIFD chain.
This commit is contained in:
1 parent
36a16db659
commit
c073841a9d
2 files changed
+48
-1
No files matched your search
@@ -693,6 +693,27 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start the chain of IFDs from a new location.
|
||||||
|
///
|
||||||
|
/// This enters a new chain of image file descriptors with the indicated IFD as the new root
|
||||||
|
/// (similar to the file having its initial offset at the given IFD). After this call,
|
||||||
|
/// [`Self::seek_to_image`] works relative to the new root.
|
||||||
|
///
|
||||||
|
/// Note that this is not atomic. If the function returns an error, the decoder is left in an
|
||||||
|
/// intermediate state where it does not point to any image. A valid state can be recovered by
|
||||||
|
/// calling [`Self::restart_ifds`] with a valid offset and a successful seek. Explicit reads
|
||||||
|
/// will still work.
|
||||||
|
pub fn restart_ifds(&mut self, offset: IfdPointer) -> TiffResult<()> {
|
||||||
|
self.ifd_offsets.clear();
|
||||||
|
self.ifd_offsets.push(offset);
|
||||||
|
|
||||||
|
self.next_ifd = Some(offset);
|
||||||
|
self.current_ifd = None;
|
||||||
|
|
||||||
|
self.next_ifd()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn next_ifd(&mut self) -> TiffResult<Directory> {
|
fn next_ifd(&mut self) -> TiffResult<Directory> {
|
||||||
let Some(next_ifd) = self.next_ifd.take() else {
|
let Some(next_ifd) = self.next_ifd.take() else {
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
|
|||||||
+27
-1
@@ -1,4 +1,4 @@
|
|||||||
use tiff::decoder::Decoder;
|
use tiff::{decoder::Decoder, tags::IfdPointer};
|
||||||
|
|
||||||
// This file has the following IFD structure:
|
// This file has the following IFD structure:
|
||||||
//
|
//
|
||||||
@@ -39,3 +39,29 @@ fn decode_seek_chain() {
|
|||||||
assert_eq!(Some(offset2), decoder.ifd_pointer());
|
assert_eq!(Some(offset2), decoder.ifd_pointer());
|
||||||
assert!(!decoder.more_images());
|
assert!(!decoder.more_images());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_seek_recover() {
|
||||||
|
let file = File::open(TEST_IMAGE_SUBIFD).expect("Cannot open test image");
|
||||||
|
let mut decoder = Decoder::new(file).expect("Invalid format to create decoder");
|
||||||
|
|
||||||
|
// Remember the offsets in the first iteration.
|
||||||
|
let offset0 = decoder.ifd_pointer().expect("First IFD pointer not found");
|
||||||
|
decoder.next_image().unwrap();
|
||||||
|
let offset1 = decoder.ifd_pointer().expect("Second IFD pointer not found");
|
||||||
|
decoder.next_image().unwrap();
|
||||||
|
let offset2 = decoder.ifd_pointer().expect("Third IFD pointer not found");
|
||||||
|
|
||||||
|
// oops!
|
||||||
|
let fails = decoder.restart_ifds(IfdPointer(0xdead_beef));
|
||||||
|
assert!(fails.is_err());
|
||||||
|
|
||||||
|
// However we can recover by restarting our seek.
|
||||||
|
decoder.restart_ifds(offset0)
|
||||||
|
.expect("Failed to restart IFDs from first image");
|
||||||
|
assert_eq!(Some(offset0), decoder.ifd_pointer());
|
||||||
|
decoder.next_image().unwrap();
|
||||||
|
assert_eq!(Some(offset1), decoder.ifd_pointer());
|
||||||
|
decoder.next_image().unwrap();
|
||||||
|
assert_eq!(Some(offset2), decoder.ifd_pointer());
|
||||||
|
}
|
||||||
Reference in new issue
Block a user