Reading fields shouldn't need the entire Decoder

This commit is contained in:
Jonathan Behrens committed 2022-01-12 19:50:06 -05:00
1 parent 23fe194ad9
commit 2d10cff97e
3 files changed
+79 -61

No files matched your search

+73 -58
View File
@@ -341,14 +341,15 @@ impl Entry {
pub fn val<R: Read + Seek>( pub fn val<R: Read + Seek>(
&self, &self,
limits: &super::Limits, limits: &super::Limits,
decoder: &mut super::Decoder<R>, bigtiff: bool,
reader: &mut SmartReader<R>,
) -> TiffResult<Value> { ) -> TiffResult<Value> {
// Case 1: there are no values so we can return immediately. // Case 1: there are no values so we can return immediately.
if self.count == 0 { if self.count == 0 {
return Ok(List(Vec::new())); return Ok(List(Vec::new()));
} }
let bo = decoder.byte_order(); let bo = reader.byte_order();
let tag_size = match self.type_ { let tag_size = match self.type_ {
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1, Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
@@ -373,7 +374,7 @@ impl Entry {
// Case 2: there is one value. // Case 2: there is one value.
if self.count == 1 { if self.count == 1 {
// 2a: the value is 5-8 bytes and we're in BigTiff mode. // 2a: the value is 5-8 bytes and we're in BigTiff mode.
if decoder.bigtiff && value_bytes > 4 && value_bytes <= 8 { if bigtiff && value_bytes > 4 && value_bytes <= 8 {
return Ok(match self.type_ { return Ok(match self.type_ {
Type::LONG8 => UnsignedBig(self.r(bo).read_u64()?), Type::LONG8 => UnsignedBig(self.r(bo).read_u64()?),
Type::SLONG8 => SignedBig(self.r(bo).read_i64()?), Type::SLONG8 => SignedBig(self.r(bo).read_i64()?),
@@ -419,36 +420,36 @@ impl Entry {
} }
} }
Type::LONG8 => { Type::LONG8 => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
UnsignedBig(decoder.read_long8()?) UnsignedBig(reader.read_u64()?)
} }
Type::SLONG8 => { Type::SLONG8 => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
SignedBig(decoder.read_slong8()?) SignedBig(reader.read_i64()?)
} }
Type::DOUBLE => { Type::DOUBLE => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
Double(decoder.read_double()?) Double(reader.read_f64()?)
} }
Type::RATIONAL => { Type::RATIONAL => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
Rational(decoder.read_long()?, decoder.read_long()?) Rational(reader.read_u32()?, reader.read_u32()?)
} }
Type::SRATIONAL => { Type::SRATIONAL => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
SRational(decoder.read_slong()?, decoder.read_slong()?) SRational(reader.read_i32()?, reader.read_i32()?)
} }
Type::IFD => Ifd(self.r(bo).read_u32()?), Type::IFD => Ifd(self.r(bo).read_u32()?),
Type::IFD8 => { Type::IFD8 => {
decoder.goto_offset(self.r(bo).read_u32()?)?; reader.goto_offset(self.r(bo).read_u32()?.into())?;
IfdBig(decoder.read_long8()?) IfdBig(reader.read_u64()?)
} }
Type::__NonExhaustive => unreachable!(), Type::__NonExhaustive => unreachable!(),
}); });
} }
// Case 3: There is more than one value, but it fits in the offset field. // Case 3: There is more than one value, but it fits in the offset field.
if value_bytes <= 4 || decoder.bigtiff && value_bytes <= 8 { if value_bytes <= 4 || bigtiff && value_bytes <= 8 {
match self.type_ { match self.type_ {
Type::BYTE => return Ok(offset_to_bytes(self.count as usize, self)?), Type::BYTE => return Ok(offset_to_bytes(self.count as usize, self)?),
Type::SBYTE => return Ok(offset_to_sbytes(self.count as usize, self)?), Type::SBYTE => return Ok(offset_to_sbytes(self.count as usize, self)?),
@@ -535,50 +536,54 @@ impl Entry {
match self.type_ { match self.type_ {
// TODO check if this could give wrong results // TODO check if this could give wrong results
// at a different endianess of file/computer. // at a different endianess of file/computer.
Type::BYTE => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::BYTE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(UnsignedBig(u64::from(decoder.read_byte()?))) let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
Ok(UnsignedBig(u64::from(buf[0])))
}), }),
Type::SBYTE => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SBYTE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(SignedBig(i64::from(decoder.read_byte()? as i8))) Ok(SignedBig(i64::from(reader.read_i8()? as i8)))
}), }),
Type::SHORT => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SHORT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(UnsignedBig(u64::from(decoder.read_short()?))) Ok(UnsignedBig(u64::from(reader.read_u16()?)))
}), }),
Type::SSHORT => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SSHORT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(SignedBig(i64::from(decoder.read_sshort()?))) Ok(SignedBig(i64::from(reader.read_i16()?)))
}), }),
Type::LONG => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::LONG => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Unsigned(decoder.read_long()?)) Ok(Unsigned(reader.read_u32()?))
}), }),
Type::SLONG => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SLONG => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Signed(decoder.read_slong()?)) Ok(Signed(reader.read_i32()?))
}), }),
Type::FLOAT => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::FLOAT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Float(decoder.read_float()?)) Ok(Float(reader.read_f32()?))
}), }),
Type::DOUBLE => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::DOUBLE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Double(decoder.read_double()?)) Ok(Double(reader.read_f64()?))
}), }),
Type::RATIONAL => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::RATIONAL => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Rational(decoder.read_long()?, decoder.read_long()?)) Ok(Rational(reader.read_u32()?, reader.read_u32()?))
}), }),
Type::SRATIONAL => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SRATIONAL => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(SRational(decoder.read_slong()?, decoder.read_slong()?)) Ok(SRational(reader.read_i32()?, reader.read_i32()?))
}), }),
Type::LONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::LONG8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(UnsignedBig(decoder.read_long8()?)) Ok(UnsignedBig(reader.read_u64()?))
}), }),
Type::SLONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::SLONG8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(SignedBig(decoder.read_slong8()?)) Ok(SignedBig(reader.read_i64()?))
}), }),
Type::IFD => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::IFD => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Ifd(decoder.read_long()?)) Ok(Ifd(reader.read_u32()?))
}), }),
Type::IFD8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::IFD8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(IfdBig(decoder.read_long8()?)) Ok(IfdBig(reader.read_u64()?))
}), }),
Type::UNDEFINED => self.decode_offset(self.count, bo, limits, decoder, |decoder| { Type::UNDEFINED => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
Ok(Byte(u8::from(decoder.read_byte()?))) let mut buf = [0; 1];
reader.read_exact(&mut buf)?;
Ok(Byte(buf[0]))
}), }),
Type::ASCII => { Type::ASCII => {
let n = usize::try_from(self.count)?; let n = usize::try_from(self.count)?;
@@ -586,13 +591,19 @@ impl Entry {
return Err(TiffError::LimitsExceeded); return Err(TiffError::LimitsExceeded);
} }
if decoder.bigtiff { if bigtiff {
decoder.goto_offset_u64(self.r(bo).read_u64()?)? reader.goto_offset(self.r(bo).read_u64()?)?
} else { } else {
decoder.goto_offset(self.r(bo).read_u32()?)? reader.goto_offset(self.r(bo).read_u32()?.into())?
} }
let string = decoder.read_string(n)?;
Ok(Ascii(string)) let mut out = vec![0; n];
reader.read_exact(&mut out)?;
// Strings may be null-terminated, so we trim anything downstream of the null byte
if let Some(first) = out.iter().position(|&b| b == 0) {
out.truncate(first);
}
Ok(Ascii(String::from_utf8(out)?))
} }
Type::__NonExhaustive => unreachable!(), Type::__NonExhaustive => unreachable!(),
} }
@@ -603,13 +614,14 @@ impl Entry {
&self, &self,
value_count: u64, value_count: u64,
bo: ByteOrder, bo: ByteOrder,
bigtiff: bool,
limits: &super::Limits, limits: &super::Limits,
decoder: &mut super::Decoder<R>, reader: &mut SmartReader<R>,
decode_fn: F, decode_fn: F,
) -> TiffResult<Value> ) -> TiffResult<Value>
where where
R: Read + Seek, R: Read + Seek,
F: Fn(&mut super::Decoder<R>) -> TiffResult<Value>, F: Fn(&mut SmartReader<R>) -> TiffResult<Value>,
{ {
let value_count = usize::try_from(value_count)?; let value_count = usize::try_from(value_count)?;
if value_count > limits.decoding_buffer_size / mem::size_of::<Value>() { if value_count > limits.decoding_buffer_size / mem::size_of::<Value>() {
@@ -617,13 +629,16 @@ impl Entry {
} }
let mut v = Vec::with_capacity(value_count); let mut v = Vec::with_capacity(value_count);
if decoder.bigtiff {
decoder.goto_offset_u64(self.r(bo).read_u64()?)? let offset = if bigtiff {
self.r(bo).read_u64()?
} else { } else {
decoder.goto_offset(self.r(bo).read_u32()?)? self.r(bo).read_u32()?.into()
} };
reader.goto_offset(offset)?;
for _ in 0..value_count { for _ in 0..value_count {
v.push(decode_fn(decoder)?) v.push(decode_fn(reader)?)
} }
Ok(List(v)) Ok(List(v))
} }
+1 -3
View File
@@ -988,9 +988,7 @@ impl<R: Read + Seek> Decoder<R> {
Some(entry) => entry.clone(), Some(entry) => entry.clone(),
}; };
let limits = self.limits.clone(); Ok(Some(entry.val(&self.limits, self.bigtiff, &mut self.reader)?))
Ok(Some(entry.val(&limits, self)?))
} }
/// 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.
+5
View File
@@ -343,6 +343,11 @@ where
self.reader self.reader
} }
} }
impl<R: Read + Seek> SmartReader<R> {
pub fn goto_offset(&mut self, offset: u64) -> io::Result<()> {
self.seek(io::SeekFrom::Start(offset)).map(|_| ())
}
}
impl<R> EndianReader for SmartReader<R> impl<R> EndianReader for SmartReader<R>
where where