feat: Support decoding big tiff

This commit is contained in:
Etienne Prothon committed 2020-07-23 01:33:41 +02:00
1 parent 472cf6d07d
commit 23751bd8c5
3 files changed
+270 -156

No files matched your search

+167 -100
View File
@@ -15,18 +15,18 @@ use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
#[allow(unused_qualifications)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Value {
Signed(i32),
Unsigned(u32),
Signed(i64),
Unsigned(u64),
List(Vec<Value>),
Rational(u32, u32),
SRational(i32, i32),
Rational(u64, u64),
SRational(i64, i64),
Ascii(String),
#[doc(hidden)] // Do not match against this.
__NonExhaustive,
}
impl Value {
pub fn into_u32(self) -> TiffResult<u32> {
pub fn into_u64(self) -> TiffResult<u64> {
match self {
Unsigned(val) => Ok(val),
val => Err(TiffError::FormatError(
@@ -35,7 +35,7 @@ impl Value {
}
}
pub fn into_i32(self) -> TiffResult<i32> {
pub fn into_i64(self) -> TiffResult<i64> {
match self {
Signed(val) => Ok(val),
val => Err(TiffError::FormatError(
@@ -44,25 +44,25 @@ impl Value {
}
}
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
pub fn into_u64_vec(self) -> TiffResult<Vec<u64>> {
match self {
List(vec) => {
let mut new_vec = Vec::with_capacity(vec.len());
for v in vec {
new_vec.push(v.into_u32()?)
new_vec.push(v.into_u64()?)
}
Ok(new_vec)
}
Unsigned(val) => Ok(vec![val]),
Rational(numerator, denominator) => Ok(vec![numerator, denominator]),
Ascii(val) => Ok(val.chars().map(u32::from).collect()),
Ascii(val) => Ok(val.chars().map(u32::from).map(u64::from).collect()),
val => Err(TiffError::FormatError(
TiffFormatError::UnsignedIntegerExpected(val),
)),
}
}
pub fn into_i32_vec(self) -> TiffResult<Vec<i32>> {
pub fn into_i64_vec(self) -> TiffResult<Vec<i64>> {
match self {
List(vec) => {
let mut new_vec = Vec::with_capacity(vec.len());
@@ -72,7 +72,7 @@ impl Value {
new_vec.push(numerator);
new_vec.push(denominator);
}
_ => new_vec.push(v.into_i32()?)
_ => new_vec.push(v.into_i64()?),
}
}
Ok(new_vec)
@@ -85,12 +85,12 @@ impl Value {
}
}
}
#[derive(Clone)]
pub struct Entry {
type_: Type,
count: u32,
offset: [u8; 4],
count: u64,
offset: [u8; 8],
}
impl ::std::fmt::Debug for Entry {
@@ -103,7 +103,7 @@ impl ::std::fmt::Debug for Entry {
}
impl Entry {
pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry {
pub fn new(type_: Type, count: u64, offset: [u8; 8]) -> Entry {
Entry {
type_,
count,
@@ -122,94 +122,156 @@ impl Entry {
decoder: &mut super::Decoder<R>,
) -> TiffResult<Value> {
let bo = decoder.byte_order();
match (self.type_, self.count) {
// TODO check if this could give wrong results
// at a different endianess of file/computer.
(Type::BYTE, 1) => Ok(Unsigned(u32::from(self.offset[0]))),
(Type::BYTE, 2) => offset_to_bytes(2, self),
(Type::BYTE, 3) => offset_to_bytes(3, self),
(Type::BYTE, 4) => offset_to_bytes(4, self),
(Type::BYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(u32::from(decoder.read_byte()?)))
}),
(Type::SBYTE, 1) => Ok(Signed(i32::from(self.offset[0] as i8))),
(Type::SBYTE, 2) => offset_to_sbytes(2, self),
(Type::SBYTE, 3) => offset_to_sbytes(3, self),
(Type::SBYTE, 4) => offset_to_sbytes(4, self),
(Type::SBYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(i32::from(decoder.read_byte()? as i8)))
}),
(Type::SHORT, 1) => Ok(Unsigned(u32::from(self.r(bo).read_u16()?))),
(Type::SSHORT, 1) => Ok(Signed(i32::from(self.r(bo).read_i16()?))),
(Type::SHORT, 2) => {
let mut r = self.r(bo);
Ok(List(vec![
Unsigned(u32::from(r.read_u16()?)),
Unsigned(u32::from(r.read_u16()?)),
]))
}
(Type::SSHORT, 2) => {
let mut r = self.r(bo);
Ok(List(vec![
Signed(i32::from(r.read_i16()?)),
Signed(i32::from(r.read_i16()?)),
]))
}
(Type::SHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(u32::from(decoder.read_short()?)))
}),
(Type::SSHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(i32::from(decoder.read_sshort()?)))
}),
(Type::LONG, 1) => Ok(Unsigned(self.r(bo).read_u32()?)),
(Type::SLONG, 1) => Ok(Signed(self.r(bo).read_i32()?)),
(Type::LONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(decoder.read_long()?))
}),
(Type::SLONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(decoder.read_slong()?))
}),
(Type::RATIONAL, 1) => {
decoder.goto_offset(self.r(bo).read_u32()?)?;
let numerator = decoder.read_long()?;
let denominator = decoder.read_long()?;
Ok(Rational(numerator, denominator))
}
(Type::SRATIONAL, 1) => {
decoder.goto_offset(self.r(bo).read_u32()?)?;
let numerator = decoder.read_slong()?;
let denominator = decoder.read_slong()?;
Ok(SRational(numerator, denominator))
}
(Type::RATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Rational(
decoder.read_long()?,
decoder.read_long()?,
))
}),
(Type::SRATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(SRational(
decoder.read_slong()?,
decoder.read_slong()?,
))
}),
(Type::ASCII, n) => {
let n = usize::try_from(n)?;
if n > limits.decoding_buffer_size {
return Err(TiffError::LimitsExceeded);
let bigtiff_value = if decoder.bigtiff && 4 < self.count && self.count <= 8 {
match (self.type_, self.count) {
(Type::BYTE, n) => Some(offset_to_bytes(n as usize, self)?),
(Type::SBYTE, n) => Some(offset_to_sbytes(n as usize, self)?),
(Type::SHORT, 3) => {
let mut r = self.r(bo);
Some(List(vec![
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
]))
}
decoder.goto_offset(self.r(bo).read_u32()?)?;
let string = decoder.read_string(n)?;
Ok(Ascii(string))
(Type::SSHORT, 3) => {
let mut r = self.r(bo);
Some(List(vec![
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
]))
}
(Type::SHORT, 4) => {
let mut r = self.r(bo);
Some(List(vec![
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
]))
}
(Type::SSHORT, 4) => {
let mut r = self.r(bo);
Some(List(vec![
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
]))
}
(Type::LONG, 2) => {
let mut r = self.r(bo);
Some(List(vec![
Unsigned(r.read_u32()?.into()),
Unsigned(r.read_u32()?.into()),
]))
}
(Type::SLONG, 2) => {
let mut r = self.r(bo);
Some(List(vec![
Signed(r.read_i32()?.into()),
Signed(r.read_i32()?.into()),
]))
}
(Type::RATIONAL, 1) => {
let mut r = self.r(bo);
let numerator = r.read_u32()?.into();
let denominator = r.read_u32()?.into();
Some(Rational(numerator, denominator))
}
(Type::SRATIONAL, 1) => {
let mut r = self.r(bo);
let numerator = r.read_i32()?.into();
let denominator = r.read_i32()?.into();
Some(SRational(numerator, denominator))
}
_ => None
}
} else {
None
};
if let Some(v) = bigtiff_value {
Ok(v)
} else {
match (self.type_, self.count) {
// TODO check if this could give wrong results
// at a different endianess of file/computer.
(Type::BYTE, 1) => Ok(Unsigned(u64::from(self.offset[0]))),
(Type::BYTE, 2) => offset_to_bytes(2, self),
(Type::BYTE, 3) => offset_to_bytes(3, self),
(Type::BYTE, 4) => offset_to_bytes(4, self),
(Type::BYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(u64::from(decoder.read_byte()?)))
}),
(Type::SBYTE, 1) => Ok(Signed(i64::from(self.offset[0] as i8))),
(Type::SBYTE, 2) => offset_to_sbytes(2, self),
(Type::SBYTE, 3) => offset_to_sbytes(3, self),
(Type::SBYTE, 4) => offset_to_sbytes(4, self),
(Type::SBYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(i64::from(decoder.read_byte()? as i8)))
}),
(Type::SHORT, 1) => Ok(Unsigned(u64::from(self.r(bo).read_u16()?))),
(Type::SSHORT, 1) => Ok(Signed(i64::from(self.r(bo).read_i16()?))),
(Type::SHORT, 2) => {
let mut r = self.r(bo);
Ok(List(vec![
Unsigned(u64::from(r.read_u16()?)),
Unsigned(u64::from(r.read_u16()?)),
]))
}
(Type::SSHORT, 2) => {
let mut r = self.r(bo);
Ok(List(vec![
Signed(i64::from(r.read_i16()?)),
Signed(i64::from(r.read_i16()?)),
]))
}
(Type::SHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(u64::from(decoder.read_short()?)))
}),
(Type::SSHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(i64::from(decoder.read_sshort()?)))
}),
(Type::LONG, 1) => Ok(Unsigned(self.r(bo).read_u32()?.into())),
(Type::SLONG, 1) => Ok(Signed(self.r(bo).read_i32()?.into())),
(Type::LONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Unsigned(decoder.read_long()?.into()))
}),
(Type::SLONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Signed(decoder.read_slong()?.into()))
}),
(Type::RATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(Rational(decoder.read_long()?.into(), decoder.read_long()?.into()))
}),
(Type::SRATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
Ok(SRational(decoder.read_slong()?.into(), decoder.read_slong()?.into()))
}),
(Type::ASCII, n) => {
println!("ASCIII COUNT {}", n);
let n = usize::try_from(n)?;
if n > limits.decoding_buffer_size {
return Err(TiffError::LimitsExceeded);
}
let offset = if decoder.bigtiff {
self.r(bo).read_u64()?
} else {
self.r(bo).read_u32()?.into()
};
decoder.goto_offset(offset)?;
let string = decoder.read_string(n)?;
Ok(Ascii(string))
}
_ => Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedDataType,
)),
}
_ => Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedDataType,
)),
}
}
#[inline]
fn decode_offset<R, F>(&self, value_count: u32, bo: ByteOrder, limits: &super::Limits, decoder: &mut super::Decoder<R>, decode_fn: F) -> TiffResult<Value>
fn decode_offset<R, F>(&self, value_count: u64, bo: ByteOrder, limits: &super::Limits, decoder: &mut super::Decoder<R>, decode_fn: F) -> TiffResult<Value>
where
R: Read + Seek,
F: Fn(&mut super::Decoder<R>) -> TiffResult<Value>,
@@ -220,7 +282,12 @@ impl Entry {
}
let mut v = Vec::with_capacity(value_count);
decoder.goto_offset(self.r(bo).read_u32()?)?;
let offset = if decoder.bigtiff {
self.r(bo).read_u64()?
} else {
self.r(bo).read_u32()?.into()
};
decoder.goto_offset(offset)?;
for _ in 0..value_count {
v.push(decode_fn(decoder)?)
}
@@ -234,7 +301,7 @@ fn offset_to_bytes(n: usize, entry: &Entry) -> TiffResult<Value> {
Ok(List(
entry.offset[0..n]
.iter()
.map(|&e| Unsigned(u32::from(e)))
.map(|&e| Unsigned(u64::from(e)))
.collect()
))
}
@@ -245,7 +312,7 @@ fn offset_to_sbytes(n: usize, entry: &Entry) -> TiffResult<Value> {
Ok(List(
entry.offset[0..n]
.iter()
.map(|&e| Signed(i32::from(e as i8)))
.map(|&e| Signed(i64::from(e as i8)))
.collect()
))
}