Merge pull request #325 from image-rs/decode-values-into-buffer
Decode tag values into buffer
This commit is contained in:
4 files changed
+326
-11
No files matched your search
+122
-4
@@ -6,7 +6,7 @@ use std::mem;
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use super::stream::{ByteOrder, EndianReader};
|
use super::stream::{ByteOrder, EndianReader};
|
||||||
use crate::tags::{IfdPointer, Tag, Type};
|
use crate::tags::{IfdPointer, Tag, Type, ValueBuffer};
|
||||||
use crate::{TiffError, TiffFormatError, TiffResult};
|
use crate::{TiffError, TiffFormatError, TiffResult};
|
||||||
|
|
||||||
use self::Value::{
|
use self::Value::{
|
||||||
@@ -579,7 +579,7 @@ impl Entry {
|
|||||||
|
|
||||||
// Case 4: there is more than one value, and it doesn't fit in the offset field.
|
// Case 4: there is more than one value, and it doesn't fit in the offset field.
|
||||||
let mut v;
|
let mut v;
|
||||||
self.set_reader_offset(bo, bigtiff, reader)?;
|
self.set_reader_offset_relative(bigtiff, reader, 0)?;
|
||||||
|
|
||||||
match self.type_ {
|
match self.type_ {
|
||||||
Type::BYTE | Type::UNDEFINED => {
|
Type::BYTE | Type::UNDEFINED => {
|
||||||
@@ -737,6 +737,113 @@ impl Entry {
|
|||||||
Ok(List(v))
|
Ok(List(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn buffered_value<R: Read + Seek>(
|
||||||
|
&self,
|
||||||
|
buf: &mut ValueBuffer,
|
||||||
|
limits: &super::Limits,
|
||||||
|
bigtiff: bool,
|
||||||
|
reader: &mut EndianReader<R>,
|
||||||
|
) -> TiffResult<()> {
|
||||||
|
if self.count == 0 {
|
||||||
|
buf.assume_type(self.type_, 0, reader.byte_order);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let value_bytes = self.buffer_with_capacity(buf, limits)?;
|
||||||
|
|
||||||
|
// Case 1: the value fits in the offset field.
|
||||||
|
if value_bytes <= 4 || bigtiff && value_bytes <= 8 {
|
||||||
|
let src = &self.offset[..value_bytes];
|
||||||
|
buf.raw_bytes_mut()[..value_bytes].copy_from_slice(src);
|
||||||
|
buf.assume_type(self.type_, self.count, reader.byte_order);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: the value is stored in the reader at an offset.
|
||||||
|
self.set_reader_offset_relative(bigtiff, reader, 0)?;
|
||||||
|
|
||||||
|
// In case of an error we set the type and endianess.
|
||||||
|
buf.assume_type(self.type_, 0, reader.byte_order);
|
||||||
|
let target = &mut buf.raw_bytes_mut()[..value_bytes];
|
||||||
|
// FIXME: if the read fails we have already grown to full size, which is not great.
|
||||||
|
reader.inner().read_exact(target)?;
|
||||||
|
buf.assume_type(self.type_, self.count, reader.byte_order);
|
||||||
|
|
||||||
|
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
|
||||||
|
// within the limits. Extends the buffer to that many bytes.
|
||||||
|
fn buffer_with_capacity(
|
||||||
|
&self,
|
||||||
|
buf: &mut ValueBuffer,
|
||||||
|
limits: &super::Limits,
|
||||||
|
) -> TiffResult<usize> {
|
||||||
|
let bytes = self.type_.value_bytes(self.count())?;
|
||||||
|
|
||||||
|
let allowed_length = usize::try_from(bytes)
|
||||||
|
.ok()
|
||||||
|
.filter(|&n| n <= limits.decoding_buffer_size)
|
||||||
|
.ok_or(TiffError::LimitsExceeded)?;
|
||||||
|
|
||||||
|
buf.prepare_length(allowed_length);
|
||||||
|
|
||||||
|
Ok(allowed_length)
|
||||||
|
}
|
||||||
|
|
||||||
fn vec_with_capacity(
|
fn vec_with_capacity(
|
||||||
value_count: u64,
|
value_count: u64,
|
||||||
limits: &super::Limits,
|
limits: &super::Limits,
|
||||||
@@ -750,21 +857,32 @@ impl Entry {
|
|||||||
Ok(Vec::with_capacity(value_count))
|
Ok(Vec::with_capacity(value_count))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_reader_offset<R>(
|
/// Seek to an offset within a value stored in the offset defined by this entry.
|
||||||
|
fn set_reader_offset_relative<R>(
|
||||||
&self,
|
&self,
|
||||||
bo: ByteOrder,
|
|
||||||
bigtiff: bool,
|
bigtiff: bool,
|
||||||
reader: &mut EndianReader<R>,
|
reader: &mut EndianReader<R>,
|
||||||
|
at: u64,
|
||||||
) -> TiffResult<()>
|
) -> TiffResult<()>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
|
let bo = reader.byte_order;
|
||||||
|
|
||||||
let offset = if bigtiff {
|
let offset = if bigtiff {
|
||||||
self.offset_field_reader(bo).read_u64()?
|
self.offset_field_reader(bo).read_u64()?
|
||||||
} else {
|
} else {
|
||||||
self.offset_field_reader(bo).read_u32()?.into()
|
self.offset_field_reader(bo).read_u32()?.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: `at` should be within `self.type_.value_bytes(self.count)` and that itself should
|
||||||
|
// be within the bounds of the stream. But we do not check this eagerly so this below will
|
||||||
|
// fail sometimes differently for exotic streams, depending on the method by which we read
|
||||||
|
// (at once or through multiple raw into-byte-slice reads).
|
||||||
|
let offset = offset.checked_add(at).ok_or(TiffError::FormatError(
|
||||||
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
|
))?;
|
||||||
|
|
||||||
reader.goto_offset(offset)?;
|
reader.goto_offset(offset)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+97
-1
@@ -5,7 +5,7 @@ use std::num::NonZeroUsize;
|
|||||||
|
|
||||||
use crate::tags::{
|
use crate::tags::{
|
||||||
CompressionMethod, IfdPointer, PhotometricInterpretation, PlanarConfiguration, Predictor,
|
CompressionMethod, IfdPointer, PhotometricInterpretation, PlanarConfiguration, Predictor,
|
||||||
SampleFormat, Tag, Type,
|
SampleFormat, Tag, Type, ValueBuffer,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
bytecast, ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError,
|
bytecast, ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError,
|
||||||
@@ -1717,12 +1717,41 @@ impl<R: Seek + Read> ValueReader<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IfdDecoder<'_> {
|
impl IfdDecoder<'_> {
|
||||||
|
/// Retrieve the IFD entry for a given tag, if it exists.
|
||||||
|
///
|
||||||
|
/// The entry contains the metadata of the value, that is its type and count from which we can
|
||||||
|
/// calculate a total byte size.
|
||||||
|
pub fn find_entry(&self, tag: Tag) -> Option<ifd::Entry> {
|
||||||
|
self.inner.ifd.get(tag).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
/// Tries to retrieve a tag.
|
/// Tries to retrieve a tag.
|
||||||
/// Return `Ok(None)` if the tag is not present.
|
/// Return `Ok(None)` if the tag is not present.
|
||||||
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
|
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
|
||||||
self.inner.find_tag(tag)
|
self.inner.find_tag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a tag and reproduce its bytes into the provided buffer.
|
||||||
|
///
|
||||||
|
/// The buffer is unmodified if the tag is not present.
|
||||||
|
pub fn find_tag_buf(
|
||||||
|
&mut self,
|
||||||
|
tag: Tag,
|
||||||
|
buf: &mut ValueBuffer,
|
||||||
|
) -> TiffResult<Option<ifd::Entry>> {
|
||||||
|
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)?
|
||||||
@@ -1836,3 +1865,70 @@ impl<'l> IfdDecoder<'l> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Decoder;
|
||||||
|
use crate::{
|
||||||
|
bytecast,
|
||||||
|
tags::{ByteOrder, Tag, ValueBuffer},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equivalence_of_tag_readers() {
|
||||||
|
let file = std::fs::File::open(concat!(
|
||||||
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
|
"/tests/images/int8_rgb.tif"
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut decoder = Decoder::new(file).unwrap();
|
||||||
|
let file_bo = decoder.byte_order();
|
||||||
|
let mut ifd = decoder.image_ifd();
|
||||||
|
|
||||||
|
{
|
||||||
|
let value = ifd
|
||||||
|
.find_tag(Tag::BitsPerSample)
|
||||||
|
.unwrap()
|
||||||
|
.expect("must have BitsPerSample");
|
||||||
|
|
||||||
|
let samples = value.into_u16_vec().unwrap();
|
||||||
|
assert_eq!(samples.as_slice(), [8, 8, 8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut value = ValueBuffer::from_value(&[0u16; 4]);
|
||||||
|
let _entry = ifd
|
||||||
|
.find_tag_buf(Tag::BitsPerSample, &mut value)
|
||||||
|
.unwrap()
|
||||||
|
.expect("must have BitsPerSample");
|
||||||
|
|
||||||
|
value.set_byte_order(ByteOrder::native());
|
||||||
|
assert_eq!(value.as_bytes(), bytecast::u16_as_ne_bytes(&[8, 8, 8]));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut by_bytes = [0u16; 4];
|
||||||
|
let entry = ifd
|
||||||
|
.find_entry(Tag::BitsPerSample)
|
||||||
|
.expect("must have BitsPerSample");
|
||||||
|
|
||||||
|
let byte_len = ifd
|
||||||
|
.find_tag_bytes(
|
||||||
|
Tag::BitsPerSample,
|
||||||
|
bytecast::u16_as_ne_mut_bytes(&mut by_bytes),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.expect("must have BitsPerSample");
|
||||||
|
assert_eq!(byte_len, 3 * std::mem::size_of::<u16>());
|
||||||
|
|
||||||
|
file_bo.convert(
|
||||||
|
entry.field_type(),
|
||||||
|
bytecast::u16_as_ne_mut_bytes(&mut by_bytes[..3]),
|
||||||
|
ByteOrder::native(),
|
||||||
|
);
|
||||||
|
assert_eq!(&by_bytes[..3], &[8, 8, 8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
use crate::{tags::Tag, Directory};
|
use crate::{
|
||||||
use crate::{TiffError, TiffFormatError, TiffResult};
|
tags::{Tag, ValueBuffer},
|
||||||
|
Directory, TiffError, TiffFormatError, TiffResult,
|
||||||
|
};
|
||||||
|
|
||||||
use super::ifd::{Entry, Value};
|
use super::ifd::{Entry, Value};
|
||||||
use super::ValueReader;
|
use super::ValueReader;
|
||||||
@@ -14,12 +16,25 @@ pub(crate) struct TagReader<'lt, R: EntryDecoder + ?Sized> {
|
|||||||
pub(crate) trait EntryDecoder {
|
pub(crate) trait EntryDecoder {
|
||||||
/// Turn an entry into a value by fetching the required bytes in the stream.
|
/// Turn an entry into a value by fetching the required bytes in the stream.
|
||||||
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.
|
||||||
|
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> {
|
||||||
fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value> {
|
fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value> {
|
||||||
entry.val(&self.limits, self.bigtiff, &mut self.reader)
|
entry.val(&self.limits, self.bigtiff, &mut self.reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn entry_buf(&mut self, entry: &Entry, buf: &mut ValueBuffer) -> TiffResult<()> {
|
||||||
|
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> {
|
||||||
@@ -32,6 +47,39 @@ impl<'a, R: EntryDecoder + ?Sized> TagReader<'a, R> {
|
|||||||
self.decoder.entry_val(&entry).map(Some)
|
self.decoder.entry_val(&entry).map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find a tag and fill the provided buffer with its raw data.
|
||||||
|
///
|
||||||
|
/// Returns the entry of the tag if found. This signals that the buffer was overwritten.
|
||||||
|
/// Otherwise the buffer is preserved as-is.
|
||||||
|
pub(crate) fn find_tag_buf(
|
||||||
|
&mut self,
|
||||||
|
tag: Tag,
|
||||||
|
buf: &mut ValueBuffer,
|
||||||
|
) -> TiffResult<Option<Entry>> {
|
||||||
|
let entry = match self.ifd.get(tag) {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(entry) => entry.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.decoder.entry_buf(&entry, buf)?;
|
||||||
|
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),
|
||||||
|
|||||||
+57
-4
@@ -346,6 +346,10 @@ pub struct ValueBuffer {
|
|||||||
/// The type of the value.
|
/// The type of the value.
|
||||||
ty: Type,
|
ty: Type,
|
||||||
|
|
||||||
|
/// The number of items, as `bytes` may be oversized while holding bytes that are initialized
|
||||||
|
/// but not used by any value.
|
||||||
|
count: u64,
|
||||||
|
|
||||||
/// The byte order of the value.
|
/// The byte order of the value.
|
||||||
byte_order: ByteOrder,
|
byte_order: ByteOrder,
|
||||||
}
|
}
|
||||||
@@ -358,6 +362,7 @@ impl ValueBuffer {
|
|||||||
ValueBuffer {
|
ValueBuffer {
|
||||||
bytes: vec![],
|
bytes: vec![],
|
||||||
ty,
|
ty,
|
||||||
|
count: 0,
|
||||||
byte_order: ByteOrder::native(),
|
byte_order: ByteOrder::native(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,6 +372,7 @@ impl ValueBuffer {
|
|||||||
ValueBuffer {
|
ValueBuffer {
|
||||||
bytes: value.data().into_owned(),
|
bytes: value.data().into_owned(),
|
||||||
ty: <T as TiffValue>::FIELD_TYPE,
|
ty: <T as TiffValue>::FIELD_TYPE,
|
||||||
|
count: value.count() as u64,
|
||||||
byte_order: ByteOrder::native(),
|
byte_order: ByteOrder::native(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,26 +387,73 @@ impl ValueBuffer {
|
|||||||
|
|
||||||
/// The count of items in the value.
|
/// The count of items in the value.
|
||||||
pub fn count(&self) -> u64 {
|
pub fn count(&self) -> u64 {
|
||||||
(self.bytes.len() / usize::from(self.ty.byte_len())) as u64
|
debug_assert!({
|
||||||
|
self.ty
|
||||||
|
.value_bytes(self.count)
|
||||||
|
.is_ok_and(|n| n < self.bytes.len() as u64)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying raw bytes of this value.
|
/// View the underlying raw bytes of this value.
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
&self.bytes
|
&self.bytes[..self.assumed_len_from_count()]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying mutable raw bytes of this value.
|
/// View the underlying mutable raw bytes of this value.
|
||||||
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
|
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
|
||||||
&mut self.bytes
|
let len = self.assumed_len_from_count();
|
||||||
|
&mut self.bytes[..len]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the byte order of the value representation.
|
/// Change the byte order of the value representation.
|
||||||
pub fn set_byte_order(&mut self, byte_order: ByteOrder) {
|
pub fn set_byte_order(&mut self, byte_order: ByteOrder) {
|
||||||
|
let len = self.assumed_len_from_count();
|
||||||
|
|
||||||
self.byte_order
|
self.byte_order
|
||||||
.convert(self.ty, self.bytes.as_mut_slice(), byte_order);
|
.convert(self.ty, &mut self.bytes[..len], byte_order);
|
||||||
|
|
||||||
self.byte_order = byte_order;
|
self.byte_order = byte_order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prepare the internal for a value `to_len` bytes long.
|
||||||
|
///
|
||||||
|
/// Shrinks the allocation if it is far too large or extends it if it is too small. In either
|
||||||
|
/// case ensures that at least `to_len` bytes are initialized for [`Self::raw_bytes_mut`].
|
||||||
|
pub(crate) fn prepare_length(&mut self, to_len: usize) {
|
||||||
|
if to_len > self.bytes.len() {
|
||||||
|
self.bytes.resize(to_len, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.bytes.len() < to_len / 2 {
|
||||||
|
self.bytes.truncate(to_len);
|
||||||
|
self.bytes.shrink_to_fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal method to change the type and count while re-interpreting the byte buffer.
|
||||||
|
///
|
||||||
|
/// Should only be called after writing bytes to the internal buffer prepared with
|
||||||
|
/// `Self::prepare_length`.
|
||||||
|
pub(crate) fn assume_type(&mut self, ty: Type, count: u64, bo: ByteOrder) {
|
||||||
|
debug_assert!({
|
||||||
|
ty.value_bytes(count)
|
||||||
|
.is_ok_and(|n| n < self.bytes.len() as u64)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.byte_order = bo;
|
||||||
|
self.ty = ty;
|
||||||
|
self.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn raw_bytes_mut(&mut self) -> &mut [u8] {
|
||||||
|
&mut self.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assumed_len_from_count(&self) -> usize {
|
||||||
|
usize::from(self.ty.byte_len()) * self.count as usize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte order of the TIFF file.
|
/// Byte order of the TIFF file.
|
||||||
|
|||||||
Reference in new issue
Block a user