Make defer strile offset/bytecount loading available at runtime

... and add per-strile offset/bytecount loading capabilities.

Part of this commit makes the behaviour that was previously met when
libtiff was compiled with -DDEFER_STRILE_LOAD available for default builds
when specifying the new 'D' (Deferred) TIFFOpen() flag. In that mode, the [Tile/Strip][ByteCounts/Offsets]
arrays are only loaded when first accessed. This can speed-up the opening
of files stored on the network when just metadata retrieval is needed.
This mode has been used for years by the GDAL library when compiled with
its embeded libtiff copy.

To avoid potential out-of-tree code (typically codecs) that would use
the td_stripbytecount and td_stripoffset array inconditionnaly assuming they
have been loaded, those have been suffixed with _p (for protected). The
use of the new functions mentionned below is then recommended.

Another addition of this commit is the capability of loading only the
values of the offset/bytecount of the strile of interest instead of the
whole array. This is enabled with the new 'O' (Ondemand) flag of TIFFOpen()
(which implies 'D'). That behaviour has also been used by GDAL, which hacked
into the td_stripoffset/td_stripbytecount arrays directly. The new code
added in the _TIFFFetchStrileValue() and _TIFFPartialReadStripArray() internal
functions is mostly a port of what was in GDAL GTiff driver previously.

Related to that, the public TIFFGetStrileOffset[WithErr]() and TIFFGetStrileByteCount[WithErr]()
functions have been added to API. They are of particular interest when
using sparse files (with offset == bytecount == 0) and you want to detect
if a strile is present or not without decompressing the data, or updating
an existing sparse file.
They will also be used to enable a future enhancement where client code can entirely
skip bytecount loading in some situtations

A new test/defer_strile_loading.c test has been added to test the above
capabilities.
This commit is contained in:
Even Rouault 2019-05-10 14:46:45 +02:00
parent b9b93f661e
commit 371ad2658c
No known key found for this signature in database
GPG Key ID: 33EBBFC47B3DD87D
20 changed files with 863 additions and 270 deletions

1
.gitignore vendored
View File

@ -66,6 +66,7 @@ test/raw_decode
test/rewrite
test/short_tag
test/strip_rw
test/defer_strile_loading
test/*.log
test/*.trs
test/o-*

View File

@ -623,7 +623,7 @@ if(strip-chopping)
endif()
# Defer loading of strip/tile offsets
option(defer-strile-load "enable deferred strip/tile offset/size loading (experimental)" OFF)
option(defer-strile-load "enable deferred strip/tile offset/size loading (also available at runtime with the 'D' flag of TIFFOpen())" OFF)
set(DEFER_STRILE_LOAD ${defer-strile-load})
# CHUNKY_STRIP_READ_SUPPORT

View File

@ -1070,17 +1070,16 @@ fi
dnl ---------------------------------------------------------------------------
dnl Should we try to defer loading of strip/tile offsets and sizes to
dnl optimize directory scanning? These is an experimental feature for
dnl libtiff 4.0.
dnl optimize directory scanning?
dnl ---------------------------------------------------------------------------
AC_ARG_ENABLE(defer-strile-load,
AS_HELP_STRING([--enable-defer-strile-load],
[enable deferred strip/tile offset/size loading (experimental)]),
[enable deferred strip/tile offset/size loading (also available at runtime with the 'D' flag of TIFFOpen()]),
[HAVE_DEFER_STRILE_LOAD=$enableval], [HAVE_DEFER_STRILE_LOAD=no])
if test "$HAVE_DEFER_STRILE_LOAD" = "yes" ; then
AC_DEFINE(DEFER_STRILE_LOAD,1,[enable deferred strip/tile offset/size loading (experimental)])
AC_DEFINE(DEFER_STRILE_LOAD,1,[enable deferred strip/tile offset/size loading])
fi

View File

@ -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;

View File

@ -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 */

View File

@ -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,6 +5947,317 @@ 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;
}
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 _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( 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( ~((*parray)[strile]) == 0 )
{
if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) )
{
(*parray)[strile] = 0;
return 0;
}
}
return 1;
}
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 )
{
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];
}
/* 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);
}
int _TIFFFillStriles( TIFF *tif )
@ -5945,51 +6267,64 @@ int _TIFFFillStriles( TIFF *tif )
static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount )
{
#if defined(DEFER_STRILE_LOAD)
register TIFFDirectory *td = &tif->tif_dir;
int return_value = 1;
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 )
return 0;
if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
td->td_nstrips,&td->td_stripoffset))
{
return_value = 0;
}
if (loadStripByteCount &&
!TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
td->td_nstrips,&td->td_stripbytecount))
{
return_value = 0;
}
_TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
_TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
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[strip - 1] >
tif->tif_dir.td_stripoffset[strip]) {
tif->tif_dir.td_stripbytecountsorted = 0;
break;
}
}
}
return return_value;
#else /* !defined(DEFER_STRILE_LOAD) */
(void) tif;
(void) loadStripByteCount;
/* 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;
}

View File

@ -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;
}
}

View File

@ -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");

View File

@ -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)

View File

@ -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.
*/

View File

@ -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
}
}

View File

@ -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)));

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -207,6 +207,21 @@ Disable the use of strip chopping when reading images.
Read TIFF header only, do not load the first image directory. That could be
useful in case of the broken first directory. We can open the file and proceed
to the other directories.
.TP
.B 4
ClassicTIFF for creating a file (default)
.TP
.B 8
BigTIFF for creating a file.
.TP
.B D
Enable use of deferred strip/tile offset/bytecount array loading. They will
be loaded the first time they are accessed to. This loading will be done in
its entirety unless the O flag is also specified.
.TP
.B O
On-demand loading of values of the strip/tile offset/bytecount arrays, limited
to the requested strip/tile, instead of whole array loading (implies D)
.SH "BYTE ORDER"
The
.SM TIFF

View File

@ -188,6 +188,9 @@ endif()
add_executable(custom_dir custom_dir.c)
target_link_libraries(custom_dir tiff port)
add_executable(defer_strile_loading defer_strile_loading.c)
target_link_libraries(defer_strile_loading tiff port)
set(TEST_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output")
file(MAKE_DIRECTORY "${TEST_OUTPUT}")

View File

@ -63,7 +63,7 @@ endif
# Executable programs which need to be built in order to support tests
check_PROGRAMS = \
ascii_tag long_tag short_tag strip_rw rewrite custom_dir \
ascii_tag long_tag short_tag strip_rw rewrite custom_dir defer_strile_loading \
$(JPEG_DEPENDENT_CHECK_PROG)
# Test scripts to execute
@ -202,6 +202,8 @@ raw_decode_SOURCES = raw_decode.c
raw_decode_LDADD = $(LIBTIFF)
custom_dir_SOURCES = custom_dir.c
custom_dir_LDADD = $(LIBTIFF)
defer_strile_loading_SOURCES = defer_strile_loading.c
defer_strile_loading_LDADD = $(LIBTIFF)
AM_CPPFLAGS = -I$(top_srcdir)/libtiff

256
test/defer_strile_loading.c Normal file
View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that (i) the above copyright notices and this permission notice appear in
* all copies of the software and related documentation, and (ii) the names of
* Sam Leffler and Silicon Graphics may not be used in any advertising or
* publicity relating to the software without the specific, prior written
* permission of Sam Leffler and Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* TIFF Library
*
* Module to test 'D' and 'O' open flags
*/
#include "tif_config.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "tiffio.h"
#include "tifftest.h"
int test(int classictif, int height, int tiled)
{
const char* filename = "defer_strile_loading.tif";
TIFF* tif;
int i;
int ret;
tif = TIFFOpen(filename, classictif ? "wDO" : "w8DO"); /* O should be ignored in write mode */
if(!tif)
{
fprintf(stderr, "cannot create %s\n", filename);
return 1;
}
ret = TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
assert(ret);
ret = TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 1);
assert(ret);
ret = TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
assert(ret);
ret = TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
assert(ret);
ret = TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
assert(ret);
ret = TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
assert(ret);
if( tiled )
{
int j;
ret = TIFFSetField(tif, TIFFTAG_TILEWIDTH, 16);
assert( ret );
ret = TIFFSetField(tif, TIFFTAG_TILELENGTH, 16);
assert( ret );
for( j = 0; j < (height+15) / 16; j++ )
{
unsigned char tilebuffer[256];
memset(tilebuffer, (unsigned char)j, 256);
ret = TIFFWriteEncodedTile( tif, j, tilebuffer, 256 );
assert(ret == 256);
}
}
else
{
ret = TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
assert(ret);
for( i = 0; i < height; i++ )
{
unsigned char c = (unsigned char)i;
ret = TIFFWriteEncodedStrip( tif, i, &c, 1 );
assert(ret == 1);
if( i == 1 && height > 100000 )
i = height - 2;
}
}
TIFFClose(tif);
for( i = 0; i < 2; i++ )
{
tif = TIFFOpen(filename, i == 0 ? "rD" : "rO");
if(!tif)
{
fprintf(stderr, "cannot open %s\n", filename);
return 1;
}
if( tiled )
{
int j;
for( j = 0; j < (height+15) / 16; j++ )
{
int retry;
for( retry = 0; retry < 2; retry++ )
{
unsigned char tilebuffer[256];
unsigned char expected_c = (unsigned char)j;
memset(tilebuffer,0, 256);
ret = TIFFReadEncodedTile( tif, j, tilebuffer, 256 );
assert(ret == 256);
if( tilebuffer[0] != expected_c ||
tilebuffer[255] != expected_c )
{
fprintf(stderr, "unexpected value at tile %d: %d %d\n",
j, tilebuffer[0], tilebuffer[255]);
TIFFClose(tif);
return 1;
}
}
{
int err = 0;
ret = TIFFGetStrileOffsetWithErr(tif, j, &err);
assert(ret != 0);
assert(err == 0);
ret = TIFFGetStrileByteCountWithErr(tif, j, &err);
assert(ret == 256);
assert(err == 0);
}
}
}
else
{
int j;
for( j = 0; j < height; j++ )
{
int retry;
for( retry = 0; retry < 2; retry++ )
{
unsigned char c = 0;
unsigned char expected_c = (unsigned char)j;
ret = TIFFReadEncodedStrip( tif, j, &c, 1 );
assert(ret == 1);
if( c != expected_c )
{
fprintf(stderr, "unexpected value at line %d: %d\n",
j, c);
TIFFClose(tif);
return 1;
}
}
{
int err = 0;
ret = TIFFGetStrileOffsetWithErr(tif, j, &err);
assert(ret != 0);
assert(err == 0);
ret = TIFFGetStrileByteCountWithErr(tif, j, &err);
assert(ret == 1);
assert(err == 0);
}
if( j == 1 && height > 100000 )
j = height - 2;
}
if( height > 100000 )
{
/* Missing strip */
int err = 0;
ret = TIFFGetStrileOffsetWithErr(tif, 2, &err);
assert(ret == 0);
assert(err == 0);
ret = TIFFGetStrileByteCountWithErr(tif, 2, &err);
assert(ret == 0);
assert(err == 0);
}
}
{
int err = 0;
ret = TIFFGetStrileOffsetWithErr(tif, 0xFFFFFFFFU, &err);
assert(ret == 0);
assert(err == 1);
ret = TIFFGetStrileByteCountWithErr(tif, 0xFFFFFFFFU, &err);
assert(ret == 0);
assert(err == 1);
}
{
toff_t* offsets = NULL;
toff_t* bytecounts = NULL;
ret = TIFFGetField( tif,
tiled ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS, &offsets );
assert(ret);
assert(offsets);
ret = TIFFGetField( tif,
tiled ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS, &bytecounts );
assert(ret);
assert(bytecounts);
if( tiled )
{
assert(bytecounts[0] == 256);
}
else
{
assert(bytecounts[0] == 1);
if( height > 1 && height <= 100000)
{
assert(offsets[1] == offsets[0] + 1);
assert(offsets[height - 1] == offsets[0] + height - 1);
}
assert(bytecounts[height - 1] == 1);
}
}
TIFFClose(tif);
}
unlink(filename);
return 0;
}
int
main()
{
int is_classic;
for( is_classic = 1; is_classic >= 0; is_classic-- )
{
int tiled;
for( tiled = 0; tiled <= 1; tiled ++ )
{
if( test(is_classic, 1, tiled) )
return 1;
if( test(is_classic, 8192, tiled) )
return 1;
}
if( test(is_classic, 2000000, 0) )
return 1;
}
return 0;
}