diff options
Diffstat (limited to 'libtiff')
-rw-r--r-- | libtiff/tif_dir.c | 13 | ||||
-rw-r--r-- | libtiff/tif_dir.h | 9 | ||||
-rw-r--r-- | libtiff/tif_dirread.c | 591 | ||||
-rw-r--r-- | libtiff/tif_dirwrite.c | 14 | ||||
-rw-r--r-- | libtiff/tif_jpeg.c | 11 | ||||
-rw-r--r-- | libtiff/tif_ojpeg.c | 17 | ||||
-rw-r--r-- | libtiff/tif_open.c | 17 | ||||
-rw-r--r-- | libtiff/tif_print.c | 10 | ||||
-rw-r--r-- | libtiff/tif_read.c | 87 | ||||
-rw-r--r-- | libtiff/tif_strip.c | 3 | ||||
-rw-r--r-- | libtiff/tif_write.c | 54 | ||||
-rw-r--r-- | libtiff/tiffio.h | 5 | ||||
-rw-r--r-- | libtiff/tiffiop.h | 2 |
13 files changed, 575 insertions, 258 deletions
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c index b4ecd44f..4a3fcd55 100644 --- a/libtiff/tif_dir.c +++ b/libtiff/tif_dir.c @@ -1018,12 +1018,12 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) case TIFFTAG_STRIPOFFSETS: case TIFFTAG_TILEOFFSETS: _TIFFFillStriles( tif ); - *va_arg(ap, uint64**) = td->td_stripoffset; + *va_arg(ap, uint64**) = td->td_stripoffset_p; break; case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEBYTECOUNTS: _TIFFFillStriles( tif ); - *va_arg(ap, uint64**) = td->td_stripbytecount; + *va_arg(ap, uint64**) = td->td_stripbytecount_p; break; case TIFFTAG_MATTEING: *va_arg(ap, uint16*) = @@ -1282,8 +1282,9 @@ TIFFFreeDirectory(TIFF* tif) CleanupField(td_transferfunction[0]); CleanupField(td_transferfunction[1]); CleanupField(td_transferfunction[2]); - CleanupField(td_stripoffset); - CleanupField(td_stripbytecount); + CleanupField(td_stripoffset_p); + CleanupField(td_stripbytecount_p); + td->td_stripoffsetbyteallocsize = 0; TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING); TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING); @@ -1296,10 +1297,8 @@ TIFFFreeDirectory(TIFF* tif) td->td_customValueCount = 0; CleanupField(td_customValues); -#if defined(DEFER_STRILE_LOAD) _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); -#endif } #undef CleanupField @@ -1387,7 +1386,9 @@ TIFFDefaultDirectory(TIFF* tif) td->td_tilewidth = 0; td->td_tilelength = 0; td->td_tiledepth = 1; +#ifdef STRIPBYTECOUNTSORTED_UNUSED td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */ +#endif td->td_resolutionunit = RESUNIT_INCH; td->td_sampleformat = SAMPLEFORMAT_UINT; td->td_imagedepth = 1; diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h index b2f5e694..76f3eaf7 100644 --- a/libtiff/tif_dir.h +++ b/libtiff/tif_dir.h @@ -97,13 +97,14 @@ typedef struct { * number of striles */ uint32 td_stripsperimage; uint32 td_nstrips; /* size of offset & bytecount arrays */ - uint64* td_stripoffset; - uint64* td_stripbytecount; + uint64* td_stripoffset_p; /* should be accessed with TIFFGetStrileOffset */ + uint64* td_stripbytecount_p; /* should be accessed with TIFFGetStrileByteCount */ + uint32 td_stripoffsetbyteallocsize; /* number of elements currently allocated for td_stripoffset/td_stripbytecount. Only used if TIFF_LAZYSTRILELOAD is set */ +#ifdef STRIPBYTECOUNTSORTED_UNUSED int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ -#if defined(DEFER_STRILE_LOAD) +#endif TIFFDirEntry td_stripoffset_entry; /* for deferred loading */ TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */ -#endif uint16 td_nsubifd; uint64* td_subifd; /* YCbCr parameters */ diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c index 65675d0f..023c4c9b 100644 --- a/libtiff/tif_dirread.c +++ b/libtiff/tif_dirread.c @@ -3536,6 +3536,41 @@ 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 && + bytecount < TIFFScanlineSize64(tif) * 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. @@ -3870,39 +3905,39 @@ TIFFReadDirectory(TIFF* tif) 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 ) + if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) { - TIFFErrorExt(tif->tif_clientdata, module, - "tif->tif_dir.td_stripoffset is " - "already allocated. Likely duplicated " - "StripOffsets/TileOffsets tag"); - goto bad; + if( tif->tif_dir.td_stripoffset_p != 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_p)) + 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 ) + if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) { - TIFFErrorExt(tif->tif_clientdata, module, - "tif->tif_dir.td_stripbytecount is " - "already allocated. Likely duplicated " - "StripByteCounts/TileByteCounts tag"); - goto bad; + if( tif->tif_dir.td_stripbytecount_p != 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_p)) + 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: @@ -4130,33 +4165,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 @@ -4168,13 +4180,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 @@ -4189,7 +4201,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) @@ -4204,26 +4215,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 */ @@ -4242,11 +4254,9 @@ 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 stripped files with strips larger than */ /* 2 GB, which make them unfriendly with a lot of code. If possible, */ @@ -4256,8 +4266,6 @@ TIFFReadDirectory(TIFF* tif) (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP && TIFFStripSize64(tif) > 0x7FFFFFFFUL ) { - if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount ) - return 0; TryChopUpUncompressedBigTiff(tif); } @@ -4502,12 +4510,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) { @@ -4552,7 +4560,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 @@ -4561,18 +4569,18 @@ 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]+td->td_stripbytecount_p[strip] > filesize) + 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; + td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip; } TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) @@ -5744,9 +5752,9 @@ static void allocChoppedUpStripArrays(TIFF* tif, uint32 nstrips, * Fill the strip information arrays with new bytecounts and offsets * that reflect the broken-up format. */ - offset = td->td_stripoffset[0]; - bytecount = td->td_stripoffset[td->td_nstrips-1] + - td->td_stripbytecount[td->td_nstrips-1] - offset; + offset = TIFFGetStrileOffset(tif, 0); + bytecount = TIFFGetStrileOffset(tif, td->td_nstrips-1) + + TIFFGetStrileByteCount(tif, td->td_nstrips-1) - offset; for (i = 0; i < nstrips; i++) { if (stripbytes > bytecount) @@ -5763,11 +5771,14 @@ static void allocChoppedUpStripArrays(TIFF* tif, uint32 nstrips, 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; + _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_DEFERSTRILELOAD; } @@ -5789,13 +5800,13 @@ ChopUpSingleUncompressedStrip(TIFF* tif) uint32 nstrips; uint32 rowsperstrip; - 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))) @@ -5870,7 +5881,7 @@ static void TryChopUpUncompressedBigTiff( TIFF* tif ) /* 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( td->td_stripbytecount[0] == 0 && tif->tif_mode != O_RDONLY ) + if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY ) return; if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& @@ -5890,7 +5901,7 @@ static void TryChopUpUncompressedBigTiff( TIFF* tif ) { if( i == td->td_nstrips - 1 ) { - if( td->td_stripbytecount[i] < TIFFVStripSize64( + if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64( tif, td->td_imagelength - i * td->td_rowsperstrip ) ) { return; @@ -5898,12 +5909,12 @@ static void TryChopUpUncompressedBigTiff( TIFF* tif ) } else { - if( td->td_stripbytecount[i] != stripsize ) + if( TIFFGetStrileByteCount(tif, i) != stripsize ) { return; } - if( i > 0 && td->td_stripoffset[i] != - td->td_stripoffset[i-1] + td->td_stripbytecount[i - 1] ) + if( i > 0 && TIFFGetStrileOffset(tif, i) != + TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) ) { return; } @@ -5926,9 +5937,9 @@ static void TryChopUpUncompressedBigTiff( TIFF* tif ) /* file is as big as needed */ if( tif->tif_mode == O_RDONLY && nstrips > 1000000 && - (td->td_stripoffset[td->td_nstrips-1] > TIFFGetFileSize(tif) || - td->td_stripoffset[td->td_nstrips-1] + - td->td_stripbytecount[td->td_nstrips-1] > TIFFGetFileSize(tif)) ) + (TIFFGetStrileOffset(tif, td->td_nstrips-1) > TIFFGetFileSize(tif) || + TIFFGetStrileOffset(tif, td->td_nstrips-1) + + TIFFGetStrileByteCount(tif, td->td_nstrips-1) > TIFFGetFileSize(tif)) ) { return; } @@ -5936,60 +5947,384 @@ static void TryChopUpUncompressedBigTiff( TIFF* tif ) allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); } +/* 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/ByteCounnt] tag"); + panVals[strile] = 0; + return 0; + } + sizeofvalint = (int)(sizeofval); + 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; + } + 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; + } -int _TIFFFillStriles( TIFF *tif ) -{ - return _TIFFFillStrilesInternal( tif, 1 ); + 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 && + (uint64)(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 _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ) +static int _TIFFFetchStrileValue(TIFF* tif, + uint32 strile, + TIFFDirEntry* dirent, + uint64** parray) { -#if defined(DEFER_STRILE_LOAD) - register TIFFDirectory *td = &tif->tif_dir; - int return_value = 1; - - if( td->td_stripoffset != NULL ) - return 1; - - if( td->td_stripoffset_entry.tdir_count == 0 ) + 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( td->td_stripoffsetbyteallocsize == 0 && + td->td_nstrips < 1024 * 1024 ) + { + 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 (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry), - td->td_nstrips,&td->td_stripoffset)) + if( ~((*parray)[strile]) == 0 ) + { + if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) ) { - return_value = 0; + (*parray)[strile] = 0; + return 0; } + } + + return 1; +} - if (loadStripByteCount && - !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry), - td->td_nstrips,&td->td_stripbytecount)) +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 ) + { + 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 ) { - return_value = 0; + if( !_TIFFFillStriles(tif) ) + { + if( pbErr ) + *pbErr = 1; + return 0; + } } + 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]; +} - _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); - _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); +/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */ +uint64 TIFFGetStrileOffset(TIFF *tif, uint32 strile) +{ + return TIFFGetStrileOffsetWithErr(tif, strile, NULL); +} - if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) { - uint32 strip; +/* 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); +} - 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 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) ) 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; } diff --git a/libtiff/tif_dirwrite.c b/libtiff/tif_dirwrite.c index 83c01b24..cc0e6217 100644 --- a/libtiff/tif_dirwrite.c +++ b/libtiff/tif_dirwrite.c @@ -192,7 +192,7 @@ TIFFCheckpointDirectory(TIFF* tif) { int rc; /* Setup the strips arrays, if they haven't already been. */ - if (tif->tif_dir.td_stripoffset == NULL) + if (tif->tif_dir.td_stripoffset_p == NULL) (void) TIFFSetupStrips(tif); rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL); (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); @@ -527,12 +527,12 @@ TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) { if (!isTiled(tif)) { - if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount)) + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount_p)) goto bad; } else { - if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount)) + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount_p)) goto bad; } } @@ -540,7 +540,7 @@ TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) { if (!isTiled(tif)) { - /* td_stripoffset might be NULL in an odd OJPEG case. See + /* td_stripoffset_p might be NULL in an odd OJPEG case. See * tif_dirread.c around line 3634. * XXX: OJPEG hack. * If a) compression is OJPEG, b) it's not a tiled TIFF, @@ -551,13 +551,13 @@ TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) * We can get here when using tiffset on such a file. * See http://bugzilla.maptools.org/show_bug.cgi?id=2500 */ - if (tif->tif_dir.td_stripoffset != NULL && - !TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset)) + if (tif->tif_dir.td_stripoffset_p != NULL && + !TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset_p)) goto bad; } else { - if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset)) + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset_p)) goto bad; } } diff --git a/libtiff/tif_jpeg.c b/libtiff/tif_jpeg.c index f2ddc331..8606f623 100644 --- a/libtiff/tif_jpeg.c +++ b/libtiff/tif_jpeg.c @@ -780,12 +780,9 @@ JPEGFixupTagsSubsampling(TIFF* tif) */ static const char module[] = "JPEGFixupTagsSubsampling"; struct JPEGFixupTagsSubsamplingData m; + uint64 fileoffset = TIFFGetStrileOffset(tif, 0); - _TIFFFillStriles( tif ); - - if( tif->tif_dir.td_stripbytecount == NULL - || tif->tif_dir.td_stripoffset == NULL - || tif->tif_dir.td_stripbytecount[0] == 0 ) + if( fileoffset == 0 ) { /* Do not even try to check if the first strip/tile does not yet exist, as occurs when GDAL has created a new NULL file @@ -804,9 +801,9 @@ JPEGFixupTagsSubsampling(TIFF* tif) } m.buffercurrentbyte=NULL; m.bufferbytesleft=0; - m.fileoffset=tif->tif_dir.td_stripoffset[0]; + m.fileoffset=fileoffset; m.filepositioned=0; - m.filebytesleft=tif->tif_dir.td_stripbytecount[0]; + m.filebytesleft=TIFFGetStrileByteCount(tif, 0); if (!JPEGFixupTagsSubsamplingSec(&m)) TIFFWarningExt(tif->tif_clientdata,module, "Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped"); diff --git a/libtiff/tif_ojpeg.c b/libtiff/tif_ojpeg.c index 27385d8c..c01d71a2 100644 --- a/libtiff/tif_ojpeg.c +++ b/libtiff/tif_ojpeg.c @@ -990,7 +990,6 @@ OJPEGSubsamplingCorrect(TIFF* tif) OJPEGState* sp=(OJPEGState*)tif->tif_data; uint8 mh; uint8 mv; - _TIFFFillStriles( tif ); assert(sp->subsamplingcorrect_done==0); if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) && @@ -1989,29 +1988,21 @@ OJPEGReadBufferFill(OJPEGState* sp) sp->in_buffer_source=osibsStrile; break; case osibsStrile: - if (!_TIFFFillStriles( sp->tif ) - || sp->tif->tif_dir.td_stripoffset == NULL - || sp->tif->tif_dir.td_stripbytecount == NULL) - return 0; - if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) sp->in_buffer_source=osibsEof; else { - sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile]; + sp->in_buffer_file_pos=TIFFGetStrileOffset(sp->tif, sp->in_buffer_next_strile); if (sp->in_buffer_file_pos!=0) { + uint64 bytecount = TIFFGetStrileByteCount(sp->tif, sp->in_buffer_next_strile); if (sp->in_buffer_file_pos>=sp->file_size) sp->in_buffer_file_pos=0; - else if (sp->tif->tif_dir.td_stripbytecount==NULL) + else if (bytecount==0) sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; else { - if (sp->tif->tif_dir.td_stripbytecount == 0) { - TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing"); - return(0); - } - sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; + sp->in_buffer_file_togo=bytecount; if (sp->in_buffer_file_togo==0) sp->in_buffer_file_pos=0; else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size) diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c index c574c452..f7b7e0f8 100644 --- a/libtiff/tif_open.c +++ b/libtiff/tif_open.c @@ -181,6 +181,8 @@ TIFFClientOpen( * 'h' read TIFF header only, do not load the first IFD * '4' ClassicTIFF for creating a file (default) * '8' BigTIFF for creating a file + * 'D' enable use of deferred strip/tile offset/bytecount array loading. + * 'O' on-demand loading of values instead of whole array loading (implies D) * * The use of the 'l' and 'b' flags is strongly discouraged. * These flags are provided solely because numerous vendors, @@ -262,7 +264,22 @@ TIFFClientOpen( if (m&O_CREAT) tif->tif_flags |= TIFF_BIGTIFF; break; + case 'D': + tif->tif_flags |= TIFF_DEFERSTRILELOAD; + break; + case 'O': + if( m == O_RDONLY ) + tif->tif_flags |= (TIFF_LAZYSTRILELOAD | TIFF_DEFERSTRILELOAD); + break; } + +#ifdef DEFER_STRILE_LOAD + /* Compatibility with old DEFER_STRILE_LOAD compilation flag */ + /* Probably unneeded, since to the best of my knowledge (E. Rouault) */ + /* GDAL was the only user of this, and will now use the new 'D' flag */ + tif->tif_flags |= TIFF_DEFERSTRILELOAD; +#endif + /* * Read in TIFF header. */ diff --git a/libtiff/tif_print.c b/libtiff/tif_print.c index 1d86adbf..a0737941 100644 --- a/libtiff/tif_print.c +++ b/libtiff/tif_print.c @@ -652,8 +652,6 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) if (tif->tif_tagmethods.printdir) (*tif->tif_tagmethods.printdir)(tif, fd, flags); - _TIFFFillStriles( tif ); - if ((flags & TIFFPRINT_STRIPS) && TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) { uint32 s; @@ -665,13 +663,13 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) fprintf(fd, " %3lu: [%8I64u, %8I64u]\n", (unsigned long) s, - td->td_stripoffset ? (unsigned __int64) td->td_stripoffset[s] : 0, - td->td_stripbytecount ? (unsigned __int64) td->td_stripbytecount[s] : 0); + (unsigned __int64) TIFFGetStrileOffset(tif, s), + (unsigned __int64) TIFFGetStrileByteCount(tif, s)); #else fprintf(fd, " %3lu: [%8llu, %8llu]\n", (unsigned long) s, - td->td_stripoffset ? (unsigned long long) td->td_stripoffset[s] : 0, - td->td_stripbytecount ? (unsigned long long) td->td_stripbytecount[s] : 0); + (unsigned long long) TIFFGetStrileOffset(tif, s), + (unsigned long long) TIFFGetStrileByteCount(tif, s)); #endif } } diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c index 79c470cb..c65abcea 100644 --- a/libtiff/tif_read.c +++ b/libtiff/tif_read.c @@ -175,17 +175,14 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) tmsize_t to_read; tmsize_t read_ahead_mod; /* tmsize_t bytecountm; */ - - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - + /* * Expand raw data buffer, if needed, to hold data * strip coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ - /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ + /* bytecountm=(tmsize_t) TIFFGetStrileByteCount(tif, strip); */ /* Not completely sure where the * 2 comes from, but probably for */ /* an exponentional growth strategy of tif_rawdatasize */ @@ -229,7 +226,7 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) /* ** Seek to the point in the file where more data should be read. */ - read_offset = td->td_stripoffset[strip] + read_offset = TIFFGetStrileOffset(tif, strip) + tif->tif_rawdataoff + tif->tif_rawdataloaded; if (!SeekOK(tif, read_offset)) { @@ -246,10 +243,10 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) to_read = read_ahead_mod - unused_data; else to_read = tif->tif_rawdatasize - unused_data; - if( (uint64) to_read > td->td_stripbytecount[strip] + if( (uint64) to_read > TIFFGetStrileByteCount(tif, strip) - tif->tif_rawdataoff - tif->tif_rawdataloaded ) { - to_read = (tmsize_t) td->td_stripbytecount[strip] + to_read = (tmsize_t) TIFFGetStrileByteCount(tif, strip) - tif->tif_rawdataoff - tif->tif_rawdataloaded; } @@ -288,7 +285,7 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) /* For JPEG, if there are multiple scans (can generally be known */ /* with the read_ahead used), we need to read the whole strip */ if( tif->tif_dir.td_compression==COMPRESSION_JPEG && - (uint64)tif->tif_rawcc < td->td_stripbytecount[strip] ) + (uint64)tif->tif_rawcc < TIFFGetStrileByteCount(tif, strip) ) { if( TIFFJPEGIsFullStripRequired(tif) ) { @@ -347,9 +344,7 @@ TIFFSeek(TIFF* tif, uint32 row, uint16 sample ) * read it a few lines at a time? */ #if defined(CHUNKY_STRIP_READ_SUPPORT) - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10 + whole_strip = TIFFGetStrileByteCount(tif, strip) < 10 || isMapped(tif); if( td->td_compression == COMPRESSION_LERC || td->td_compression == COMPRESSION_JBIG ) @@ -402,7 +397,7 @@ TIFFSeek(TIFF* tif, uint32 row, uint16 sample ) else if( !whole_strip ) { if( ((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead - && (uint64) tif->tif_rawdataoff+tif->tif_rawdataloaded < td->td_stripbytecount[strip] ) + && (uint64) tif->tif_rawdataoff+tif->tif_rawdataloaded < TIFFGetStrileByteCount(tif, strip) ) { if( !TIFFFillStripPartial(tif,strip,read_ahead,0) ) return 0; @@ -599,16 +594,11 @@ static tmsize_t TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size, const char* module) { - TIFFDirectory *td = &tif->tif_dir; - - if (!_TIFFFillStriles( tif )) - return ((tmsize_t)(-1)); - assert((tif->tif_flags&TIFF_NOREADRAW)==0); if (!isMapped(tif)) { tmsize_t cc; - if (!SeekOK(tif, td->td_stripoffset[strip])) { + if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip))) { TIFFErrorExt(tif->tif_clientdata, module, "Seek error at scanline %lu, strip %lu", (unsigned long) tif->tif_row, (unsigned long) strip); @@ -634,8 +624,8 @@ TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size, } else { tmsize_t ma = 0; tmsize_t n; - if ((td->td_stripoffset[strip] > (uint64)TIFF_TMSIZE_T_MAX)|| - ((ma=(tmsize_t)td->td_stripoffset[strip])>tif->tif_size)) + if ((TIFFGetStrileOffset(tif, strip) > (uint64)TIFF_TMSIZE_T_MAX)|| + ((ma=(tmsize_t)TIFFGetStrileOffset(tif, strip))>tif->tif_size)) { n=0; } @@ -679,12 +669,10 @@ static tmsize_t TIFFReadRawStripOrTile2(TIFF* tif, uint32 strip_or_tile, int is_strip, tmsize_t size, const char* module) { - TIFFDirectory *td = &tif->tif_dir; - assert( !isMapped(tif) ); assert((tif->tif_flags&TIFF_NOREADRAW)==0); - if (!SeekOK(tif, td->td_stripoffset[strip_or_tile])) { + if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip_or_tile))) { if( is_strip ) { TIFFErrorExt(tif->tif_clientdata, module, @@ -738,7 +726,7 @@ TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size) "Compression scheme does not support access to raw uncompressed data"); return ((tmsize_t)(-1)); } - bytecount = td->td_stripbytecount[strip]; + bytecount = TIFFGetStrileByteCount(tif, strip); if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, @@ -773,12 +761,9 @@ TIFFFillStrip(TIFF* tif, uint32 strip) static const char module[] = "TIFFFillStrip"; TIFFDirectory *td = &tif->tif_dir; - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - if ((tif->tif_flags&TIFF_NOREADRAW)==0) { - uint64 bytecount = td->td_stripbytecount[strip]; + uint64 bytecount = TIFFGetStrileByteCount(tif, strip); if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, @@ -831,13 +816,13 @@ TIFFFillStrip(TIFF* tif, uint32 strip) * We must check for overflow, potentially causing * an OOB read. Instead of simple * - * td->td_stripoffset[strip]+bytecount > tif->tif_size + * TIFFGetStrileOffset(tif, strip)+bytecount > tif->tif_size * * comparison (which can overflow) we do the following * two comparisons: */ if (bytecount > (uint64)tif->tif_size || - td->td_stripoffset[strip] > (uint64)tif->tif_size - bytecount) { + TIFFGetStrileOffset(tif, strip) > (uint64)tif->tif_size - bytecount) { /* * This error message might seem strange, but * it's what would happen if a read were done @@ -849,7 +834,7 @@ TIFFFillStrip(TIFF* tif, uint32 strip) "Read error on strip %lu; " "got %I64u bytes, expected %I64u", (unsigned long) strip, - (unsigned __int64) tif->tif_size - td->td_stripoffset[strip], + (unsigned __int64) tif->tif_size - TIFFGetStrileOffset(tif, strip), (unsigned __int64) bytecount); #else TIFFErrorExt(tif->tif_clientdata, module, @@ -857,7 +842,7 @@ TIFFFillStrip(TIFF* tif, uint32 strip) "Read error on strip %lu; " "got %llu bytes, expected %llu", (unsigned long) strip, - (unsigned long long) tif->tif_size - td->td_stripoffset[strip], + (unsigned long long) tif->tif_size - TIFFGetStrileOffset(tif, strip), (unsigned long long) bytecount); #endif tif->tif_curstrip = NOSTRIP; @@ -886,7 +871,7 @@ TIFFFillStrip(TIFF* tif, uint32 strip) } tif->tif_flags &= ~TIFF_MYBUFFER; tif->tif_rawdatasize = (tmsize_t)bytecount; - tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[strip]; + tif->tif_rawdata = tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, strip); tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; @@ -1101,16 +1086,11 @@ _TIFFReadEncodedTileAndAllocBuffer(TIFF* tif, uint32 tile, static tmsize_t TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* module) { - TIFFDirectory *td = &tif->tif_dir; - - if (!_TIFFFillStriles( tif )) - return ((tmsize_t)(-1)); - assert((tif->tif_flags&TIFF_NOREADRAW)==0); if (!isMapped(tif)) { tmsize_t cc; - if (!SeekOK(tif, td->td_stripoffset[tile])) { + if (!SeekOK(tif, TIFFGetStrileOffset(tif, tile))) { TIFFErrorExt(tif->tif_clientdata, module, "Seek error at row %lu, col %lu, tile %lu", (unsigned long) tif->tif_row, @@ -1140,9 +1120,9 @@ TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* m } else { tmsize_t ma,mb; tmsize_t n; - ma=(tmsize_t)td->td_stripoffset[tile]; + ma=(tmsize_t)TIFFGetStrileOffset(tif, tile); mb=ma+size; - if ((td->td_stripoffset[tile] > (uint64)TIFF_TMSIZE_T_MAX)||(ma>tif->tif_size)) + if ((TIFFGetStrileOffset(tif, tile) > (uint64)TIFF_TMSIZE_T_MAX)||(ma>tif->tif_size)) n=0; else if ((mb<ma)||(mb<size)||(mb>tif->tif_size)) n=tif->tif_size-ma; @@ -1198,7 +1178,7 @@ TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size) "Compression scheme does not support access to raw uncompressed data"); return ((tmsize_t)(-1)); } - bytecount64 = td->td_stripbytecount[tile]; + bytecount64 = TIFFGetStrileByteCount(tif, tile); if (size != (tmsize_t)(-1) && (uint64)size < bytecount64) bytecount64 = (uint64)size; bytecountm = (tmsize_t)bytecount64; @@ -1220,12 +1200,9 @@ TIFFFillTile(TIFF* tif, uint32 tile) static const char module[] = "TIFFFillTile"; TIFFDirectory *td = &tif->tif_dir; - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - if ((tif->tif_flags&TIFF_NOREADRAW)==0) { - uint64 bytecount = td->td_stripbytecount[tile]; + uint64 bytecount = TIFFGetStrileByteCount(tif, tile); if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, @@ -1278,13 +1255,13 @@ TIFFFillTile(TIFF* tif, uint32 tile) * We must check for overflow, potentially causing * an OOB read. Instead of simple * - * td->td_stripoffset[tile]+bytecount > tif->tif_size + * TIFFGetStrileOffset(tif, tile)+bytecount > tif->tif_size * * comparison (which can overflow) we do the following * two comparisons: */ if (bytecount > (uint64)tif->tif_size || - td->td_stripoffset[tile] > (uint64)tif->tif_size - bytecount) { + TIFFGetStrileOffset(tif, tile) > (uint64)tif->tif_size - bytecount) { tif->tif_curtile = NOTILE; return (0); } @@ -1313,7 +1290,7 @@ TIFFFillTile(TIFF* tif, uint32 tile) tif->tif_rawdatasize = (tmsize_t)bytecount; tif->tif_rawdata = - tif->tif_base + (tmsize_t)td->td_stripoffset[tile]; + tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, tile); tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; tif->tif_flags |= TIFF_BUFFERMMAP; @@ -1440,9 +1417,6 @@ TIFFStartStrip(TIFF* tif, uint32 strip) { TIFFDirectory *td = &tif->tif_dir; - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupdecode)(tif)) return (0); @@ -1463,7 +1437,7 @@ TIFFStartStrip(TIFF* tif, uint32 strip) if( tif->tif_rawdataloaded > 0 ) tif->tif_rawcc = tif->tif_rawdataloaded; else - tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[strip]; + tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, strip); } return ((*tif->tif_predecode)(tif, (uint16)(strip / td->td_stripsperimage))); @@ -1480,9 +1454,6 @@ TIFFStartTile(TIFF* tif, uint32 tile) TIFFDirectory *td = &tif->tif_dir; uint32 howmany32; - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; - if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupdecode)(tif)) return (0); @@ -1513,7 +1484,7 @@ TIFFStartTile(TIFF* tif, uint32 tile) if( tif->tif_rawdataloaded > 0 ) tif->tif_rawcc = tif->tif_rawdataloaded; else - tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[tile]; + tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, tile); } return ((*tif->tif_predecode)(tif, (uint16)(tile/td->td_stripsperimage))); diff --git a/libtiff/tif_strip.c b/libtiff/tif_strip.c index 5b76fba5..2f3cd883 100644 --- a/libtiff/tif_strip.c +++ b/libtiff/tif_strip.c @@ -147,8 +147,7 @@ uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip) { static const char module[] = "TIFFRawStripSize64"; - TIFFDirectory* td = &tif->tif_dir; - uint64 bytecount = td->td_stripbytecount[strip]; + uint64 bytecount = TIFFGetStrileByteCount(tif, strip); if (bytecount == 0) { diff --git a/libtiff/tif_write.c b/libtiff/tif_write.c index 4e5d8175..b79fd945 100644 --- a/libtiff/tif_write.c +++ b/libtiff/tif_write.c @@ -128,10 +128,10 @@ TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample) tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; - if( td->td_stripbytecount[strip] > 0 ) + if( td->td_stripbytecount_p[strip] > 0 ) { /* if we are writing over existing tiles, zero length */ - td->td_stripbytecount[strip] = 0; + td->td_stripbytecount_p[strip] = 0; /* this forces TIFFAppendToStrip() to do a seek */ tif->tif_curoff = 0; @@ -183,11 +183,11 @@ TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample) static int _TIFFReserveLargeEnoughWriteBuffer(TIFF* tif, uint32 strip_or_tile) { TIFFDirectory *td = &tif->tif_dir; - if( td->td_stripbytecount[strip_or_tile] > 0 ) + if( td->td_stripbytecount_p[strip_or_tile] > 0 ) { /* The +1 is to ensure at least one extra bytes */ /* The +4 is because the LZW encoder flushes 4 bytes before the limit */ - uint64 safe_buffer_size = (uint64)(td->td_stripbytecount[strip_or_tile] + 1 + 4); + uint64 safe_buffer_size = (uint64)(td->td_stripbytecount_p[strip_or_tile] + 1 + 4); if( tif->tif_rawdatasize <= (tmsize_t)safe_buffer_size ) { if( !(TIFFWriteBufferSetup(tif, NULL, @@ -535,20 +535,20 @@ TIFFSetupStrips(TIFF* tif) td->td_nstrips = td->td_stripsperimage; if (td->td_planarconfig == PLANARCONFIG_SEPARATE) td->td_stripsperimage /= td->td_samplesperpixel; - td->td_stripoffset = (uint64 *) + td->td_stripoffset_p = (uint64 *) _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64), "for \"StripOffsets\" array"); - td->td_stripbytecount = (uint64 *) + td->td_stripbytecount_p = (uint64 *) _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64), "for \"StripByteCounts\" array"); - if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) + if (td->td_stripoffset_p == NULL || td->td_stripbytecount_p == NULL) return (0); /* * Place data at the end-of-file * (by setting offsets to zero). */ - _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint64)); - _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint64)); + _TIFFmemset(td->td_stripoffset_p, 0, td->td_nstrips*sizeof (uint64)); + _TIFFmemset(td->td_stripbytecount_p, 0, td->td_nstrips*sizeof (uint64)); TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); return (1); @@ -608,7 +608,7 @@ TIFFWriteCheck(TIFF* tif, int tiles, const char* module) return (0); } } - if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { + if (tif->tif_dir.td_stripoffset_p == NULL && !TIFFSetupStrips(tif)) { tif->tif_dir.td_nstrips = 0; TIFFErrorExt(tif->tif_clientdata, module, "No space for %s arrays", isTiled(tif) ? "tile" : "strip"); @@ -682,9 +682,9 @@ TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module) uint64* new_stripbytecount; assert(td->td_planarconfig == PLANARCONFIG_CONTIG); - new_stripoffset = (uint64*)_TIFFrealloc(td->td_stripoffset, + new_stripoffset = (uint64*)_TIFFrealloc(td->td_stripoffset_p, (td->td_nstrips + delta) * sizeof (uint64)); - new_stripbytecount = (uint64*)_TIFFrealloc(td->td_stripbytecount, + new_stripbytecount = (uint64*)_TIFFrealloc(td->td_stripbytecount_p, (td->td_nstrips + delta) * sizeof (uint64)); if (new_stripoffset == NULL || new_stripbytecount == NULL) { if (new_stripoffset) @@ -695,11 +695,11 @@ TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module) TIFFErrorExt(tif->tif_clientdata, module, "No space to expand strip arrays"); return (0); } - td->td_stripoffset = new_stripoffset; - td->td_stripbytecount = new_stripbytecount; - _TIFFmemset(td->td_stripoffset + td->td_nstrips, + td->td_stripoffset_p = new_stripoffset; + td->td_stripbytecount_p = new_stripbytecount; + _TIFFmemset(td->td_stripoffset_p + td->td_nstrips, 0, delta*sizeof (uint64)); - _TIFFmemset(td->td_stripbytecount + td->td_nstrips, + _TIFFmemset(td->td_stripbytecount_p + td->td_nstrips, 0, delta*sizeof (uint64)); td->td_nstrips += delta; tif->tif_flags |= TIFF_DIRTYDIRECT; @@ -718,12 +718,12 @@ TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc) uint64 m; int64 old_byte_count = -1; - if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { + if (td->td_stripoffset_p[strip] == 0 || tif->tif_curoff == 0) { assert(td->td_nstrips > 0); - if( td->td_stripbytecount[strip] != 0 - && td->td_stripoffset[strip] != 0 - && td->td_stripbytecount[strip] >= (uint64) cc ) + if( td->td_stripbytecount_p[strip] != 0 + && td->td_stripoffset_p[strip] != 0 + && td->td_stripbytecount_p[strip] >= (uint64) cc ) { /* * There is already tile data on disk, and the new tile @@ -732,7 +732,7 @@ TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc) * more data to append to this strip before we are done * depending on how we are getting called. */ - if (!SeekOK(tif, td->td_stripoffset[strip])) { + if (!SeekOK(tif, td->td_stripoffset_p[strip])) { TIFFErrorExt(tif->tif_clientdata, module, "Seek error at scanline %lu", (unsigned long)tif->tif_row); @@ -745,17 +745,17 @@ TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc) * Seek to end of file, and set that as our location to * write this strip. */ - td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END); + td->td_stripoffset_p[strip] = TIFFSeekFile(tif, 0, SEEK_END); tif->tif_flags |= TIFF_DIRTYSTRIP; } - tif->tif_curoff = td->td_stripoffset[strip]; + tif->tif_curoff = td->td_stripoffset_p[strip]; /* * We are starting a fresh strip/tile, so set the size to zero. */ - old_byte_count = td->td_stripbytecount[strip]; - td->td_stripbytecount[strip] = 0; + old_byte_count = td->td_stripbytecount_p[strip]; + td->td_stripbytecount_p[strip] = 0; } m = tif->tif_curoff+cc; @@ -772,9 +772,9 @@ TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc) return (0); } tif->tif_curoff = m; - td->td_stripbytecount[strip] += cc; + td->td_stripbytecount_p[strip] += cc; - if( (int64) td->td_stripbytecount[strip] != old_byte_count ) + if( (int64) td->td_stripbytecount_p[strip] != old_byte_count ) tif->tif_flags |= TIFF_DIRTYSTRIP; return (1); diff --git a/libtiff/tiffio.h b/libtiff/tiffio.h index 31c2e676..7193fbcf 100644 --- a/libtiff/tiffio.h +++ b/libtiff/tiffio.h @@ -488,6 +488,11 @@ extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); extern void TIFFReverseBits(uint8* cp, tmsize_t n); extern const unsigned char* TIFFGetBitRevTable(int); +extern uint64 TIFFGetStrileOffset(TIFF *tif, uint32 strile); +extern uint64 TIFFGetStrileByteCount(TIFF *tif, uint32 strile); +extern uint64 TIFFGetStrileOffsetWithErr(TIFF *tif, uint32 strile, int *pbErr); +extern uint64 TIFFGetStrileByteCountWithErr(TIFF *tif, uint32 strile, int *pbErr); + #ifdef LOGLUV_PUBLIC #define U_NEU 0.210526316 #define V_NEU 0.473684211 diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h index 47a553aa..ef63de53 100644 --- a/libtiff/tiffiop.h +++ b/libtiff/tiffiop.h @@ -127,6 +127,8 @@ struct tiff { #define TIFF_DIRTYSTRIP 0x200000U /* stripoffsets/stripbytecount dirty*/ #define TIFF_PERSAMPLE 0x400000U /* get/set per sample tags as arrays */ #define TIFF_BUFFERMMAP 0x800000U /* read buffer (tif_rawdata) points into mmap() memory */ + #define TIFF_DEFERSTRILELOAD 0x1000000U /* defer strip/tile offset/bytecount array loading. */ + #define TIFF_LAZYSTRILELOAD 0x2000000U /* lazy/ondemand loading of strip/tile offset/bytecount values. Only used if TIFF_DEFERSTRILELOAD is set and in read-only mode */ uint64 tif_diroff; /* file offset of current directory */ uint64 tif_nextdiroff; /* file offset of following directory */ uint64* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */ |