Repository: image-rs/image-tiff
Pull request #83 (2020-07-22 23:39:47)

Big tiff decoding support
I need to add some tests with bigtiff files but it didn't break the current tests.
I replaced all the internal u32 types by u64 (offset...). 
I didn't change the type of the width and the height but in big tiff their tag can contain u64 values (even if i don't think we can have an image with a u64 as width).
We could keep Rational and SRational with u32 values i think (i never use this kind of value).


Patch:
diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs
index 444597e..79c9e72 100644
--- a/src/decoder/ifd.rs
+++ b/src/decoder/ifd.rs
@@ -1,7 +1,7 @@
 //! Function for reading TIFF tags
 
 use std::collections::HashMap;
-use std::convert::TryFrom;
+use std::convert::{TryInto, TryFrom};
 use std::io::{self, Read, Seek};
 use std::mem;
 
@@ -9,17 +9,21 @@ use super::stream::{ByteOrder, EndianReader, SmartReader};
 use tags::{Tag, Type};
 use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
 
-use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
+use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational, RationalBig, UnsignedBig, SignedBig, SRationalBig};
 
 
 #[allow(unused_qualifications)]
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Value {
     Signed(i32),
+    SignedBig(i64),
     Unsigned(u32),
+    UnsignedBig(u64),
     List(Vec<Value>),
     Rational(u32, u32),
+    RationalBig(u64, u64),
     SRational(i32, i32),
+    SRationalBig(i64, i64),
     Ascii(String),
     #[doc(hidden)] // Do not match against this.
     __NonExhaustive,
@@ -29,6 +33,7 @@ impl Value {
     pub fn into_u32(self) -> TiffResult<u32> {
         match self {
             Unsigned(val) => Ok(val),
+            UnsignedBig(val) => Ok(u32::try_from(val)?),
             val => Err(TiffError::FormatError(
                 TiffFormatError::UnsignedIntegerExpected(val),
             )),
@@ -38,6 +43,27 @@ impl Value {
     pub fn into_i32(self) -> TiffResult<i32> {
         match self {
             Signed(val) => Ok(val),
+            SignedBig(val) => Ok(i32::try_from(val)?),
+            val => Err(TiffError::FormatError(
+                TiffFormatError::SignedIntegerExpected(val),
+            )),
+        }
+    }
+
+    pub fn into_u64(self) -> TiffResult<u64> {
+        match self {
+            Unsigned(val) => Ok(val.into()),
+            UnsignedBig(val) => Ok(val),
+            val => Err(TiffError::FormatError(
+                TiffFormatError::UnsignedIntegerExpected(val),
+            )),
+        }
+    }
+
+    pub fn into_i64(self) -> TiffResult<i64> {
+        match self {
+            Signed(val) => Ok(val.into()),
+            SignedBig(val) => Ok(val),
             val => Err(TiffError::FormatError(
                 TiffFormatError::SignedIntegerExpected(val),
             )),
@@ -54,7 +80,9 @@ impl Value {
                 Ok(new_vec)
             }
             Unsigned(val) => Ok(vec![val]),
+            UnsignedBig(val) => Ok(vec![u32::try_from(val)?]),
             Rational(numerator, denominator) => Ok(vec![numerator, denominator]),
+            RationalBig(numerator, denominator) => Ok(vec![u32::try_from(numerator)?, u32::try_from(denominator)?]),
             Ascii(val) => Ok(val.chars().map(u32::from).collect()),
             val => Err(TiffError::FormatError(
                 TiffFormatError::UnsignedIntegerExpected(val),
@@ -72,25 +100,80 @@ impl Value {
                             new_vec.push(numerator);
                             new_vec.push(denominator);
                         }
-                        _ => new_vec.push(v.into_i32()?)
+                        SRationalBig(numerator, denominator) => {
+                            new_vec.push(i32::try_from(numerator)?);
+                            new_vec.push(i32::try_from(denominator)?);
+                        }
+                        _ => new_vec.push(v.into_i32()?),
                     }
                 }
                 Ok(new_vec)
             }
             Signed(val) => Ok(vec![val]),
+            SignedBig(val) => Ok(vec![i32::try_from(val)?]),
             SRational(numerator, denominator) => Ok(vec![numerator, denominator]),
+            SRationalBig(numerator, denominator) => Ok(vec![i32::try_from(numerator)?, i32::try_from(denominator)?]),
             val => Err(TiffError::FormatError(
                 TiffFormatError::SignedIntegerExpected(val),
             )),
         }
     }
-}
 
+    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_u64()?)
+                }
+                Ok(new_vec)
+            }
+            Unsigned(val) => Ok(vec![val.into()]),
+            UnsignedBig(val) => Ok(vec![val]),
+            Rational(numerator, denominator) => Ok(vec![numerator.into(), denominator.into()]),
+            RationalBig(numerator, denominator) => Ok(vec![numerator, denominator]),
+            Ascii(val) => Ok(val.chars().map(u32::from).map(u64::from).collect()),
+            val => Err(TiffError::FormatError(
+                TiffFormatError::UnsignedIntegerExpected(val),
+            )),
+        }
+    }
+
+    pub fn into_i64_vec(self) -> TiffResult<Vec<i64>> {
+        match self {
+            List(vec) => {
+                let mut new_vec = Vec::with_capacity(vec.len());
+                for v in vec {
+                    match v {
+                        SRational(numerator, denominator) => {
+                            new_vec.push(numerator.into());
+                            new_vec.push(denominator.into());
+                        }
+                        SRationalBig(numerator, denominator) => {
+                            new_vec.push(numerator);
+                            new_vec.push(denominator);
+                        }
+                        _ => new_vec.push(v.into_i64()?),
+                    }
+                }
+                Ok(new_vec)
+            }
+            Signed(val) => Ok(vec![val.into()]),
+            SignedBig(val) => Ok(vec![val]),
+            SRational(numerator, denominator) => Ok(vec![numerator.into(), denominator.into()]),
+            SRationalBig(numerator, denominator) => Ok(vec![numerator, denominator]),
+            val => Err(TiffError::FormatError(
+                TiffFormatError::SignedIntegerExpected(val),
+            )),
+        }
+    }
+}
+    
 #[derive(Clone)]
 pub struct Entry {
     type_: Type,
-    count: u32,
-    offset: [u8; 4],
+    count: u64,
+    offset: [u8; 8],
 }
 
 impl ::std::fmt::Debug for Entry {
@@ -104,6 +187,12 @@ impl ::std::fmt::Debug for Entry {
 
 impl Entry {
     pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry {
+        let mut offset = offset.to_vec();
+        offset.append(&mut vec![0; 4]);
+        Entry::new_u64(type_, count.into(), offset[..].try_into().unwrap())
+    }
+
+    pub fn new_u64(type_: Type, count: u64, offset: [u8; 8]) -> Entry {
         Entry {
             type_,
             count,
@@ -122,102 +211,169 @@ 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))
+        let bigtiff_value = if decoder.bigtiff {
+            match (self.type_, self.count) {
+                (Type::BYTE, 5) => Some(offset_to_bytes(5, self)?),
+                (Type::BYTE, 6) => Some(offset_to_bytes(6, self)?),
+                (Type::BYTE, 7) => Some(offset_to_bytes(7, self)?),
+                (Type::BYTE, 8) => Some(offset_to_bytes(8, self)?),
+                (Type::SBYTE, 5) => Some(offset_to_sbytes(5, self)?),
+                (Type::SBYTE, 6) => Some(offset_to_sbytes(6, self)?),
+                (Type::SBYTE, 7) => Some(offset_to_sbytes(7, self)?),
+                (Type::SBYTE, 8) => Some(offset_to_sbytes(8, self)?),
+                (Type::SHORT, 3) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Unsigned(u32::from(r.read_u16()?)),
+                        Unsigned(u32::from(r.read_u16()?)),
+                        Unsigned(u32::from(r.read_u16()?)),
+                    ]))
+                }
+                (Type::SSHORT, 3) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Signed(i32::from(r.read_i16()?)),
+                        Signed(i32::from(r.read_i16()?)),
+                        Signed(i32::from(r.read_i16()?)),
+                    ]))
+                }
+                (Type::SHORT, 4) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Unsigned(u32::from(r.read_u16()?)),
+                        Unsigned(u32::from(r.read_u16()?)),
+                        Unsigned(u32::from(r.read_u16()?)),
+                        Unsigned(u32::from(r.read_u16()?)),
+                    ]))
+                }
+                (Type::SSHORT, 4) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Signed(i32::from(r.read_i16()?)),
+                        Signed(i32::from(r.read_i16()?)),
+                        Signed(i32::from(r.read_i16()?)),
+                        Signed(i32::from(r.read_i16()?)),
+                    ]))
+                }
+                (Type::LONG, 2) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Unsigned(r.read_u32()?),
+                        Unsigned(r.read_u32()?),
+                    ]))
+                }
+                (Type::SLONG, 2) => {
+                    let mut r = self.r(bo);
+                    Some(List(vec![
+                        Signed(r.read_i32()?),
+                        Signed(r.read_i32()?),
+                    ]))
+                }
+                (Type::RATIONAL, 1) => {
+                    let mut r = self.r(bo);
+                    let numerator = r.read_u32()?;
+                    let denominator = r.read_u32()?;
+                    Some(Rational(numerator, denominator))
+                }
+                (Type::SRATIONAL, 1) => {
+                    let mut r = self.r(bo);
+                    let numerator = r.read_i32()?;
+                    let denominator = r.read_i32()?;
+                    Some(SRational(numerator, denominator))
+                }
+                _ => None
             }
-            (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);
+        } 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(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(UnsignedBig(u64::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(SignedBig(i64::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()?)),
+                    ]))
                 }
-                if n <= 4 {
-                    let mut buf = vec![0; n];
-                    self.r(bo).read_exact(&mut buf )?;
-                    let v = String::from_utf8(buf)?;
-                    let v = v.trim_matches(char::from(0));
-                    Ok(Ascii(v.into()))
-                } else {
-                    decoder.goto_offset(self.r(bo).read_u32()?)?;
-                    let string = decoder.read_string(n)?;
-                    Ok(Ascii(string))
+                (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(UnsignedBig(u64::from(decoder.read_short()?)))
+                }),
+                (Type::SSHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
+                    Ok(SignedBig(i64::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, 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);
+                    }
+                    
+                    if (n <= 4 && !decoder.bigtiff) || (n <= 8 && decoder.bigtiff) {
+                        let mut buf = vec![0; n];
+                        self.r(bo).read_exact(&mut buf )?;
+                        let v = String::from_utf8(buf)?;
+                        let v = v.trim_matches(char::from(0));
+                        Ok(Ascii(v.into()))
+                    } else {
+                        if decoder.bigtiff {
+                            decoder.goto_offset_u64(self.r(bo).read_u64()?)?
+                        } else {
+                            decoder.goto_offset(self.r(bo).read_u32()?)?
+                        }
+                        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>,
@@ -228,7 +384,11 @@ impl Entry {
         }
 
         let mut v = Vec::with_capacity(value_count);
-        decoder.goto_offset(self.r(bo).read_u32()?)?;
+        if decoder.bigtiff {
+            decoder.goto_offset_u64(self.r(bo).read_u64()?)?
+        } else {
+            decoder.goto_offset(self.r(bo).read_u32()?)?
+        }
         for _ in 0..value_count {
             v.push(decode_fn(decoder)?)
         }
diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs
index 4175352..43a45f8 100644
--- a/src/decoder/mod.rs
+++ b/src/decoder/mod.rs
@@ -116,8 +116,8 @@ impl<'a> DecodingBuffer<'a> {
 #[derive(Debug)]
 struct StripDecodeState {
     strip_index: usize,
-    strip_offsets: Vec<u32>,
-    strip_bytes: Vec<u32>,
+    strip_offsets: Vec<u64>,
+    strip_bytes: Vec<u64>,
 }
 
 /// Decoding limits
@@ -157,8 +157,9 @@ where
 {
     reader: SmartReader<R>,
     byte_order: ByteOrder,
+    bigtiff: bool,
     limits: Limits,
-    next_ifd: Option<u32>,
+    next_ifd: Option<u64>,
     ifd: Option<Directory>,
     width: u32,
     height: u32,
@@ -248,6 +249,7 @@ impl<R: Read + Seek> Decoder<R> {
         Decoder {
             reader: SmartReader::wrap(r, ByteOrder::LittleEndian),
             byte_order: ByteOrder::LittleEndian,
+            bigtiff: false,
             limits: Default::default(),
             next_ifd: None,
             ifd: None,
@@ -330,12 +332,28 @@ impl<R: Read + Seek> Decoder<R> {
                 ))
             }
         }
-        if self.read_short()? != 42 {
-            return Err(TiffError::FormatError(
+        match self.read_short()? {
+            42 => self.bigtiff = false,
+            43 => {
+                self.bigtiff = true;
+                // Read bytesize of offsets (in bigtiff it's alway 8 but provide a way to move to 16 some day)
+                if self.read_short()? != 8 {
+                    return Err(TiffError::FormatError(
+                        TiffFormatError::TiffSignatureNotFound,
+                    ))
+                }
+                // This constant should always be 0
+                if self.read_short()? != 0 {
+                    return Err(TiffError::FormatError(
+                        TiffFormatError::TiffSignatureNotFound,
+                    ))
+                }
+            },
+            _ => return Err(TiffError::FormatError(
                 TiffFormatError::TiffSignatureInvalid,
-            ));
+            ))
         }
-        self.next_ifd = match self.read_long()? {
+        self.next_ifd = match self.read_ifd_offset()? {
             0 => None,
             n => Some(n),
         };
@@ -389,6 +407,15 @@ impl<R: Read + Seek> Decoder<R> {
         self.byte_order
     }
 
+    #[inline]
+    pub fn read_ifd_offset(&mut self) -> Result<u64, io::Error> {
+        if self.bigtiff {
+            self.read_long8()
+        } else {
+            self.read_long().map(u64::from)
+        }
+    }
+
     /// Reads a TIFF byte value
     #[inline]
     pub fn read_byte(&mut self) -> Result<u8, io::Error> {
@@ -421,6 +448,12 @@ impl<R: Read + Seek> Decoder<R> {
         self.reader.read_i32()
     }
 
+    #[inline]
+    pub fn read_long8(&mut self) -> Result<u64, io::Error> {
+        self.reader.read_u64()
+    }
+
+
     /// Reads a string
     #[inline]
     pub fn read_string(&mut self, length: usize) -> TiffResult<String> {
@@ -435,17 +468,33 @@ impl<R: Read + Seek> Decoder<R> {
 
     /// Reads a TIFF IFA offset/value field
     #[inline]
-    pub fn read_offset(&mut self) -> Result<[u8; 4], io::Error> {
+    pub fn read_offset(&mut self) -> TiffResult<[u8; 4]> {
+        if self.bigtiff {
+            return Err(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered))
+        }
         let mut val = [0; 4];
         self.reader.read_exact(&mut val)?;
         Ok(val)
     }
 
+    /// Reads a TIFF IFA offset/value field
+    #[inline]
+    pub fn read_offset_u64(&mut self) -> Result<[u8; 8], io::Error> {
+        let mut val = [0; 8];
+        self.reader.read_exact(&mut val)?;
+        Ok(val)
+    }
+
     /// Moves the cursor to the specified offset
     #[inline]
     pub fn goto_offset(&mut self, offset: u32) -> io::Result<()> {
+        self.goto_offset_u64(offset.into())
+    }
+
+    #[inline]
+    pub fn goto_offset_u64(&mut self, offset: u64) -> io::Result<()> {
         self.reader
-            .seek(io::SeekFrom::Start(u64::from(offset)))
+            .seek(io::SeekFrom::Start(offset))
             .map(|_| ())
     }
 
@@ -467,13 +516,22 @@ impl<R: Read + Seek> Decoder<R> {
                 return Ok(None);
             }
         };
-        Ok(Some((
-            tag,
+        let entry = if self.bigtiff {
+            ifd::Entry::new_u64(
+                type_,
+                self.read_long8()?,
+                self.read_offset_u64()?
+            )
+        } else {
             ifd::Entry::new(
                 type_,
-                self.read_long()?,   // count
-                self.read_offset()?, // offset
-            ),
+                self.read_long()?, 
+                self.read_offset()?
+            )
+        };
+        Ok(Some((
+            tag,
+            entry,
         )))
     }
 
@@ -486,16 +544,17 @@ impl<R: Read + Seek> Decoder<R> {
                     TiffFormatError::ImageFileDirectoryNotFound,
                 ))
             }
-            Some(offset) => self.goto_offset(offset)?,
+            Some(offset) => self.goto_offset_u64(offset)?,
         }
-        for _ in 0..self.read_short()? {
+        let num_tags = if self.bigtiff { self.read_long8()? } else { self.read_short()?.into() };
+        for _ in 0..num_tags {
             let (tag, entry) = match self.read_entry()? {
                 Some(val) => val,
                 None => continue, // Unknown data type in tag, skip
             };
             dir.insert(tag, entry);
         }
-        self.next_ifd = match self.read_long()? {
+        self.next_ifd = match self.read_ifd_offset()? {
             0 => None,
             n => Some(n),
         };
@@ -516,9 +575,9 @@ impl<R: Read + Seek> Decoder<R> {
     }
 
     /// Tries to retrieve a tag and convert it to the desired unsigned type.
-    pub fn find_tag_unsigned<T: TryFrom<u32>>(&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)?
-            .map(|v| v.into_u32()).transpose()?
+            .map(|v| v.into_u64()).transpose()?
             .map(|value| T::try_from(value)
                 .map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()))
             .transpose()
@@ -526,9 +585,9 @@ impl<R: Read + Seek> Decoder<R> {
 
     /// Tries to retrieve a vector of all a tag's values and convert them to
     /// the desired unsigned type.
-    pub fn find_tag_unsigned_vec<T: TryFrom<u32>>(&mut self, tag: Tag) -> TiffResult<Option<Vec<T>>> {
+    pub fn find_tag_unsigned_vec<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<Vec<T>>> {
         self.find_tag(tag)?
-            .map(|v| v.into_u32_vec()).transpose()?
+            .map(|v| v.into_u64_vec()).transpose()?
             .map(|v| v.into_iter()
                 .map(|u| T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()))
                 .collect())
@@ -537,7 +596,7 @@ impl<R: Read + Seek> Decoder<R> {
 
     /// Tries to retrieve a tag and convert it to the desired unsigned type.
     /// Returns an error if the tag is not present.
-    pub fn get_tag_unsigned<T: TryFrom<u32>>(&mut self, tag: Tag) -> TiffResult<T> {
+    pub fn get_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<T> {
         self.find_tag_unsigned(tag)?
             .ok_or_else(|| TiffFormatError::RequiredTagNotFound(tag).into())
     }
@@ -557,24 +616,30 @@ impl<R: Read + Seek> Decoder<R> {
     pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> {
         self.get_tag(tag)?.into_u32()
     }
+    pub fn get_tag_u64(&mut self, tag: Tag) -> TiffResult<u64> {
+        self.get_tag(tag)?.into_u64()
+    }
 
     /// Tries to retrieve a tag and convert it to the desired type.
     pub fn get_tag_u32_vec(&mut self, tag: Tag) -> TiffResult<Vec<u32>> {
         self.get_tag(tag)?.into_u32_vec()
     }
+    pub fn get_tag_u64_vec(&mut self, tag: Tag) -> TiffResult<Vec<u64>> {
+        self.get_tag(tag)?.into_u64_vec()
+    }
 
     /// Decompresses the strip into the supplied buffer.
     /// Returns the number of bytes read.
     fn expand_strip<'a>(
         &mut self,
         buffer: DecodingBuffer<'a>,
-        offset: u32,
-        length: u32,
+        offset: u64,
+        length: u64,
         max_uncompressed_length: usize,
     ) -> TiffResult<usize> {
         let color_type = self.colortype()?;
-        self.goto_offset(offset)?;
-        let (bytes, mut reader): (usize, Box<EndianReader>) = match self.compression_method {
+        self.goto_offset_u64(offset)?;
+        let (bytes, mut reader): (usize, Box<dyn EndianReader>) = match self.compression_method {
             CompressionMethod::None => {
                 let order = self.reader.byte_order;
                 (
@@ -700,8 +765,8 @@ impl<R: Read + Seek> Decoder<R> {
 
     fn initialize_strip_decoder(&mut self) -> TiffResult<()> {
         if self.strip_decoder.is_none() {
-            let strip_offsets = self.get_tag_u32_vec(Tag::StripOffsets)?;
-            let strip_bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?;
+            let strip_offsets = self.get_tag_u64_vec(Tag::StripOffsets)?;
+            let strip_bytes = self.get_tag_u64_vec(Tag::StripByteCounts)?;
 
             self.strip_decoder = Some(StripDecodeState {
                 strip_index: 0,


Test patch:
diff --git a/tests/decode_bigtiff_images.rs b/tests/decode_bigtiff_images.rs
new file mode 100644
index 0000000..9113f42
--- /dev/null
+++ b/tests/decode_bigtiff_images.rs
@@ -0,0 +1,46 @@
+extern crate tiff;
+
+use tiff::decoder::Decoder;
+use tiff::tags::Tag;
+use tiff::ColorType;
+
+use std::fs::File;
+use std::path::PathBuf;
+
+const TEST_IMAGE_DIR: &str = "./tests/images/bigtiff";
+
+#[test]
+fn test_big_tiff() {
+    let filenames = ["BigTIFF.tif", "BigTIFFMotorola.tif", "BigTIFFLong.tif"];
+    for filename in filenames.iter() {
+        let path = PathBuf::from(TEST_IMAGE_DIR).join(filename);
+        let img_file = File::open(path).expect("Cannot find test image!");
+        let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
+        assert_eq!(
+            decoder.dimensions().expect("Cannot get dimensions"),
+            (64, 64)
+        );
+        assert_eq!(
+            decoder.colortype().expect("Cannot get colortype"),
+            ColorType::RGB(8)
+        );
+        assert_eq!(
+            decoder
+                .get_tag_u64(Tag::StripOffsets)
+                .expect("Cannot get StripOffsets"),
+            16
+        );
+        assert_eq!(
+            decoder
+                .get_tag_u64(Tag::RowsPerStrip)
+                .expect("Cannot get RowsPerStrip"),
+            64
+        );
+        assert_eq!(
+            decoder
+                .get_tag_u64(Tag::StripByteCounts)
+                .expect("Cannot get StripByteCounts"),
+            12288
+        )
+    }
+}