Read tag values into byte slice
This commit is contained in:
1 parent
34bd1da99e
commit
24b008a7c3
3 files changed
+84
No files matched your search
@@ -773,6 +773,58 @@ impl Entry {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn raw_value_at<R: Read + Seek>(
|
||||||
|
&self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
bigtiff: bool,
|
||||||
|
reader: &mut EndianReader<R>,
|
||||||
|
at: u64,
|
||||||
|
) -> TiffResult<usize> {
|
||||||
|
if self.count == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have no limits to handle, we do not allocate.
|
||||||
|
let value_bytes = self.type_.value_bytes(self.count)?;
|
||||||
|
|
||||||
|
// No bytes to fill into the buffer.
|
||||||
|
if at >= value_bytes {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 1: the value fits in the offset field.
|
||||||
|
if value_bytes <= 4 || bigtiff && value_bytes <= 8 {
|
||||||
|
// `at < value_bytes` and `value_bytes <= 8` so casting is mathematical
|
||||||
|
let src = &self.offset[..value_bytes as usize][at as usize..];
|
||||||
|
let len = src.len().min(buf.len());
|
||||||
|
buf[..len].copy_from_slice(&src[..len]);
|
||||||
|
return Ok(value_bytes as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: the value is stored in the reader at an offset. We will find the offset
|
||||||
|
// encoded in the entry, apply the relative start position and seek there.
|
||||||
|
self.set_reader_offset_relative(bigtiff, reader, at)?;
|
||||||
|
|
||||||
|
let remainder = value_bytes - at;
|
||||||
|
let len = usize::try_from(remainder)
|
||||||
|
.unwrap_or(usize::MAX)
|
||||||
|
.min(buf.len());
|
||||||
|
|
||||||
|
let target = &mut buf[..len];
|
||||||
|
reader.inner().read_exact(target)?;
|
||||||
|
|
||||||
|
// Design note: in a previous draft we would consume the rest of the bytes of this value
|
||||||
|
// here (into a stack buffer if need be) to verify the stream itself. But in the end we
|
||||||
|
// have `Seek` so we better verify this by seeking over the rest of the bytes, finding if
|
||||||
|
// the stream continues that far. Even that is maybe bad if we wanted to provide a
|
||||||
|
// async-adaptor that `WouldBlock` errors to fill back a read window then the seek is
|
||||||
|
// poison to that, too.
|
||||||
|
|
||||||
|
// So a really simple choice: The caller is responsible for handling the fact that this did
|
||||||
|
// not verify the whole value. Attempt a 1-byte read at the end of the value instead?
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
// Returns `Ok(bytes)` if our value's bytes through type and count fit into `usize` and are
|
// Returns `Ok(bytes)` if our value's bytes through type and count fit into `usize` and are
|
||||||
// within the limits. Extends the buffer to that many bytes.
|
// within the limits. Extends the buffer to that many bytes.
|
||||||
fn buffer_with_capacity(
|
fn buffer_with_capacity(
|
||||||
|
|||||||
@@ -1742,6 +1742,16 @@ impl IfdDecoder<'_> {
|
|||||||
self.inner.find_tag_buf(tag, buf)
|
self.inner.find_tag_buf(tag, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read bytes of a tag's value into a byte buffer.
|
||||||
|
pub fn find_tag_bytes(
|
||||||
|
&mut self,
|
||||||
|
tag: Tag,
|
||||||
|
buf: &mut [u8],
|
||||||
|
offset: u64,
|
||||||
|
) -> TiffResult<Option<usize>> {
|
||||||
|
self.inner.find_tag_raw(tag, buf, offset)
|
||||||
|
}
|
||||||
|
|
||||||
/// Tries to retrieve a tag and convert it to the desired unsigned type.
|
/// Tries to retrieve a tag and convert it to the desired unsigned type.
|
||||||
pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> {
|
pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> {
|
||||||
self.find_tag(tag)?
|
self.find_tag(tag)?
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ pub(crate) trait EntryDecoder {
|
|||||||
fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value>;
|
fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value>;
|
||||||
/// Fill a `ValueBuffer` by fetching the required bytes.
|
/// Fill a `ValueBuffer` by fetching the required bytes.
|
||||||
fn entry_buf(&mut self, entry: &Entry, _: &mut ValueBuffer) -> TiffResult<()>;
|
fn entry_buf(&mut self, entry: &Entry, _: &mut ValueBuffer) -> TiffResult<()>;
|
||||||
|
/// Fill the prefix of the buffer and return the actual bytes. Start interpreting the inner
|
||||||
|
/// value at `offset`.
|
||||||
|
fn entry_raw(&mut self, entry: &Entry, _: &mut [u8], offset: u64) -> TiffResult<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Seek + Read> EntryDecoder for ValueReader<R> {
|
impl<R: Seek + Read> EntryDecoder for ValueReader<R> {
|
||||||
@@ -28,6 +31,10 @@ impl<R: Seek + Read> EntryDecoder for ValueReader<R> {
|
|||||||
fn entry_buf(&mut self, entry: &Entry, buf: &mut ValueBuffer) -> TiffResult<()> {
|
fn entry_buf(&mut self, entry: &Entry, buf: &mut ValueBuffer) -> TiffResult<()> {
|
||||||
entry.buffered_value(buf, &self.limits, self.bigtiff, &mut self.reader)
|
entry.buffered_value(buf, &self.limits, self.bigtiff, &mut self.reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn entry_raw(&mut self, entry: &Entry, buf: &mut [u8], offset: u64) -> TiffResult<usize> {
|
||||||
|
entry.raw_value_at(buf, self.bigtiff, &mut self.reader, offset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: EntryDecoder + ?Sized> TagReader<'a, R> {
|
impl<'a, R: EntryDecoder + ?Sized> TagReader<'a, R> {
|
||||||
@@ -58,6 +65,21 @@ impl<'a, R: EntryDecoder + ?Sized> TagReader<'a, R> {
|
|||||||
Ok(Some(entry))
|
Ok(Some(entry))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn find_tag_raw(
|
||||||
|
&mut self,
|
||||||
|
tag: Tag,
|
||||||
|
buf: &mut [u8],
|
||||||
|
at: u64,
|
||||||
|
) -> TiffResult<Option<usize>> {
|
||||||
|
let entry = match self.ifd.get(tag) {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(entry) => entry.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = self.decoder.entry_raw(&entry, buf, at)?;
|
||||||
|
Ok(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn require_tag(&mut self, tag: Tag) -> TiffResult<Value> {
|
pub(crate) fn require_tag(&mut self, tag: Tag) -> TiffResult<Value> {
|
||||||
match self.find_tag(tag)? {
|
match self.find_tag(tag)? {
|
||||||
Some(val) => Ok(val),
|
Some(val) => Ok(val),
|
||||||
|
|||||||
Reference in new issue
Block a user