Imported Upstream version 4.1.0 into tizen
[platform/upstream/tiff.git] / libtiff / tif_dirread.c
index e80a3b1..6f90941 100755 (executable)
@@ -29,9 +29,6 @@
  */
 
 /* Suggested pending improvements:
- * - add a field 'ignore' to the TIFFDirEntry structure, to flag status,
- *   eliminating current use of the IGNORE value, and therefore eliminating
- *   current irrational behaviour on tags with tag id code 0
  * - add a field 'field_info' to the TIFFDirEntry structure, and set that with
  *   the pointer to the appropriate TIFFField structure early on in
  *   TIFFReadDirectory, so as to eliminate current possibly repetitive lookup.
 #include <float.h>
 #include <stdlib.h>
 
-#define IGNORE 0          /* tag placeholder used below */
 #define FAILED_FII    ((uint32) -1)
 
+/*
+ * Largest 64-bit signed integer value.
+ */
+#define TIFF_INT64_MAX ((int64)(TIFF_UINT64_MAX >> 1))
+
 #ifdef HAVE_IEEEFP
 # define TIFFCvtIEEEFloatToNative(tif, n, fp)
 # define TIFFCvtIEEEDoubleToNative(tif, n, dp)
@@ -164,6 +165,7 @@ static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
 static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp);
 static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
 static void ChopUpSingleUncompressedStrip(TIFF*);
+static void TryChopUpUncompressedBigTiff(TIFF*);
 static uint64 TIFFReadUInt64(const uint8 *value);
 static int _TIFFGetMaxColorChannels(uint16 photometric);
 
@@ -205,6 +207,7 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* di
        switch (direntry->tdir_type)
        {
                case TIFF_BYTE:
+               case TIFF_UNDEFINED:    /* Support to read TIFF_UNDEFINED with field_readcount==1 */
                        TIFFReadDirEntryCheckedByte(tif,direntry,value);
                        return(TIFFReadDirEntryErrOk);
                case TIFF_SBYTE:
@@ -3287,11 +3290,6 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value)
                return(TIFFReadDirEntryErrOk);
 }
 
-/*
- * Largest 32-bit unsigned integer value.
- */
-#define TIFF_UINT32_MAX 0xFFFFFFFFU
-
 static enum TIFFReadDirEntryErr
 TIFFReadDirEntryCheckRangeLongLong8(uint64 value)
 {
@@ -3310,8 +3308,6 @@ TIFFReadDirEntryCheckRangeLongSlong8(int64 value)
                return(TIFFReadDirEntryErrOk);
 }
 
-#undef TIFF_UINT32_MAX
-
 static enum TIFFReadDirEntryErr
 TIFFReadDirEntryCheckRangeSlongLong(uint32 value)
 {
@@ -3377,11 +3373,6 @@ TIFFReadDirEntryCheckRangeLong8Slong8(int64 value)
                return(TIFFReadDirEntryErrOk);
 }
 
-/*
- * Largest 64-bit signed integer value.
- */
-#define TIFF_INT64_MAX ((int64)(((uint64) ~0) >> 1))
-
 static enum TIFFReadDirEntryErr
 TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value)
 {
@@ -3391,8 +3382,6 @@ TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value)
                return(TIFFReadDirEntryErrOk);
 }
 
-#undef TIFF_INT64_MAX
-
 static enum TIFFReadDirEntryErr
 TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest)
 {
@@ -3405,13 +3394,13 @@ TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest)
        } else {
                size_t ma,mb;
                ma=(size_t)offset;
+                if( (uint64)ma!=offset ||
+                    ma > (~(size_t)0) - (size_t)size )
+                {
+                    return TIFFReadDirEntryErrIo;
+                }
                mb=ma+size;
-               if (((uint64)ma!=offset)
-                   || (mb < ma)
-                   || (mb - ma != (size_t) size)
-                   || (mb < (size_t)size)
-                   || (mb > (size_t)tif->tif_size)
-                   )
+               if (mb > (size_t)tif->tif_size)
                        return(TIFFReadDirEntryErrIo);
                _TIFFmemcpy(dest,tif->tif_base+ma,size);
        }
@@ -3534,6 +3523,49 @@ static int _TIFFGetMaxColorChannels( uint16 photometric )
     }
 }
 
+static int ByteCountLooksBad(TIFF* tif)
+{
+    /*
+        * Assume we have wrong StripByteCount value (in case
+        * of single strip) in following cases:
+        *   - it is equal to zero along with StripOffset;
+        *   - it is larger than file itself (in case of uncompressed
+        *     image);
+        *   - it is smaller than the size of the bytes per row
+        *     multiplied on the number of rows.  The last case should
+        *     not be checked in the case of writing new image,
+        *     because we may do not know the exact strip size
+        *     until the whole image will be written and directory
+        *     dumped out.
+        */
+    uint64 bytecount = TIFFGetStrileByteCount(tif, 0);
+    uint64 offset = TIFFGetStrileOffset(tif, 0);
+    uint64 filesize;
+
+    if( offset == 0 )
+        return 0;
+    if (bytecount == 0)
+        return 1;
+    if ( tif->tif_dir.td_compression != COMPRESSION_NONE )
+        return 0;
+    filesize = TIFFGetFileSize(tif);
+    if( offset <= filesize && bytecount > filesize - offset )
+        return 1;
+    if( tif->tif_mode == O_RDONLY )
+    {
+        uint64 scanlinesize = TIFFScanlineSize64(tif);
+        if( tif->tif_dir.td_imagelength > 0 &&
+            scanlinesize > TIFF_UINT64_MAX / tif->tif_dir.td_imagelength )
+        {
+            return 1;
+        }
+        if( bytecount < scanlinesize * tif->tif_dir.td_imagelength)
+            return 1;
+    }
+    return 0;
+}
+
+
 /*
  * Read the next TIFF directory from a file and convert it to the internal
  * format. We read directories sequentially.
@@ -3580,14 +3612,17 @@ TIFFReadDirectory(TIFF* tif)
                        uint16 nb;
                        for (na=ma+1, nb=mb+1; nb<dircount; na++, nb++)
                        {
-                               if (ma->tdir_tag==na->tdir_tag)
-                                       na->tdir_tag=IGNORE;
+                               if (ma->tdir_tag == na->tdir_tag) {
+                                       na->tdir_ignore = TRUE;
+                               }
                        }
                }
        }
         
        tif->tif_flags &= ~TIFF_BEENWRITING;    /* reset before new dir */
        tif->tif_flags &= ~TIFF_BUF4WRITE;      /* reset before new dir */
+       tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS;
+
        /* free any old stuff and reinit */
        TIFFFreeDirectory(tif);
        TIFFDefaultDirectory(tif);
@@ -3620,7 +3655,7 @@ TIFFReadDirectory(TIFF* tif)
        {
                if (!TIFFFetchNormalTag(tif,dp,0))
                        goto bad;
-               dp->tdir_tag=IGNORE;
+               dp->tdir_ignore = TRUE;
        }
        dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION);
        if (dp)
@@ -3643,7 +3678,7 @@ TIFFReadDirectory(TIFF* tif)
                }
                if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value))
                        goto bad;
-               dp->tdir_tag=IGNORE;
+               dp->tdir_ignore = TRUE;
        }
        else
        {
@@ -3655,7 +3690,7 @@ TIFFReadDirectory(TIFF* tif)
         */
        for (di=0, dp=dir; di<dircount; di++, dp++)
        {
-               if (dp->tdir_tag!=IGNORE)
+               if (!dp->tdir_ignore)
                {
                        TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
                        if (fii == FAILED_FII)
@@ -3663,8 +3698,8 @@ TIFFReadDirectory(TIFF* tif)
                                TIFFWarningExt(tif->tif_clientdata, module,
                                    "Unknown field with tag %d (0x%x) encountered",
                                    dp->tdir_tag,dp->tdir_tag);
-                                /* the following knowingly leaks the 
-                                   anonymous field structure */
+                               /* the following knowingly leaks the 
+                                  anonymous field structure */
                                if (!_TIFFMergeFields(tif,
                                        _TIFFCreateAnonField(tif,
                                                dp->tdir_tag,
@@ -3675,18 +3710,18 @@ TIFFReadDirectory(TIFF* tif)
                                            "Registering anonymous field with tag %d (0x%x) failed",
                                            dp->tdir_tag,
                                            dp->tdir_tag);
-                                       dp->tdir_tag=IGNORE;
+                                       dp->tdir_ignore = TRUE;
                                } else {
                                        TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
                                        assert(fii != FAILED_FII);
                                }
                        }
                }
-               if (dp->tdir_tag!=IGNORE)
+               if (!dp->tdir_ignore)
                {
                        fip=tif->tif_fields[fii];
                        if (fip->field_bit==FIELD_IGNORE)
-                               dp->tdir_tag=IGNORE;
+                               dp->tdir_ignore = TRUE;
                        else
                        {
                                switch (dp->tdir_tag)
@@ -3708,12 +3743,12 @@ TIFFReadDirectory(TIFF* tif)
                                        case TIFFTAG_EXTRASAMPLES:
                                                if (!TIFFFetchNormalTag(tif,dp,0))
                                                        goto bad;
-                                               dp->tdir_tag=IGNORE;
+                                               dp->tdir_ignore = TRUE;
+                                               break;
+                                       default:
+                                               if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) )
+                                                       dp->tdir_ignore = TRUE;
                                                break;
-                                        default:
-                                            if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) )
-                                                dp->tdir_tag=IGNORE;
-                                            break;
                                }
                        }
                }
@@ -3729,8 +3764,8 @@ TIFFReadDirectory(TIFF* tif)
        if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&&
            (tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE))
        {
-        if (!_TIFFFillStriles(tif))
-            goto bad;
+               if (!_TIFFFillStriles(tif))
+                   goto bad;
                dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS);
                if ((dp!=0)&&(dp->tdir_count==1))
                {
@@ -3802,190 +3837,200 @@ TIFFReadDirectory(TIFF* tif)
         */
        for (di=0, dp=dir; di<dircount; di++, dp++)
        {
-               switch (dp->tdir_tag)
-               {
-                       case IGNORE:
-                               break;
-                       case TIFFTAG_MINSAMPLEVALUE:
-                       case TIFFTAG_MAXSAMPLEVALUE:
-                       case TIFFTAG_BITSPERSAMPLE:
-                       case TIFFTAG_DATATYPE:
-                       case TIFFTAG_SAMPLEFORMAT:
-                               /*
-                                * The MinSampleValue, MaxSampleValue, BitsPerSample
-                                * DataType and SampleFormat tags are supposed to be
-                                * written as one value/sample, but some vendors
-                                * incorrectly write one value only -- so we accept
-                                * that as well (yuck). Other vendors write correct
-                                * value for NumberOfSamples, but incorrect one for
-                                * BitsPerSample and friends, and we will read this
-                                * too.
-                                */
-                               {
-                                       uint16 value;
-                                       enum TIFFReadDirEntryErr err;
-                                       err=TIFFReadDirEntryShort(tif,dp,&value);
-                                       if (err==TIFFReadDirEntryErrCount)
-                                               err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
-                                       if (err!=TIFFReadDirEntryErrOk)
-                                       {
-                                               fip = TIFFFieldWithTag(tif,dp->tdir_tag);
-                                               TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
-                                               goto bad;
-                                       }
-                                       if (!TIFFSetField(tif,dp->tdir_tag,value))
-                                               goto bad;
-                    if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE )
-                        bitspersample_read = TRUE;
-                               }
-                               break;
-                       case TIFFTAG_SMINSAMPLEVALUE:
-                       case TIFFTAG_SMAXSAMPLEVALUE:
-                               {
-
-                                       double *data = NULL;
-                                       enum TIFFReadDirEntryErr err;
-                                       uint32 saved_flags;
-                                       int m;
-                                       if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
-                                               err = TIFFReadDirEntryErrCount;
-                                       else
-                                               err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
-                                       if (err!=TIFFReadDirEntryErrOk)
-                                       {
-                                               fip = TIFFFieldWithTag(tif,dp->tdir_tag);
-                                               TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
-                                               goto bad;
-                                       }
-                                       saved_flags = tif->tif_flags;
-                                       tif->tif_flags |= TIFF_PERSAMPLE;
-                                       m = TIFFSetField(tif,dp->tdir_tag,data);
-                                       tif->tif_flags = saved_flags;
-                                       _TIFFfree(data);
-                                       if (!m)
-                                               goto bad;
-                               }
-                               break;
-                       case TIFFTAG_STRIPOFFSETS:
-                       case TIFFTAG_TILEOFFSETS:
-#if defined(DEFER_STRILE_LOAD)
-                                _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
-                                             dp, sizeof(TIFFDirEntry) );
-#else                          
-                                if( tif->tif_dir.td_stripoffset != NULL )
-                                {
-                                    TIFFErrorExt(tif->tif_clientdata, module,
-                                        "tif->tif_dir.td_stripoffset is "
-                                        "already allocated. Likely duplicated "
-                                        "StripOffsets/TileOffsets tag");
-                                    goto bad;
-                                }
-                               if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset))  
-                                       goto bad;
-#endif                                
-                               break;
-                       case TIFFTAG_STRIPBYTECOUNTS:
-                       case TIFFTAG_TILEBYTECOUNTS:
-#if defined(DEFER_STRILE_LOAD)
-                                _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
-                                             dp, sizeof(TIFFDirEntry) );
-#else                          
-                                if( tif->tif_dir.td_stripbytecount != NULL )
-                                {
-                                    TIFFErrorExt(tif->tif_clientdata, module,
-                                        "tif->tif_dir.td_stripbytecount is "
-                                        "already allocated. Likely duplicated "
-                                        "StripByteCounts/TileByteCounts tag");
-                                    goto bad;
-                                }
-                                if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount))  
-                                       goto bad;
-#endif                                
-                               break;
-                       case TIFFTAG_COLORMAP:
-                       case TIFFTAG_TRANSFERFUNCTION:
-                               {
-                                       enum TIFFReadDirEntryErr err;
-                                       uint32 countpersample;
-                                       uint32 countrequired;
-                                       uint32 incrementpersample;
-                                       uint16* value=NULL;
-                    /* It would be dangerous to instantiate those tag values */
-                    /* since if td_bitspersample has not yet been read (due to */
-                    /* unordered tags), it could be read afterwards with a */
-                    /* values greater than the default one (1), which may cause */
-                    /* crashes in user code */
-                    if( !bitspersample_read )
-                    {
-                        fip = TIFFFieldWithTag(tif,dp->tdir_tag);
-                        TIFFWarningExt(tif->tif_clientdata,module,
-                                       "Ignoring %s since BitsPerSample tag not found",
-                                       fip ? fip->field_name : "unknown tagname");
-                        continue;
-                    }
-                                       /* ColorMap or TransferFunction for high bit */
-                                       /* depths do not make much sense and could be */
-                                       /* used as a denial of service vector */
-                                       if (tif->tif_dir.td_bitspersample > 24)
-                                       {
-                                           fip = TIFFFieldWithTag(tif,dp->tdir_tag);
-                                           TIFFWarningExt(tif->tif_clientdata,module,
-                                               "Ignoring %s because BitsPerSample=%d>24",
-                                               fip ? fip->field_name : "unknown tagname",
-                                               tif->tif_dir.td_bitspersample);
-                                           continue;
-                                       }
-                                       countpersample=(1U<<tif->tif_dir.td_bitspersample);
-                                       if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
+               if (!dp->tdir_ignore) {
+                       switch (dp->tdir_tag) 
+                       {
+                               case TIFFTAG_MINSAMPLEVALUE:
+                               case TIFFTAG_MAXSAMPLEVALUE:
+                               case TIFFTAG_BITSPERSAMPLE:
+                               case TIFFTAG_DATATYPE:
+                               case TIFFTAG_SAMPLEFORMAT:
+                                       /*
+                                        * The MinSampleValue, MaxSampleValue, BitsPerSample
+                                        * DataType and SampleFormat tags are supposed to be
+                                        * written as one value/sample, but some vendors
+                                        * incorrectly write one value only -- so we accept
+                                        * that as well (yuck). Other vendors write correct
+                                        * value for NumberOfSamples, but incorrect one for
+                                        * BitsPerSample and friends, and we will read this
+                                        * too.
+                                        */
                                        {
-                                               countrequired=countpersample;
-                                               incrementpersample=0;
+                                               uint16 value;
+                                               enum TIFFReadDirEntryErr err;
+                                               err=TIFFReadDirEntryShort(tif,dp,&value);
+                                               if (err==TIFFReadDirEntryErrCount)
+                                                       err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
+                                               if (err!=TIFFReadDirEntryErrOk)
+                                               {
+                                                       fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                                                       TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+                                                       goto bad;
+                                               }
+                                               if (!TIFFSetField(tif,dp->tdir_tag,value))
+                                                       goto bad;
+                                               if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE )
+                                                   bitspersample_read = TRUE;
                                        }
-                                       else
+                                       break;
+                               case TIFFTAG_SMINSAMPLEVALUE:
+                               case TIFFTAG_SMAXSAMPLEVALUE:
                                        {
-                                               countrequired=3*countpersample;
-                                               incrementpersample=countpersample;
+
+                                               double *data = NULL;
+                                               enum TIFFReadDirEntryErr err;
+                                               uint32 saved_flags;
+                                               int m;
+                                               if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
+                                                       err = TIFFReadDirEntryErrCount;
+                                               else
+                                                       err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
+                                               if (err!=TIFFReadDirEntryErrOk)
+                                               {
+                                                       fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                                                       TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+                                                       goto bad;
+                                               }
+                                               saved_flags = tif->tif_flags;
+                                               tif->tif_flags |= TIFF_PERSAMPLE;
+                                               m = TIFFSetField(tif,dp->tdir_tag,data);
+                                               tif->tif_flags = saved_flags;
+                                               _TIFFfree(data);
+                                               if (!m)
+                                                       goto bad;
                                        }
-                                       if (dp->tdir_count!=(uint64)countrequired)
-                                               err=TIFFReadDirEntryErrCount;
-                                       else
-                                               err=TIFFReadDirEntryShortArray(tif,dp,&value);
-                                       if (err!=TIFFReadDirEntryErrOk)
-                    {
-                                               fip = TIFFFieldWithTag(tif,dp->tdir_tag);
-                                               TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
-                    }
-                                       else
+                                       break;
+                               case TIFFTAG_STRIPOFFSETS:
+                               case TIFFTAG_TILEOFFSETS:
+                                       _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
+                                          dp, sizeof(TIFFDirEntry) );
+                                       break;
+                               case TIFFTAG_STRIPBYTECOUNTS:
+                               case TIFFTAG_TILEBYTECOUNTS:
+                                       _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
+                                          dp, sizeof(TIFFDirEntry) );
+                                       break;
+                               case TIFFTAG_COLORMAP:
+                               case TIFFTAG_TRANSFERFUNCTION:
                                        {
-                                               TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
-                                               _TIFFfree(value);
+                                               enum TIFFReadDirEntryErr err;
+                                               uint32 countpersample;
+                                               uint32 countrequired;
+                                               uint32 incrementpersample;
+                                               uint16* value=NULL;
+                                               /* It would be dangerous to instantiate those tag values */
+                                               /* since if td_bitspersample has not yet been read (due to */
+                                               /* unordered tags), it could be read afterwards with a */
+                                               /* values greater than the default one (1), which may cause */
+                                               /* crashes in user code */
+                                               if( !bitspersample_read )
+                                               {
+                                                       fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                                                       TIFFWarningExt(tif->tif_clientdata,module,
+                                                               "Ignoring %s since BitsPerSample tag not found",
+                                                               fip ? fip->field_name : "unknown tagname");
+                                                       continue;
+                                               }
+                                               /* ColorMap or TransferFunction for high bit */
+                                               /* depths do not make much sense and could be */
+                                               /* used as a denial of service vector */
+                                               if (tif->tif_dir.td_bitspersample > 24)
+                                               {
+                                                       fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                                                       TIFFWarningExt(tif->tif_clientdata,module,
+                                                               "Ignoring %s because BitsPerSample=%d>24",
+                                                               fip ? fip->field_name : "unknown tagname",
+                                                               tif->tif_dir.td_bitspersample);
+                                                       continue;
+                                               }
+                                               countpersample=(1U<<tif->tif_dir.td_bitspersample);
+                                               if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
+                                               {
+                                                       countrequired=countpersample;
+                                                       incrementpersample=0;
+                                               }
+                                               else
+                                               {
+                                                       countrequired=3*countpersample;
+                                                       incrementpersample=countpersample;
+                                               }
+                                               if (dp->tdir_count!=(uint64)countrequired)
+                                                       err=TIFFReadDirEntryErrCount;
+                                               else
+                                                       err=TIFFReadDirEntryShortArray(tif,dp,&value);
+                                               if (err!=TIFFReadDirEntryErrOk)
+                                               {
+                                                       fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                                                       TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
+                                               }
+                                               else
+                                               {
+                                                       TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
+                                                       _TIFFfree(value);
+                                               }
                                        }
-                               }
-                               break;
+                                       break;
 /* BEGIN REV 4.0 COMPATIBILITY */
-                       case TIFFTAG_OSUBFILETYPE:
-                               {
-                                       uint16 valueo;
-                                       uint32 value;
-                                       if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk)
+                               case TIFFTAG_OSUBFILETYPE:
                                        {
-                                               switch (valueo)
+                                               uint16 valueo;
+                                               uint32 value;
+                                               if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk)
                                                {
-                                                       case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break;
-                                                       case OFILETYPE_PAGE: value=FILETYPE_PAGE; break;
-                                                       default: value=0; break;
+                                                       switch (valueo)
+                                                       {
+                                                               case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break;
+                                                               case OFILETYPE_PAGE: value=FILETYPE_PAGE; break;
+                                                               default: value=0; break;
+                                                       }
+                                                       if (value!=0)
+                                                               TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value);
                                                }
-                                               if (value!=0)
-                                                       TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value);
                                        }
-                               }
-                               break;
+                                       break;
 /* END REV 4.0 COMPATIBILITY */
-                       default:
-                               (void) TIFFFetchNormalTag(tif, dp, TRUE);
-                               break;
-               }
-       }
+                               default:
+                                       (void) TIFFFetchNormalTag(tif, dp, TRUE);
+                                       break;
+                               }
+                       } /* -- if (!dp->tdir_ignore) */
+               } /* -- for-loop -- */
+
+        if( tif->tif_mode == O_RDWR &&
+            tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
+            tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
+            tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
+            tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
+            tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
+            tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
+            tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
+            tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
+        {
+            /* Directory typically created with TIFFDeferStrileArrayWriting() */
+            TIFFSetupStrips(tif);
+        }
+        else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
+        {
+            if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
+            {
+                if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
+                                         tif->tif_dir.td_nstrips,
+                                         &tif->tif_dir.td_stripoffset_p))
+                {
+                    goto bad;
+                }
+            }
+            if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
+            {
+                if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
+                                         tif->tif_dir.td_nstrips,
+                                         &tif->tif_dir.td_stripbytecount_p))
+                {
+                    goto bad;
+                }
+            }
+        }
+
        /*
         * OJPEG hack:
         * - If a) compression is OJPEG, and b) photometric tag is missing,
@@ -4128,33 +4173,10 @@ TIFFReadDirectory(TIFF* tif)
                                "\"StripByteCounts\" field, calculating from imagelength");
                        if (EstimateStripByteCounts(tif, dir, dircount) < 0)
                            goto bad;
-               /*
-                * Assume we have wrong StripByteCount value (in case
-                * of single strip) in following cases:
-                *   - it is equal to zero along with StripOffset;
-                *   - it is larger than file itself (in case of uncompressed
-                *     image);
-                *   - it is smaller than the size of the bytes per row
-                *     multiplied on the number of rows.  The last case should
-                *     not be checked in the case of writing new image,
-                *     because we may do not know the exact strip size
-                *     until the whole image will be written and directory
-                *     dumped out.
-                */
-               #define BYTECOUNTLOOKSBAD \
-                   ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \
-                     (tif->tif_dir.td_compression == COMPRESSION_NONE && \
-                      (tif->tif_dir.td_stripoffset[0] <= TIFFGetFileSize(tif) && \
-                       tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0])) || \
-                     (tif->tif_mode == O_RDONLY && \
-                      tif->tif_dir.td_compression == COMPRESSION_NONE && \
-                      tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) )
 
                } else if (tif->tif_dir.td_nstrips == 1
                            && !(tif->tif_flags&TIFF_ISTILED)
-                           && _TIFFFillStriles(tif)
-                          && tif->tif_dir.td_stripoffset[0] != 0
-                          && BYTECOUNTLOOKSBAD) {
+                          && ByteCountLooksBad(tif)) {
                        /*
                         * XXX: Plexus (and others) sometimes give a value of
                         * zero for a tag when they don't know what the
@@ -4166,13 +4188,13 @@ TIFFReadDirectory(TIFF* tif)
                        if(EstimateStripByteCounts(tif, dir, dircount) < 0)
                            goto bad;
 
-#if !defined(DEFER_STRILE_LOAD)
-               } else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG
+               } else if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD)
+                          && tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG
                           && tif->tif_dir.td_nstrips > 2
                           && tif->tif_dir.td_compression == COMPRESSION_NONE
-                          && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1]
-                          && tif->tif_dir.td_stripbytecount[0] != 0
-                          && tif->tif_dir.td_stripbytecount[1] != 0 ) {
+                          && TIFFGetStrileByteCount(tif, 0) != TIFFGetStrileByteCount(tif, 1)
+                          && TIFFGetStrileByteCount(tif, 0) != 0
+                          && TIFFGetStrileByteCount(tif, 1) != 0 ) {
                        /*
                         * XXX: Some vendors fill StripByteCount array with
                         * absolutely wrong values (it can be equal to
@@ -4187,7 +4209,6 @@ TIFFReadDirectory(TIFF* tif)
                            "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength");
                        if (EstimateStripByteCounts(tif, dir, dircount) < 0)
                            goto bad;
-#endif /* !defined(DEFER_STRILE_LOAD) */                        
                }
        }
        if (dir)
@@ -4202,26 +4223,27 @@ TIFFReadDirectory(TIFF* tif)
                else
                        tif->tif_dir.td_maxsamplevalue = (uint16)((1L<<tif->tif_dir.td_bitspersample)-1);
        }
+
+#ifdef STRIPBYTECOUNTSORTED_UNUSED
        /*
         * XXX: We can optimize checking for the strip bounds using the sorted
         * bytecounts array. See also comments for TIFFAppendToStrip()
         * function in tif_write.c.
         */
-#if !defined(DEFER_STRILE_LOAD)        
-       if (tif->tif_dir.td_nstrips > 1) {
+       if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) && tif->tif_dir.td_nstrips > 1) {
                uint32 strip;
 
                tif->tif_dir.td_stripbytecountsorted = 1;
                for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
-                       if (tif->tif_dir.td_stripoffset[strip - 1] >
-                           tif->tif_dir.td_stripoffset[strip]) {
+                       if (TIFFGetStrileOffset(tif, strip - 1) >
+                           TIFFGetStrileOffset(tif, strip)) {
                                tif->tif_dir.td_stripbytecountsorted = 0;
                                break;
                        }
                }
        }
-#endif /* !defined(DEFER_STRILE_LOAD) */
-        
+#endif
+
        /*
         * An opportunity for compression mode dependent tag fixup
         */
@@ -4240,11 +4262,20 @@ TIFFReadDirectory(TIFF* tif)
            (tif->tif_dir.td_nstrips==1)&&
            (tif->tif_dir.td_compression==COMPRESSION_NONE)&&  
            ((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP))
-    {
-        if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount )
-            return 0;
-               ChopUpSingleUncompressedStrip(tif);
-    }
+        {
+            ChopUpSingleUncompressedStrip(tif);
+        }
+
+        /* There are also uncompressed striped files with strips larger than */
+        /* 2 GB, which make them unfriendly with a lot of code. If possible, */
+        /* try to expose smaller "virtual" strips. */
+        if( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG &&
+            tif->tif_dir.td_compression == COMPRESSION_NONE &&
+            (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP &&
+            TIFFStripSize64(tif) > 0x7FFFFFFFUL )
+        {
+            TryChopUpUncompressedBigTiff(tif);
+        }
 
         /*
          * Clear the dirty directory flag. 
@@ -4396,17 +4427,17 @@ TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
                                TIFFWarningExt(tif->tif_clientdata, module,
                                    "Registering anonymous field with tag %d (0x%x) failed",
                                    dp->tdir_tag, dp->tdir_tag);
-                               dp->tdir_tag=IGNORE;
+                               dp->tdir_ignore = TRUE;
                        } else {
                                TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
                                assert( fii != FAILED_FII );
                        }
                }
-               if (dp->tdir_tag!=IGNORE)
+               if (!dp->tdir_ignore)
                {
                        fip=tif->tif_fields[fii];
                        if (fip->field_bit==FIELD_IGNORE)
-                               dp->tdir_tag=IGNORE;
+                               dp->tdir_ignore = TRUE;
                        else
                        {
                                /* check data type */
@@ -4426,7 +4457,7 @@ TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
                                        TIFFWarningExt(tif->tif_clientdata, module,
                                            "Wrong data type %d for \"%s\"; tag ignored",
                                            dp->tdir_type,fip->field_name);
-                                       dp->tdir_tag=IGNORE;
+                                       dp->tdir_ignore = TRUE;
                                }
                                else
                                {
@@ -4440,21 +4471,21 @@ TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
                                                else
                                                        expected=(uint32)fip->field_readcount;
                                                if (!CheckDirCount(tif,dp,expected))
-                                                       dp->tdir_tag=IGNORE;
+                                                       dp->tdir_ignore = TRUE;
                                        }
                                }
                        }
-                       switch (dp->tdir_tag)
-                       {
-                               case IGNORE:
-                                       break;
-                               case EXIFTAG_SUBJECTDISTANCE:
-                                       (void) TIFFFetchSubjectDistance(tif,dp);
-                                       break;
-                               default:
-                                       (void) TIFFFetchNormalTag(tif, dp, TRUE);
-                                       break;
-                       }
+                       if (!dp->tdir_ignore) {
+                               switch (dp->tdir_tag) 
+                               {
+                                       case EXIFTAG_SUBJECTDISTANCE:
+                                               (void)TIFFFetchSubjectDistance(tif, dp);
+                                               break;
+                                       default:
+                                               (void)TIFFFetchNormalTag(tif, dp, TRUE);
+                                               break;
+                               }
+                       } /*-- if (!dp->tdir_ignore) */
                }
        }
        if (dir)
@@ -4487,12 +4518,12 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
         if( !_TIFFFillStrilesInternal( tif, 0 ) )
             return -1;
 
-       if (td->td_stripbytecount)
-               _TIFFfree(td->td_stripbytecount);
-       td->td_stripbytecount = (uint64*)
+       if (td->td_stripbytecount_p)
+               _TIFFfree(td->td_stripbytecount_p);
+       td->td_stripbytecount_p = (uint64*)
            _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64),
                "for \"StripByteCounts\" array");
-        if( td->td_stripbytecount == NULL )
+        if( td->td_stripbytecount_p == NULL )
             return -1;
 
        if (td->td_compression != COMPRESSION_NONE) {
@@ -4516,6 +4547,8 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
                                    dp->tdir_type);
                                return -1;
                        }
+                       if( dp->tdir_count > TIFF_UINT64_MAX / typewidth )
+                            return -1;
                        datasize=(uint64)typewidth*dp->tdir_count;
                        if (!(tif->tif_flags&TIFF_BIGTIFF))
                        {
@@ -4527,6 +4560,8 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
                                if (datasize<=8)
                                        datasize=0;
                        }
+                       if( space > TIFF_UINT64_MAX - datasize )
+                            return -1;
                        space+=datasize;
                }
                if( filesize < space )
@@ -4537,7 +4572,7 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
                if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
                        space /= td->td_samplesperpixel;
                for (strip = 0; strip < td->td_nstrips; strip++)
-                       td->td_stripbytecount[strip] = space;
+                       td->td_stripbytecount_p[strip] = space;
                /*
                 * This gross hack handles the case were the offset to
                 * the last strip is past the place where we think the strip
@@ -4546,18 +4581,30 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
                 * of data in the strip and trim this number back accordingly.
                 */
                strip--;
-               if (td->td_stripoffset[strip]+td->td_stripbytecount[strip] > filesize)
-                       td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip];
+                if (td->td_stripoffset_p[strip] > TIFF_UINT64_MAX - td->td_stripbytecount_p[strip])
+                    return -1;
+               if (td->td_stripoffset_p[strip]+td->td_stripbytecount_p[strip] > filesize) {
+                    if( td->td_stripoffset_p[strip] >= filesize ) {
+                        /* Not sure what we should in that case... */
+                        td->td_stripbytecount_p[strip] = 0;
+                    } else {
+                        td->td_stripbytecount_p[strip] = filesize - td->td_stripoffset_p[strip];
+                    }
+                }
        } else if (isTiled(tif)) {
                uint64 bytespertile = TIFFTileSize64(tif);
 
                for (strip = 0; strip < td->td_nstrips; strip++)
-                   td->td_stripbytecount[strip] = bytespertile;
+                   td->td_stripbytecount_p[strip] = bytespertile;
        } else {
                uint64 rowbytes = TIFFScanlineSize64(tif);
                uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
                for (strip = 0; strip < td->td_nstrips; strip++)
-                       td->td_stripbytecount[strip] = rowbytes * rowsperstrip;
+                {
+                    if( rowbytes > 0 && rowsperstrip > TIFF_UINT64_MAX / rowbytes )
+                        return -1;
+                    td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip;
+                }
        }
        TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
        if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
@@ -4751,12 +4798,13 @@ TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
                }
        } else {
                tmsize_t m;
-               tmsize_t off = (tmsize_t) tif->tif_diroff;
-               if ((uint64)off!=tif->tif_diroff)
+               tmsize_t off;
+               if (tif->tif_diroff > (uint64)TIFF_INT64_MAX)
                {
                        TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
                        return(0);
                }
+               off = (tmsize_t) tif->tif_diroff;
 
                /*
                 * Check for integer overflow when validating the dir_off,
@@ -4874,6 +4922,7 @@ TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
        mb=dir;
        for (n=0; n<dircount16; n++)
        {
+               mb->tdir_ignore = FALSE;
                if (tif->tif_flags&TIFF_SWAB)
                        TIFFSwabShort((uint16*)ma);
                mb->tdir_tag=*(uint16*)ma;
@@ -4888,6 +4937,7 @@ TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
                                TIFFSwabLong((uint32*)ma);
                        mb->tdir_count=(uint64)(*(uint32*)ma);
                        ma+=sizeof(uint32);
+                       mb->tdir_offset.toff_long8=0;
                        *(uint32*)(&mb->tdir_offset)=*(uint32*)ma;
                        ma+=sizeof(uint32);
                }
@@ -5681,7 +5731,7 @@ TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
                        TIFFSwabArrayOfLong(m.i,2);
                if (m.i[0]==0)
                        n=0.0;
-               else if (m.i[0]==0xFFFFFFFF)
+               else if (m.i[0]==0xFFFFFFFF || m.i[1]==0)
                        /*
                         * XXX: Numerator 0xFFFFFFFF means that we have infinite
                         * distance. Indicate that with a negative floating point
@@ -5699,6 +5749,75 @@ TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
        }
 }
 
+static void allocChoppedUpStripArrays(TIFF* tif, uint32 nstrips,
+                                      uint64 stripbytes, uint32 rowsperstrip)
+{
+    TIFFDirectory *td = &tif->tif_dir;
+    uint64 bytecount;
+    uint64 offset;
+    uint64 last_offset;
+    uint64 last_bytecount;
+    uint32 i;
+    uint64 *newcounts;
+    uint64 *newoffsets;
+
+    offset = TIFFGetStrileOffset(tif, 0);
+    last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1);
+    last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1);
+    if( last_offset > TIFF_UINT64_MAX - last_bytecount ||
+        last_offset + last_bytecount < offset )
+    {
+        return;
+    }
+    bytecount = last_offset + last_bytecount - offset;
+
+    newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
+                            "for chopped \"StripByteCounts\" array");
+    newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
+                            "for chopped \"StripOffsets\" array");
+    if (newcounts == NULL || newoffsets == NULL) {
+        /*
+        * Unable to allocate new strip information, give up and use
+        * the original one strip information.
+        */
+        if (newcounts != NULL)
+            _TIFFfree(newcounts);
+        if (newoffsets != NULL)
+            _TIFFfree(newoffsets);
+        return;
+    }
+
+    /*
+     * Fill the strip information arrays with new bytecounts and offsets
+     * that reflect the broken-up format.
+     */
+    for (i = 0; i < nstrips; i++)
+    {
+        if (stripbytes > bytecount)
+            stripbytes = bytecount;
+        newcounts[i] = stripbytes;
+        newoffsets[i] = stripbytes ? offset : 0;
+        offset += stripbytes;
+        bytecount -= stripbytes;
+    }
+
+    /*
+     * Replace old single strip info with multi-strip info.
+     */
+    td->td_stripsperimage = td->td_nstrips = nstrips;
+    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+    _TIFFfree(td->td_stripbytecount_p);
+    _TIFFfree(td->td_stripoffset_p);
+    td->td_stripbytecount_p = newcounts;
+    td->td_stripoffset_p = newoffsets;
+#ifdef STRIPBYTECOUNTSORTED_UNUSED
+    td->td_stripbytecountsorted = 1;
+#endif
+    tif->tif_flags |= TIFF_CHOPPEDUPARRAYS;
+}
+
+
 /*
  * Replace a single strip (tile) of uncompressed data by multiple strips
  * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for
@@ -5714,19 +5833,16 @@ ChopUpSingleUncompressedStrip(TIFF* tif)
        uint32 rowblock;
        uint64 rowblockbytes;
        uint64 stripbytes;
-       uint32 strip;
        uint32 nstrips;
        uint32 rowsperstrip;
-       uint64* newcounts;
-       uint64* newoffsets;
 
-       bytecount = td->td_stripbytecount[0];
+       bytecount = TIFFGetStrileByteCount(tif, 0);
         /* On a newly created file, just re-opened to be filled, we */
         /* don't want strip chop to trigger as it is going to cause issues */
         /* later ( StripOffsets and StripByteCounts improperly filled) . */
         if( bytecount == 0 && tif->tif_mode != O_RDONLY )
             return;
-       offset = td->td_stripoffset[0];
+       offset = TIFFGetStrileByteCount(tif, 0);
        assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
        if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
            (!isUpSampled(tif)))
@@ -5769,98 +5885,503 @@ ChopUpSingleUncompressedStrip(TIFF* tif)
             return;
         }
 
-       newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
-                               "for chopped \"StripByteCounts\" array");
-       newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
-                               "for chopped \"StripOffsets\" array");
-       if (newcounts == NULL || newoffsets == NULL) {
-               /*
-                * Unable to allocate new strip information, give up and use
-                * the original one strip information.
-                */
-               if (newcounts != NULL)
-                       _TIFFfree(newcounts);
-               if (newoffsets != NULL)
-                       _TIFFfree(newoffsets);
-               return;
-       }
-       /*
-        * Fill the strip information arrays with new bytecounts and offsets
-        * that reflect the broken-up format.
-        */
-       for (strip = 0; strip < nstrips; strip++) {
-               if (stripbytes > bytecount)
-                       stripbytes = bytecount;
-               newcounts[strip] = stripbytes;
-               newoffsets[strip] = stripbytes ? offset : 0;
-               offset += stripbytes;
-               bytecount -= stripbytes;
-       }
-       /*
-        * Replace old single strip info with multi-strip info.
-        */
-       td->td_stripsperimage = td->td_nstrips = nstrips;
-       TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
-
-       _TIFFfree(td->td_stripbytecount);
-       _TIFFfree(td->td_stripoffset);
-       td->td_stripbytecount = newcounts;
-       td->td_stripoffset = newoffsets;
-       td->td_stripbytecountsorted = 1;
+        allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip);
 }
 
-int _TIFFFillStriles( TIFF *tif )
+
+/*
+ * Replace a file with contiguous strips > 2 GB of uncompressed data by
+ * multiple smaller strips. This is useful for
+ * dealing with large images or for dealing with machines with a limited
+ * amount memory.
+ */
+static void TryChopUpUncompressedBigTiff( TIFF* tif )
 {
-    return _TIFFFillStrilesInternal( tif, 1 );
+    TIFFDirectory *td = &tif->tif_dir;
+    uint32 rowblock;
+    uint64 rowblockbytes;
+    uint32 i;
+    uint64 stripsize;
+    uint32 rowblocksperstrip;
+    uint32 rowsperstrip;
+    uint64 stripbytes;
+    uint32 nstrips;
+
+    stripsize = TIFFStripSize64(tif);
+
+    assert( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG );
+    assert( tif->tif_dir.td_compression == COMPRESSION_NONE );
+    assert( (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP );
+    assert( stripsize > 0x7FFFFFFFUL );
+
+    /* On a newly created file, just re-opened to be filled, we */
+    /* don't want strip chop to trigger as it is going to cause issues */
+    /* later ( StripOffsets and StripByteCounts improperly filled) . */
+    if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY )
+        return;
+
+    if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
+        (!isUpSampled(tif)))
+        rowblock = td->td_ycbcrsubsampling[1];
+    else
+        rowblock = 1;
+    rowblockbytes = TIFFVStripSize64(tif, rowblock);
+    if( rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL )
+    {
+        /* In case of file with gigantic width */
+        return;
+    }
+
+    /* Check that the strips are contiguous and of the expected size */
+    for( i = 0; i < td->td_nstrips; i++ )
+    {
+        if( i == td->td_nstrips - 1 )
+        {
+            if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64(
+                    tif, td->td_imagelength - i * td->td_rowsperstrip ) )
+            {
+                return;
+            }
+        }
+        else
+        {
+            if( TIFFGetStrileByteCount(tif, i) != stripsize )
+            {
+                return;
+            }
+            if( i > 0 && TIFFGetStrileOffset(tif, i) !=
+                    TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) )
+            {
+                return;
+            }
+        }
+    }
+
+    /* Aim for 512 MB strips (that will still be manageable by 32 bit builds */
+    rowblocksperstrip = (uint32) (512 * 1024 * 1024 / rowblockbytes);
+    if( rowblocksperstrip == 0 )
+        rowblocksperstrip = 1;
+    rowsperstrip = rowblocksperstrip * rowblock;
+    stripbytes = rowblocksperstrip * rowblockbytes;
+    assert( stripbytes <= 0x7FFFFFFFUL );
+
+    nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
+    if( nstrips == 0 )
+        return;
+
+    /* If we are going to allocate a lot of memory, make sure that the */
+    /* file is as big as needed */
+    if( tif->tif_mode == O_RDONLY &&
+        nstrips > 1000000 )
+    {
+        uint64 last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1);
+        uint64 filesize = TIFFGetFileSize(tif);
+        uint64 last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1);
+        if( last_offset > filesize ||
+            last_bytecount > filesize - last_offset )
+        {
+            return;
+        }
+    }
+
+    allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip);
 }
 
-static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount )
+
+TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
+static uint64 _TIFFUnsanitizedAddUInt64AndInt(uint64 a, int b)
 {
-#if defined(DEFER_STRILE_LOAD)
-        register TIFFDirectory *td = &tif->tif_dir;
-        int return_value = 1;
+    return a + b;
+}
 
-        if( td->td_stripoffset != NULL )
-                return 1;
+/* Read the value of [Strip|Tile]Offset or [Strip|Tile]ByteCount around
+ * strip/tile of number strile. Also fetch the neighbouring values using a
+ * 4096 byte page size.
+ */
+static
+int _TIFFPartialReadStripArray( TIFF* tif, TIFFDirEntry* dirent,
+                                int strile, uint64* panVals )
+{
+    static const char module[] = "_TIFFPartialReadStripArray";
+#define IO_CACHE_PAGE_SIZE 4096
+
+    size_t sizeofval;
+    const int bSwab = (tif->tif_flags & TIFF_SWAB) != 0;
+    int sizeofvalint;
+    uint64 nBaseOffset;
+    uint64 nOffset;
+    uint64 nOffsetStartPage;
+    uint64 nOffsetEndPage;
+    tmsize_t nToRead;
+    tmsize_t nRead;
+    uint64 nLastStripOffset;
+    int iStartBefore;
+    int i;
+    const uint32 arraySize = tif->tif_dir.td_stripoffsetbyteallocsize;
+    unsigned char buffer[2 * IO_CACHE_PAGE_SIZE];
+
+    assert( dirent->tdir_count > 4 );
+
+    if( dirent->tdir_type == TIFF_SHORT )
+    {
+        sizeofval = sizeof(uint16);
+    }
+    else if( dirent->tdir_type == TIFF_LONG )
+    {
+        sizeofval = sizeof(uint32);
+    }
+    else if( dirent->tdir_type == TIFF_LONG8 )
+    {
+        sizeofval = sizeof(uint64);
+    }
+    else
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                 "Invalid type for [Strip|Tile][Offset/ByteCount] tag");
+        panVals[strile] = 0;
+        return 0;
+    }
+    sizeofvalint = (int)(sizeofval);
 
-        if( td->td_stripoffset_entry.tdir_count == 0 )
+    if( tif->tif_flags&TIFF_BIGTIFF )
+    {
+        uint64 offset = dirent->tdir_offset.toff_long8;
+        if( bSwab )
+            TIFFSwabLong8(&offset);
+        nBaseOffset = offset;
+    }
+    else
+    {
+        uint32 offset = dirent->tdir_offset.toff_long;
+        if( bSwab )
+            TIFFSwabLong(&offset);
+        nBaseOffset = offset;
+    }
+    /* To avoid later unsigned integer overflows */
+    if( nBaseOffset > (uint64)TIFF_INT64_MAX )
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                 "Cannot read offset/size for strile %d", strile);
+        panVals[strile] = 0;
+        return 0;
+    }
+    nOffset = nBaseOffset + sizeofval * strile;
+    nOffsetStartPage =
+        (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE;
+    nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE;
+
+    if( nOffset + sizeofval > nOffsetEndPage )
+        nOffsetEndPage += IO_CACHE_PAGE_SIZE;
+#undef IO_CACHE_PAGE_SIZE
+
+    nLastStripOffset = nBaseOffset + arraySize * sizeofval;
+    if( nLastStripOffset < nOffsetEndPage )
+        nOffsetEndPage = nLastStripOffset;
+    if( nOffsetStartPage >= nOffsetEndPage )
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                 "Cannot read offset/size for strile %d", strile);
+        panVals[strile] = 0;
+        return 0;
+    }
+    if (!SeekOK(tif,nOffsetStartPage))
+    {
+        panVals[strile] = 0;
+        return 0;
+    }
+
+    nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage);
+    nRead = TIFFReadFile(tif, buffer, nToRead);
+    if( nRead < nToRead )
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                 "Cannot read offset/size for strile around ~%d", strile);
+        return 0;
+    }
+    iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval);
+    if( strile + iStartBefore < 0 )
+        iStartBefore = -strile;
+    for( i = iStartBefore;
+         (uint32)(strile + i) < arraySize &&
+         _TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage;
+         ++i )
+    {
+        if( sizeofval == sizeof(uint16) )
+        {
+            uint16 val;
+            memcpy(&val,
+                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
+                   sizeof(val));
+            if( bSwab )
+                TIFFSwabShort(&val);
+            panVals[strile + i] = val;
+        }
+        else if( sizeofval == sizeof(uint32) )
+        {
+            uint32 val;
+            memcpy(&val,
+                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
+                   sizeof(val));
+            if( bSwab )
+                TIFFSwabLong(&val);
+            panVals[strile + i] = val;
+        }
+        else
+        {
+            uint64 val;
+            memcpy(&val,
+                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
+                   sizeof(val));
+            if( bSwab )
+                TIFFSwabLong8(&val);
+            panVals[strile + i] = val;
+        }
+    }
+    return 1;
+}
+
+static int _TIFFFetchStrileValue(TIFF* tif,
+                                 uint32 strile,
+                                 TIFFDirEntry* dirent,
+                                 uint64** parray)
+{
+    static const char module[] = "_TIFFFetchStrileValue";
+    TIFFDirectory *td = &tif->tif_dir;
+    if( strile >= dirent->tdir_count )
+    {
+        return 0;
+    }
+    if( strile >= td->td_stripoffsetbyteallocsize )
+    {
+        uint32 nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize;
+        uint32 nStripArrayAllocNew;
+        uint64 nArraySize64;
+        size_t nArraySize;
+        uint64* offsetArray;
+        uint64* bytecountArray;
+
+        if( strile > 1000000 )
+        {
+            uint64 filesize = TIFFGetFileSize(tif);
+            /* Avoid excessive memory allocation attempt */
+            /* For such a big blockid we need at least a TIFF_LONG per strile */
+            /* for the offset array. */
+            if( strile > filesize / sizeof(uint32) )
+            {
+                TIFFErrorExt(tif->tif_clientdata, module, "File too short");
                 return 0;
+            }
+        }
 
-        if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
-                                 td->td_nstrips,&td->td_stripoffset))
+        if( td->td_stripoffsetbyteallocsize == 0 &&
+            td->td_nstrips < 1024 * 1024 )
         {
-                return_value = 0;
+            nStripArrayAllocNew = td->td_nstrips;
+        }
+        else
+        {
+#define TIFF_MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define TIFF_MIN(a,b) (((a)<(b)) ? (a) : (b))
+            nStripArrayAllocNew = TIFF_MAX(strile + 1, 1024U * 512U );
+            if( nStripArrayAllocNew < 0xFFFFFFFFU / 2  )
+                nStripArrayAllocNew *= 2;
+            nStripArrayAllocNew = TIFF_MIN(nStripArrayAllocNew, td->td_nstrips);
+        }
+        assert( strile < nStripArrayAllocNew );
+        nArraySize64 = (uint64)sizeof(uint64) * nStripArrayAllocNew;
+        nArraySize = (size_t)(nArraySize64);
+#if SIZEOF_SIZE_T == 4
+        if( nArraySize != nArraySize64 )
+        {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                        "Cannot allocate strip offset and bytecount arrays");
+            return 0;
         }
+#endif
+        offsetArray = (uint64*)(
+            _TIFFrealloc( td->td_stripoffset_p, nArraySize ) );
+        bytecountArray = (uint64*)(
+            _TIFFrealloc( td->td_stripbytecount_p, nArraySize ) );
+        if( offsetArray )
+            td->td_stripoffset_p = offsetArray;
+        if( bytecountArray )
+            td->td_stripbytecount_p = bytecountArray;
+        if( offsetArray && bytecountArray )
+        {
+            td->td_stripoffsetbyteallocsize = nStripArrayAllocNew;
+            /* Initialize new entries to ~0 / -1 */
+            memset(td->td_stripoffset_p + nStripArrayAllocBefore,
+                0xFF,
+                (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) );
+            memset(td->td_stripbytecount_p + nStripArrayAllocBefore,
+                0xFF,
+                (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) );
+        }
+        else
+        {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                        "Cannot allocate strip offset and bytecount arrays");
+            _TIFFfree(td->td_stripoffset_p);
+            td->td_stripoffset_p = NULL;
+            _TIFFfree(td->td_stripbytecount_p);
+            td->td_stripbytecount_p = NULL;
+            td->td_stripoffsetbyteallocsize = 0;
+        }
+    }
+    if( *parray == NULL || strile >= td->td_stripoffsetbyteallocsize )
+        return 0;
 
-        if (loadStripByteCount &&
-            !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
-                                 td->td_nstrips,&td->td_stripbytecount))
+    if( ~((*parray)[strile]) == 0 )
+    {
+        if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) )
         {
-                return_value = 0;
+            (*parray)[strile] = 0;
+            return 0;
         }
+    }
 
-        _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
-        _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+    return 1;
+}
 
-       if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) {
-               uint32 strip;
+static uint64 _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32 strile,
+                                                   TIFFDirEntry* dirent,
+                                                   uint64** parray,
+                                                   int *pbErr)
+{
+    TIFFDirectory *td = &tif->tif_dir;
+    if( pbErr )
+        *pbErr = 0;
+    if( (tif->tif_flags&TIFF_DEFERSTRILELOAD) && !(tif->tif_flags&TIFF_CHOPPEDUPARRAYS) )
+    {
+        if( !(tif->tif_flags&TIFF_LAZYSTRILELOAD) ||
+            /* If the values may fit in the toff_long/toff_long8 member */
+            /* then use _TIFFFillStriles to simplify _TIFFFetchStrileValue */
+            dirent->tdir_count <= 4 )
+        {
+            if( !_TIFFFillStriles(tif) )
+            {
+                if( pbErr )
+                    *pbErr = 1;
+                /* Do not return, as we want this function to always */
+                /* return the same value if called several times with */
+                /* the same arguments */
+            }
+        }
+        else
+        {
+             if( !_TIFFFetchStrileValue(tif, strile, dirent, parray) )
+             {
+                if( pbErr )
+                    *pbErr = 1;
+                 return 0;
+             }
+        }
+    }
+    if( *parray == NULL || strile >= td->td_nstrips )
+    {
+        if( pbErr )
+            *pbErr = 1;
+        return 0;
+    }
+    return (*parray)[strile];
+}
 
-               tif->tif_dir.td_stripbytecountsorted = 1;
-               for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
-                       if (tif->tif_dir.td_stripoffset[strip - 1] >
-                           tif->tif_dir.td_stripoffset[strip]) {
-                               tif->tif_dir.td_stripbytecountsorted = 0;
-                               break;
-                       }
-               }
-       }
+/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */
+uint64 TIFFGetStrileOffset(TIFF *tif, uint32 strile)
+{
+    return TIFFGetStrileOffsetWithErr(tif, strile, NULL);
+}
+
+/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */
+uint64 TIFFGetStrileOffsetWithErr(TIFF *tif, uint32 strile, int *pbErr)
+{
+    TIFFDirectory *td = &tif->tif_dir;
+    return _TIFFGetStrileOffsetOrByteCountValue(tif, strile,
+                               &(td->td_stripoffset_entry),
+                               &(td->td_stripoffset_p), pbErr);
+}
+
+/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */
+uint64 TIFFGetStrileByteCount(TIFF *tif, uint32 strile)
+{
+    return TIFFGetStrileByteCountWithErr(tif, strile, NULL);
+}
+
+/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */
+uint64 TIFFGetStrileByteCountWithErr(TIFF *tif, uint32 strile, int *pbErr)
+{
+    TIFFDirectory *td = &tif->tif_dir;
+    return _TIFFGetStrileOffsetOrByteCountValue(tif, strile,
+                               &(td->td_stripbytecount_entry),
+                               &(td->td_stripbytecount_p), pbErr);
+}
 
-        return return_value;
-#else /* !defined(DEFER_STRILE_LOAD) */
-        (void) tif;
-        (void) loadStripByteCount;
+
+int _TIFFFillStriles( TIFF *tif )
+{
+    return _TIFFFillStrilesInternal( tif, 1 );
+}
+
+static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount )
+{
+    register TIFFDirectory *td = &tif->tif_dir;
+    int return_value = 1;
+
+    /* Do not do anything if TIFF_DEFERSTRILELOAD is not set */
+    if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) || (tif->tif_flags&TIFF_CHOPPEDUPARRAYS) != 0 )
         return 1;
-#endif 
+
+    if( tif->tif_flags&TIFF_LAZYSTRILELOAD )
+    {
+        /* In case of lazy loading, reload completely the arrays */
+        _TIFFfree(td->td_stripoffset_p);
+        _TIFFfree(td->td_stripbytecount_p);
+        td->td_stripoffset_p = NULL;
+        td->td_stripbytecount_p = NULL;
+        td->td_stripoffsetbyteallocsize = 0;
+        tif->tif_flags &= ~TIFF_LAZYSTRILELOAD;
+    }
+
+    /* If stripoffset array is already loaded, exit with success */
+    if( td->td_stripoffset_p != NULL )
+            return 1;
+
+    /* If tdir_count was cancelled, then we already got there, but in error */
+    if( td->td_stripoffset_entry.tdir_count == 0 )
+            return 0;
+
+    if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
+                                td->td_nstrips,&td->td_stripoffset_p))
+    {
+            return_value = 0;
+    }
+
+    if (loadStripByteCount &&
+        !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
+                                td->td_nstrips,&td->td_stripbytecount_p))
+    {
+            return_value = 0;
+    }
+
+    _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
+    _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+
+#ifdef STRIPBYTECOUNTSORTED_UNUSED
+    if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) {
+            uint32 strip;
+
+            tif->tif_dir.td_stripbytecountsorted = 1;
+            for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
+                    if (tif->tif_dir.td_stripoffset_p[strip - 1] >
+                        tif->tif_dir.td_stripoffset_p[strip]) {
+                            tif->tif_dir.td_stripbytecountsorted = 0;
+                            break;
+                    }
+            }
+    }
+#endif
+
+    return return_value;
 }