Sweden-Number/libs/tiff/libtiff/tif_dirread.c

6496 lines
172 KiB
C

/*
* Copyright (c) 1988-1997 Sam Leffler
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
*
* 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.
*
* Directory Read Support Routines.
*/
/* Suggested pending improvements:
* - add a field 'field_info' to the TIFFDirEntry structure, and set that with
* the pointer to the appropriate TIFFField structure early on in
* TIFFReadDirectory, so as to eliminate current possibly repetitive lookup.
*/
#include "tiffconf.h"
#include "tiffiop.h"
#include <float.h>
#include <stdlib.h>
#define FAILED_FII ((uint32_t) -1)
#ifdef HAVE_IEEEFP
# define TIFFCvtIEEEFloatToNative(tif, n, fp)
# define TIFFCvtIEEEDoubleToNative(tif, n, dp)
#else
extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32_t, float*);
extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32_t, double*);
#endif
enum TIFFReadDirEntryErr {
TIFFReadDirEntryErrOk = 0,
TIFFReadDirEntryErrCount = 1,
TIFFReadDirEntryErrType = 2,
TIFFReadDirEntryErrIo = 3,
TIFFReadDirEntryErrRange = 4,
TIFFReadDirEntryErrPsdif = 5,
TIFFReadDirEntryErrSizesan = 6,
TIFFReadDirEntryErrAlloc = 7,
};
static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize, void** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value);
#if 0
static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
#endif
static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value);
static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8_t* value);
static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value);
static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16_t* value);
static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value);
static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64_t* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value);
static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64_t offset, tmsize_t size, void* dest);
static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover);
static void TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount);
static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount, uint16_t tagid);
static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t* fii);
static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount);
static void MissingRequired(TIFF*, const char*);
static int TIFFCheckDirOffset(TIFF* tif, uint64_t diroff);
static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32_t);
static uint16_t TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, uint64_t* nextdiroff);
static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32_t nstrips, uint64_t** lpp);
static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
static void ChopUpSingleUncompressedStrip(TIFF*);
static void TryChopUpUncompressedBigTiff(TIFF*);
static uint64_t TIFFReadUInt64(const uint8_t *value);
static int _TIFFGetMaxColorChannels(uint16_t photometric);
static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount );
typedef union _UInt64Aligned_t
{
double d;
uint64_t l;
uint32_t i[2];
uint16_t s[4];
uint8_t c[8];
} UInt64Aligned_t;
/*
Unaligned safe copy of a uint64_t value from an octet array.
*/
static uint64_t TIFFReadUInt64(const uint8_t *value)
{
UInt64Aligned_t result;
result.c[0]=value[0];
result.c[1]=value[1];
result.c[2]=value[2];
result.c[3]=value[3];
result.c[4]=value[4];
result.c[5]=value[5];
result.c[6]=value[6];
result.c[7]=value[7];
return result.l;
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_UNDEFINED: /* Support to read TIFF_UNDEFINED with field_readcount==1 */
TIFFReadDirEntryCheckedByte(tif,direntry,value);
return(TIFFReadDirEntryErrOk);
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeByteSbyte(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
{
uint16_t m;
TIFFReadDirEntryCheckedShort(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeByteShort(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeByteSshort(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeByteLong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeByteSlong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
{
uint64_t m;
err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeByteLong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeByteSlong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint8_t)m;
return(TIFFReadDirEntryErrOk);
}
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t m;
TIFFReadDirEntryCheckedByte(tif,direntry,&m);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeShortSbyte(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
TIFFReadDirEntryCheckedShort(tif,direntry,value);
return(TIFFReadDirEntryErrOk);
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeShortSshort(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeShortLong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeShortSlong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
{
uint64_t m;
err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeShortLong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeShortSlong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint16_t)m;
return(TIFFReadDirEntryErrOk);
}
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t m;
TIFFReadDirEntryCheckedByte(tif,direntry,&m);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLongSbyte(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
{
uint16_t m;
TIFFReadDirEntryCheckedShort(tif,direntry,&m);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLongSshort(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
TIFFReadDirEntryCheckedLong(tif,direntry,value);
return(TIFFReadDirEntryErrOk);
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLongSlong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
{
uint64_t m;
err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeLongLong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeLongSlong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint32_t)m;
return(TIFFReadDirEntryErrOk);
}
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t m;
TIFFReadDirEntryCheckedByte(tif,direntry,&m);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLong8Sbyte(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
{
uint16_t m;
TIFFReadDirEntryCheckedShort(tif,direntry,&m);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLong8Sshort(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
err=TIFFReadDirEntryCheckRangeLong8Slong(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
return(err);
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
err=TIFFReadDirEntryCheckRangeLong8Slong8(m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t m;
TIFFReadDirEntryCheckedByte(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
{
uint16_t m;
TIFFReadDirEntryCheckedShort(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
{
uint64_t m;
err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
#if defined(__WIN32__) && (_MSC_VER < 1500)
/*
* XXX: MSVC 6.0 does not support conversion
* of 64-bit integers into floating point
* values.
*/
*value = _TIFFUInt64ToFloat(m);
#else
*value=(float)m;
#endif
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_RATIONAL:
{
double m;
err=TIFFReadDirEntryCheckedRational(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SRATIONAL:
{
double m;
err=TIFFReadDirEntryCheckedSrational(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_FLOAT:
TIFFReadDirEntryCheckedFloat(tif,direntry,value);
return(TIFFReadDirEntryErrOk);
case TIFF_DOUBLE:
{
double m;
err=TIFFReadDirEntryCheckedDouble(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
if ((m > FLT_MAX) || (m < -FLT_MAX))
return(TIFFReadDirEntryErrRange);
*value=(float)m;
return(TIFFReadDirEntryErrOk);
}
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t m;
TIFFReadDirEntryCheckedByte(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
{
int8_t m;
TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SHORT:
{
uint16_t m;
TIFFReadDirEntryCheckedShort(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
{
int16_t m;
TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
{
int32_t m;
TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
{
uint64_t m;
err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
#if defined(__WIN32__) && (_MSC_VER < 1500)
/*
* XXX: MSVC 6.0 does not support conversion
* of 64-bit integers into floating point
* values.
*/
*value = _TIFFUInt64ToDouble(m);
#else
*value = (double)m;
#endif
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
{
int64_t m;
err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_RATIONAL:
err=TIFFReadDirEntryCheckedRational(tif,direntry,value);
return(err);
case TIFF_SRATIONAL:
err=TIFFReadDirEntryCheckedSrational(tif,direntry,value);
return(err);
case TIFF_FLOAT:
{
float m;
TIFFReadDirEntryCheckedFloat(tif,direntry,&m);
*value=(double)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_DOUBLE:
err=TIFFReadDirEntryCheckedDouble(tif,direntry,value);
return(err);
default:
return(TIFFReadDirEntryErrType);
}
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value)
{
enum TIFFReadDirEntryErr err;
if (direntry->tdir_count!=1)
return(TIFFReadDirEntryErrCount);
switch (direntry->tdir_type)
{
case TIFF_LONG:
case TIFF_IFD:
{
uint32_t m;
TIFFReadDirEntryCheckedLong(tif,direntry,&m);
*value=(uint64_t)m;
return(TIFFReadDirEntryErrOk);
}
case TIFF_LONG8:
case TIFF_IFD8:
err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
return(err);
default:
return(TIFFReadDirEntryErrType);
}
}
#define INITIAL_THRESHOLD (1024 * 1024)
#define THRESHOLD_MULTIPLIER 10
#define MAX_THRESHOLD (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * INITIAL_THRESHOLD)
static enum TIFFReadDirEntryErr TIFFReadDirEntryDataAndRealloc(
TIFF* tif, uint64_t offset, tmsize_t size, void** pdest)
{
#if SIZEOF_SIZE_T == 8
tmsize_t threshold = INITIAL_THRESHOLD;
#endif
tmsize_t already_read = 0;
assert( !isMapped(tif) );
if (!SeekOK(tif,offset))
return(TIFFReadDirEntryErrIo);
/* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */
/* so as to avoid allocating too much memory in case the file is too */
/* short. We could ask for the file size, but this might be */
/* expensive with some I/O layers (think of reading a gzipped file) */
/* Restrict to 64 bit processes, so as to avoid reallocs() */
/* on 32 bit processes where virtual memory is scarce. */
while( already_read < size )
{
void* new_dest;
tmsize_t bytes_read;
tmsize_t to_read = size - already_read;
#if SIZEOF_SIZE_T == 8
if( to_read >= threshold && threshold < MAX_THRESHOLD )
{
to_read = threshold;
threshold *= THRESHOLD_MULTIPLIER;
}
#endif
new_dest = (uint8_t*) _TIFFrealloc(
*pdest, already_read + to_read);
if( new_dest == NULL )
{
TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
"Failed to allocate memory for %s "
"(%"TIFF_SSIZE_FORMAT" elements of %"TIFF_SSIZE_FORMAT" bytes each)",
"TIFFReadDirEntryArray",
(tmsize_t) 1, already_read + to_read);
return TIFFReadDirEntryErrAlloc;
}
*pdest = new_dest;
bytes_read = TIFFReadFile(tif,
(char*)*pdest + already_read, to_read);
already_read += bytes_read;
if (bytes_read != to_read) {
return TIFFReadDirEntryErrIo;
}
}
return TIFFReadDirEntryErrOk;
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryArrayWithLimit(
TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize,
void** value, uint64_t maxcount)
{
int typesize;
uint32_t datasize;
void* data;
uint64_t target_count64;
int original_datasize_clamped;
typesize=TIFFDataWidth(direntry->tdir_type);
target_count64 = (direntry->tdir_count > maxcount) ?
maxcount : direntry->tdir_count;
if ((target_count64==0)||(typesize==0))
{
*value=0;
return(TIFFReadDirEntryErrOk);
}
(void) desttypesize;
/* We just want to know if the original tag size is more than 4 bytes
* (classic TIFF) or 8 bytes (BigTIFF)
*/
original_datasize_clamped =
((direntry->tdir_count > 10) ? 10 : (int)direntry->tdir_count) * typesize;
/*
* As a sanity check, make sure we have no more than a 2GB tag array
* in either the current data type or the dest data type. This also
* avoids problems with overflow of tmsize_t on 32bit systems.
*/
if ((uint64_t)(2147483647 / typesize) < target_count64)
return(TIFFReadDirEntryErrSizesan);
if ((uint64_t)(2147483647 / desttypesize) < target_count64)
return(TIFFReadDirEntryErrSizesan);
*count=(uint32_t)target_count64;
datasize=(*count)*typesize;
assert((tmsize_t)datasize>0);
if( isMapped(tif) && datasize > (uint64_t)tif->tif_size )
return TIFFReadDirEntryErrIo;
if( !isMapped(tif) &&
(((tif->tif_flags&TIFF_BIGTIFF) && datasize > 8) ||
(!(tif->tif_flags&TIFF_BIGTIFF) && datasize > 4)) )
{
data = NULL;
}
else
{
data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray");
if (data==0)
return(TIFFReadDirEntryErrAlloc);
}
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
/* Only the condition on original_datasize_clamped. The second
* one is implied, but Coverity Scan cannot see it. */
if (original_datasize_clamped<=4 && datasize <= 4 )
_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
else
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
if( isMapped(tif) )
err=TIFFReadDirEntryData(tif, (uint64_t)offset, (tmsize_t)datasize, data);
else
err=TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, (tmsize_t)datasize, &data);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
}
}
else
{
/* See above comment for the Classic TIFF case */
if (original_datasize_clamped<=8 && datasize <= 8 )
_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
else
{
enum TIFFReadDirEntryErr err;
uint64_t offset = direntry->tdir_offset.toff_long8;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(&offset);
if( isMapped(tif) )
err=TIFFReadDirEntryData(tif, (uint64_t)offset, (tmsize_t)datasize, data);
else
err=TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, (tmsize_t)datasize, &data);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
}
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize, void** value)
{
return TIFFReadDirEntryArrayWithLimit(tif, direntry, count,
desttypesize, value, ~((uint64_t)0));
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
uint8_t* data;
switch (direntry->tdir_type)
{
case TIFF_ASCII:
case TIFF_UNDEFINED:
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_ASCII:
case TIFF_UNDEFINED:
case TIFF_BYTE:
*value=(uint8_t*)origdata;
return(TIFFReadDirEntryErrOk);
case TIFF_SBYTE:
{
int8_t* m;
uint32_t n;
m=(int8_t*)origdata;
for (n=0; n<count; n++)
{
err=TIFFReadDirEntryCheckRangeByteSbyte(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(uint8_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
}
data=(uint8_t*)_TIFFmalloc(count);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_SHORT:
{
uint16_t* ma;
uint8_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
err=TIFFReadDirEntryCheckRangeByteShort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
uint8_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
err=TIFFReadDirEntryCheckRangeByteSshort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
uint8_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
err=TIFFReadDirEntryCheckRangeByteLong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
uint8_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
err=TIFFReadDirEntryCheckRangeByteSlong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
uint8_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeByteLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
uint8_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeByteSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint8_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
int8_t* data;
switch (direntry->tdir_type)
{
case TIFF_UNDEFINED:
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_UNDEFINED:
case TIFF_BYTE:
{
uint8_t* m;
uint32_t n;
m=(uint8_t*)origdata;
for (n=0; n<count; n++)
{
err=TIFFReadDirEntryCheckRangeSbyteByte(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(int8_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SBYTE:
*value=(int8_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
data=(int8_t*)_TIFFmalloc(count);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_SHORT:
{
uint16_t* ma;
int8_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
err=TIFFReadDirEntryCheckRangeSbyteShort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
int8_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
int8_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
err=TIFFReadDirEntryCheckRangeSbyteLong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
int8_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
int8_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeSbyteLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
int8_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int8_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
uint16_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_SHORT:
*value=(uint16_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfShort(*value,count);
return(TIFFReadDirEntryErrOk);
case TIFF_SSHORT:
{
int16_t* m;
uint32_t n;
m=(int16_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)m);
err=TIFFReadDirEntryCheckRangeShortSshort(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(uint16_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
}
data=(uint16_t*)_TIFFmalloc(count * 2);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
uint16_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(uint16_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
uint16_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
err=TIFFReadDirEntryCheckRangeShortSbyte(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint16_t)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
uint16_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
err=TIFFReadDirEntryCheckRangeShortLong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint16_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
uint16_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
err=TIFFReadDirEntryCheckRangeShortSlong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint16_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
uint16_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeShortLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint16_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
uint16_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeShortSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint16_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
int16_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_SHORT:
{
uint16_t* m;
uint32_t n;
m=(uint16_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(m);
err=TIFFReadDirEntryCheckRangeSshortShort(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(int16_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SSHORT:
*value=(int16_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfShort((uint16_t*)(*value), count);
return(TIFFReadDirEntryErrOk);
}
data=(int16_t*)_TIFFmalloc(count * 2);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
int16_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int16_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
int16_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int16_t)(*ma++);
}
break;
case TIFF_LONG:
{
uint32_t* ma;
int16_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
err=TIFFReadDirEntryCheckRangeSshortLong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int16_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
int16_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
err=TIFFReadDirEntryCheckRangeSshortSlong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int16_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
int16_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeSshortLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int16_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
int16_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int16_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
uint32_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_LONG:
*value=(uint32_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong(*value,count);
return(TIFFReadDirEntryErrOk);
case TIFF_SLONG:
{
int32_t* m;
uint32_t n;
m=(int32_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)m);
err=TIFFReadDirEntryCheckRangeLongSlong(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(uint32_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
}
data=(uint32_t*)_TIFFmalloc(count * 4);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
uint32_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(uint32_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
uint32_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
err=TIFFReadDirEntryCheckRangeLongSbyte(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint32_t)(*ma++);
}
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
uint32_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(uint32_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
uint32_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
err=TIFFReadDirEntryCheckRangeLongSshort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint32_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
uint32_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeLongLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint32_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
uint32_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeLongSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint32_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
int32_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_LONG:
{
uint32_t* m;
uint32_t n;
m=(uint32_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)m);
err=TIFFReadDirEntryCheckRangeSlongLong(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(int32_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG:
*value=(int32_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong((uint32_t*)(*value), count);
return(TIFFReadDirEntryErrOk);
}
data=(int32_t*)_TIFFmalloc(count * 4);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
int32_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int32_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
int32_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int32_t)(*ma++);
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
int32_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(int32_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
int32_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
*mb++=(int32_t)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
int32_t* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
err=TIFFReadDirEntryCheckRangeSlongLong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int32_t)(*ma++);
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
int32_t* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(int32_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8ArrayWithLimit(
TIFF* tif, TIFFDirEntry* direntry, uint64_t** value, uint64_t maxcount)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
uint64_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArrayWithLimit(tif,direntry,&count,8,&origdata,maxcount);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_LONG8:
*value=(uint64_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong8(*value,count);
return(TIFFReadDirEntryErrOk);
case TIFF_SLONG8:
{
int64_t* m;
uint32_t n;
m=(int64_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)m);
err=TIFFReadDirEntryCheckRangeLong8Slong8(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(uint64_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
}
data=(uint64_t*)_TIFFmalloc(count * 8);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
uint64_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(uint64_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
uint64_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
err=TIFFReadDirEntryCheckRangeLong8Sbyte(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint64_t)(*ma++);
}
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
uint64_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(uint64_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
uint64_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint64_t)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
uint64_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
*mb++=(uint64_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
uint64_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
err=TIFFReadDirEntryCheckRangeLong8Slong(*ma);
if (err!=TIFFReadDirEntryErrOk)
break;
*mb++=(uint64_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(data);
return(err);
}
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value)
{
return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, ~((uint64_t)0));
}
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
int64_t* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_LONG8:
{
uint64_t* m;
uint32_t n;
m=(uint64_t*)origdata;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(m);
err=TIFFReadDirEntryCheckRangeSlong8Long8(*m);
if (err!=TIFFReadDirEntryErrOk)
{
_TIFFfree(origdata);
return(err);
}
m++;
}
*value=(int64_t*)origdata;
return(TIFFReadDirEntryErrOk);
}
case TIFF_SLONG8:
*value=(int64_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong8((uint64_t*)(*value), count);
return(TIFFReadDirEntryErrOk);
}
data=(int64_t*)_TIFFmalloc(count * 8);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
int64_t* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int64_t)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
int64_t* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(int64_t)(*ma++);
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
int64_t* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(int64_t)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
int64_t* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
*mb++=(int64_t)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
int64_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
*mb++=(int64_t)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
int64_t* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
*mb++=(int64_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
float* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
case TIFF_RATIONAL:
case TIFF_SRATIONAL:
case TIFF_FLOAT:
case TIFF_DOUBLE:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_FLOAT:
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong((uint32_t*)origdata, count);
TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata);
*value=(float*)origdata;
return(TIFFReadDirEntryErrOk);
}
data=(float*)_TIFFmalloc(count*sizeof(float));
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
float* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(float)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
float* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(float)(*ma++);
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
float* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(float)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
float* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
*mb++=(float)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
float* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
*mb++=(float)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
float* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
*mb++=(float)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
float* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
#if defined(__WIN32__) && (_MSC_VER < 1500)
/*
* XXX: MSVC 6.0 does not support
* conversion of 64-bit integers into
* floating point values.
*/
*mb++ = _TIFFUInt64ToFloat(*ma++);
#else
*mb++ = (float)(*ma++);
#endif
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
float* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
*mb++=(float)(*ma++);
}
}
break;
case TIFF_RATIONAL:
{
uint32_t* ma;
uint32_t maa;
uint32_t mab;
float* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
maa=*ma++;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
mab=*ma++;
if (mab==0)
*mb++=0.0;
else
*mb++=(float)maa/(float)mab;
}
}
break;
case TIFF_SRATIONAL:
{
uint32_t* ma;
int32_t maa;
uint32_t mab;
float* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
maa=*(int32_t*)ma;
ma++;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
mab=*ma++;
if (mab==0)
*mb++=0.0;
else
*mb++=(float)maa/(float)mab;
}
}
break;
case TIFF_DOUBLE:
{
double* ma;
float* mb;
uint32_t n;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong8((uint64_t*)origdata, count);
TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
ma=(double*)origdata;
mb=data;
for (n=0; n<count; n++)
{
double val = *ma++;
if( val > FLT_MAX )
val = FLT_MAX;
else if( val < -FLT_MAX )
val = -FLT_MAX;
*mb++=(float)val;
}
}
break;
}
_TIFFfree(origdata);
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
double* data;
switch (direntry->tdir_type)
{
case TIFF_BYTE:
case TIFF_SBYTE:
case TIFF_SHORT:
case TIFF_SSHORT:
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_LONG8:
case TIFF_SLONG8:
case TIFF_RATIONAL:
case TIFF_SRATIONAL:
case TIFF_FLOAT:
case TIFF_DOUBLE:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_DOUBLE:
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong8((uint64_t*)origdata, count);
TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
*value=(double*)origdata;
return(TIFFReadDirEntryErrOk);
}
data=(double*)_TIFFmalloc(count*sizeof(double));
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_BYTE:
{
uint8_t* ma;
double* mb;
uint32_t n;
ma=(uint8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(double)(*ma++);
}
break;
case TIFF_SBYTE:
{
int8_t* ma;
double* mb;
uint32_t n;
ma=(int8_t*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(double)(*ma++);
}
break;
case TIFF_SHORT:
{
uint16_t* ma;
double* mb;
uint32_t n;
ma=(uint16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(ma);
*mb++=(double)(*ma++);
}
}
break;
case TIFF_SSHORT:
{
int16_t* ma;
double* mb;
uint32_t n;
ma=(int16_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
*mb++=(double)(*ma++);
}
}
break;
case TIFF_LONG:
{
uint32_t* ma;
double* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
*mb++=(double)(*ma++);
}
}
break;
case TIFF_SLONG:
{
int32_t* ma;
double* mb;
uint32_t n;
ma=(int32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
*mb++=(double)(*ma++);
}
}
break;
case TIFF_LONG8:
{
uint64_t* ma;
double* mb;
uint32_t n;
ma=(uint64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(ma);
#if defined(__WIN32__) && (_MSC_VER < 1500)
/*
* XXX: MSVC 6.0 does not support
* conversion of 64-bit integers into
* floating point values.
*/
*mb++ = _TIFFUInt64ToDouble(*ma++);
#else
*mb++ = (double)(*ma++);
#endif
}
}
break;
case TIFF_SLONG8:
{
int64_t* ma;
double* mb;
uint32_t n;
ma=(int64_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
*mb++=(double)(*ma++);
}
}
break;
case TIFF_RATIONAL:
{
uint32_t* ma;
uint32_t maa;
uint32_t mab;
double* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
maa=*ma++;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
mab=*ma++;
if (mab==0)
*mb++=0.0;
else
*mb++=(double)maa/(double)mab;
}
}
break;
case TIFF_SRATIONAL:
{
uint32_t* ma;
int32_t maa;
uint32_t mab;
double* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
maa=*(int32_t*)ma;
ma++;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
mab=*ma++;
if (mab==0)
*mb++=0.0;
else
*mb++=(double)maa/(double)mab;
}
}
break;
case TIFF_FLOAT:
{
float* ma;
double* mb;
uint32_t n;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong((uint32_t*)origdata, count);
TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata);
ma=(float*)origdata;
mb=data;
for (n=0; n<count; n++)
*mb++=(double)(*ma++);
}
break;
}
_TIFFfree(origdata);
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value)
{
enum TIFFReadDirEntryErr err;
uint32_t count;
void* origdata;
uint64_t* data;
switch (direntry->tdir_type)
{
case TIFF_LONG:
case TIFF_LONG8:
case TIFF_IFD:
case TIFF_IFD8:
break;
default:
return(TIFFReadDirEntryErrType);
}
err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{
*value=0;
return(err);
}
switch (direntry->tdir_type)
{
case TIFF_LONG8:
case TIFF_IFD8:
*value=(uint64_t*)origdata;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong8(*value,count);
return(TIFFReadDirEntryErrOk);
}
data=(uint64_t*)_TIFFmalloc(count * 8);
if (data==0)
{
_TIFFfree(origdata);
return(TIFFReadDirEntryErrAlloc);
}
switch (direntry->tdir_type)
{
case TIFF_LONG:
case TIFF_IFD:
{
uint32_t* ma;
uint64_t* mb;
uint32_t n;
ma=(uint32_t*)origdata;
mb=data;
for (n=0; n<count; n++)
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(ma);
*mb++=(uint64_t)(*ma++);
}
}
break;
}
_TIFFfree(origdata);
*value=data;
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value)
{
enum TIFFReadDirEntryErr err;
uint16_t* m;
uint16_t* na;
uint16_t nb;
if (direntry->tdir_count<(uint64_t)tif->tif_dir.td_samplesperpixel)
return(TIFFReadDirEntryErrCount);
err=TIFFReadDirEntryShortArray(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk || m == NULL)
return(err);
na=m;
nb=tif->tif_dir.td_samplesperpixel;
*value=*na++;
nb--;
while (nb>0)
{
if (*na++!=*value)
{
err=TIFFReadDirEntryErrPsdif;
break;
}
nb--;
}
_TIFFfree(m);
return(err);
}
#if 0
static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
enum TIFFReadDirEntryErr err;
double* m;
double* na;
uint16_t nb;
if (direntry->tdir_count<(uint64_t)tif->tif_dir.td_samplesperpixel)
return(TIFFReadDirEntryErrCount);
err=TIFFReadDirEntryDoubleArray(tif,direntry,&m);
if (err!=TIFFReadDirEntryErrOk)
return(err);
na=m;
nb=tif->tif_dir.td_samplesperpixel;
*value=*na++;
nb--;
while (nb>0)
{
if (*na++!=*value)
{
err=TIFFReadDirEntryErrPsdif;
break;
}
nb--;
}
_TIFFfree(m);
return(err);
}
#endif
static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value)
{
(void) tif;
*value=*(uint8_t*)(&direntry->tdir_offset);
}
static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8_t* value)
{
(void) tif;
*value=*(int8_t*)(&direntry->tdir_offset);
}
static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value)
{
*value = direntry->tdir_offset.toff_short;
/* *value=*(uint16_t*)(&direntry->tdir_offset); */
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort(value);
}
static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16_t* value)
{
*value=*(int16_t*)(&direntry->tdir_offset);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)value);
}
static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value)
{
*value=*(uint32_t*)(&direntry->tdir_offset);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(value);
}
static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32_t* value)
{
*value=*(int32_t*)(&direntry->tdir_offset);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)value);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value)
{
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,value);
if (err!=TIFFReadDirEntryErrOk)
return(err);
}
else
*value = direntry->tdir_offset.toff_long8;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(value);
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64_t* value)
{
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,value);
if (err!=TIFFReadDirEntryErrOk)
return(err);
}
else
*value=*(int64_t*)(&direntry->tdir_offset);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)value);
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
UInt64Aligned_t m;
assert(sizeof(double)==8);
assert(sizeof(uint64_t) == 8);
assert(sizeof(uint32_t) == 4);
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,m.i);
if (err!=TIFFReadDirEntryErrOk)
return(err);
}
else
m.l = direntry->tdir_offset.toff_long8;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong(m.i,2);
/* Not completely sure what we should do when m.i[1]==0, but some */
/* sanitizers do not like division by 0.0: */
/* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */
if (m.i[0]==0 || m.i[1]==0)
*value=0.0;
else
*value=(double)m.i[0]/(double)m.i[1];
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
UInt64Aligned_t m;
assert(sizeof(double)==8);
assert(sizeof(uint64_t) == 8);
assert(sizeof(int32_t) == 4);
assert(sizeof(uint32_t) == 4);
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,m.i);
if (err!=TIFFReadDirEntryErrOk)
return(err);
}
else
m.l=direntry->tdir_offset.toff_long8;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong(m.i,2);
/* Not completely sure what we should do when m.i[1]==0, but some */
/* sanitizers do not like division by 0.0: */
/* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */
if ((int32_t)m.i[0] == 0 || m.i[1] == 0)
*value=0.0;
else
*value= (double)((int32_t)m.i[0]) / (double)m.i[1];
return(TIFFReadDirEntryErrOk);
}
static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
{
union
{
float f;
uint32_t i;
} float_union;
assert(sizeof(float)==4);
assert(sizeof(uint32_t) == 4);
assert(sizeof(float_union)==4);
float_union.i=*(uint32_t*)(&direntry->tdir_offset);
*value=float_union.f;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)value);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
assert(sizeof(double)==8);
assert(sizeof(uint64_t) == 8);
assert(sizeof(UInt64Aligned_t)==8);
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
enum TIFFReadDirEntryErr err;
uint32_t offset = direntry->tdir_offset.toff_long;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,value);
if (err!=TIFFReadDirEntryErrOk)
return(err);
}
else
{
UInt64Aligned_t uint64_union;
uint64_union.l=direntry->tdir_offset.toff_long8;
*value=uint64_union.d;
}
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)value);
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16_t value)
{
if (value>0xFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16_t value)
{
if ((value<0)||(value>0xFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32_t value)
{
if (value>0xFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32_t value)
{
if ((value<0)||(value>0xFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64_t value)
{
if (value>0xFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64_t value)
{
if ((value<0)||(value>0xFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value)
{
if (value>0x7F)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value)
{
if (value>0x7F)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value)
{
if ((value<-0x80)||(value>0x7F))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value)
{
if (value>0x7F)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value)
{
if ((value<-0x80)||(value>0x7F))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value)
{
if (value>0x7F)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value)
{
if ((value<-0x80)||(value>0x7F))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32_t value)
{
if (value>0xFFFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32_t value)
{
if ((value<0)||(value>0xFFFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64_t value)
{
if (value>0xFFFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64_t value)
{
if ((value<0)||(value>0xFFFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16_t value)
{
if (value>0x7FFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32_t value)
{
if (value>0x7FFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32_t value)
{
if ((value<-0x8000)||(value>0x7FFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value)
{
if (value>0x7FFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value)
{
if ((value<-0x8000)||(value>0x7FFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32_t value)
{
if (value<0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLongLong8(uint64_t value)
{
if (value > UINT32_MAX)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLongSlong8(int64_t value)
{
if ((value < 0) || (value > (int64_t) UINT32_MAX))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlongLong(uint32_t value)
{
if (value > 0x7FFFFFFFUL)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
/* Check that the 8-byte unsigned value can fit in a 4-byte unsigned range */
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value)
{
if (value > 0x7FFFFFFF)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
/* Check that the 8-byte signed value can fit in a 4-byte signed range */
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value)
{
if ((value < 0-((int64_t) 0x7FFFFFFF + 1)) || (value > 0x7FFFFFFF))
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value)
{
if (value < 0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value)
{
if (value < 0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Slong(int32_t value)
{
if (value < 0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value)
{
if (value < 0)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value)
{
if (value > INT64_MAX)
return(TIFFReadDirEntryErrRange);
else
return(TIFFReadDirEntryErrOk);
}
static enum TIFFReadDirEntryErr
TIFFReadDirEntryData(TIFF* tif, uint64_t offset, tmsize_t size, void* dest)
{
assert(size>0);
if (!isMapped(tif)) {
if (!SeekOK(tif,offset))
return(TIFFReadDirEntryErrIo);
if (!ReadOK(tif,dest,size))
return(TIFFReadDirEntryErrIo);
} else {
size_t ma,mb;
ma=(size_t)offset;
if((uint64_t)ma != offset ||
ma > (~(size_t)0) - (size_t)size )
{
return TIFFReadDirEntryErrIo;
}
mb=ma+size;
if (mb > (uint64_t)tif->tif_size)
return(TIFFReadDirEntryErrIo);
_TIFFmemcpy(dest,tif->tif_base+ma,size);
}
return(TIFFReadDirEntryErrOk);
}
static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover)
{
if (!recover) {
switch (err) {
case TIFFReadDirEntryErrCount:
TIFFErrorExt(tif->tif_clientdata, module,
"Incorrect count for \"%s\"",
tagname);
break;
case TIFFReadDirEntryErrType:
TIFFErrorExt(tif->tif_clientdata, module,
"Incompatible type for \"%s\"",
tagname);
break;
case TIFFReadDirEntryErrIo:
TIFFErrorExt(tif->tif_clientdata, module,
"IO error during reading of \"%s\"",
tagname);
break;
case TIFFReadDirEntryErrRange:
TIFFErrorExt(tif->tif_clientdata, module,
"Incorrect value for \"%s\"",
tagname);
break;
case TIFFReadDirEntryErrPsdif:
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot handle different values per sample for \"%s\"",
tagname);
break;
case TIFFReadDirEntryErrSizesan:
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on size of \"%s\" value failed",
tagname);
break;
case TIFFReadDirEntryErrAlloc:
TIFFErrorExt(tif->tif_clientdata, module,
"Out of memory reading of \"%s\"",
tagname);
break;
default:
assert(0); /* we should never get here */
break;
}
} else {
switch (err) {
case TIFFReadDirEntryErrCount:
TIFFWarningExt(tif->tif_clientdata, module,
"Incorrect count for \"%s\"; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrType:
TIFFWarningExt(tif->tif_clientdata, module,
"Incompatible type for \"%s\"; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrIo:
TIFFWarningExt(tif->tif_clientdata, module,
"IO error during reading of \"%s\"; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrRange:
TIFFWarningExt(tif->tif_clientdata, module,
"Incorrect value for \"%s\"; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrPsdif:
TIFFWarningExt(tif->tif_clientdata, module,
"Cannot handle different values per sample for \"%s\"; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrSizesan:
TIFFWarningExt(tif->tif_clientdata, module,
"Sanity check on size of \"%s\" value failed; tag ignored",
tagname);
break;
case TIFFReadDirEntryErrAlloc:
TIFFWarningExt(tif->tif_clientdata, module,
"Out of memory reading of \"%s\"; tag ignored",
tagname);
break;
default:
assert(0); /* we should never get here */
break;
}
}
}
/*
* Return the maximum number of color channels specified for a given photometric
* type. 0 is returned if photometric type isn't supported or no default value
* is defined by the specification.
*/
static int _TIFFGetMaxColorChannels(uint16_t photometric )
{
switch (photometric) {
case PHOTOMETRIC_PALETTE:
case PHOTOMETRIC_MINISWHITE:
case PHOTOMETRIC_MINISBLACK:
return 1;
case PHOTOMETRIC_YCBCR:
case PHOTOMETRIC_RGB:
case PHOTOMETRIC_CIELAB:
case PHOTOMETRIC_LOGLUV:
case PHOTOMETRIC_ITULAB:
case PHOTOMETRIC_ICCLAB:
return 3;
case PHOTOMETRIC_SEPARATED:
case PHOTOMETRIC_MASK:
return 4;
case PHOTOMETRIC_LOGL:
case PHOTOMETRIC_CFA:
default:
return 0;
}
}
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_t bytecount = TIFFGetStrileByteCount(tif, 0);
uint64_t offset = TIFFGetStrileOffset(tif, 0);
uint64_t filesize;
if( offset == 0 )
return 0;
if (bytecount == 0)
return 1;
if ( tif->tif_dir.td_compression != COMPRESSION_NONE )
return 0;
filesize = TIFFGetFileSize(tif);
if( offset <= filesize && bytecount > filesize - offset )
return 1;
if( tif->tif_mode == O_RDONLY )
{
uint64_t scanlinesize = TIFFScanlineSize64(tif);
if( tif->tif_dir.td_imagelength > 0 &&
scanlinesize > UINT64_MAX / tif->tif_dir.td_imagelength )
{
return 1;
}
if( bytecount < scanlinesize * tif->tif_dir.td_imagelength)
return 1;
}
return 0;
}
/*
* Read the next TIFF directory from a file and convert it to the internal
* format. We read directories sequentially.
*/
int
TIFFReadDirectory(TIFF* tif)
{
static const char module[] = "TIFFReadDirectory";
TIFFDirEntry* dir;
uint16_t dircount;
TIFFDirEntry* dp;
uint16_t di;
const TIFFField* fip;
uint32_t fii=FAILED_FII;
toff_t nextdiroff;
int bitspersample_read = FALSE;
int color_channels;
tif->tif_diroff=tif->tif_nextdiroff;
if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
return 0; /* last offset or bad offset (IFD looping) */
(*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
tif->tif_curdir++;
nextdiroff = tif->tif_nextdiroff;
dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff);
if (!dircount)
{
TIFFErrorExt(tif->tif_clientdata,module,
"Failed to read directory at offset %" PRIu64, nextdiroff);
return 0;
}
TIFFReadDirectoryCheckOrder(tif,dir,dircount);
/*
* Mark duplicates of any tag to be ignored (bugzilla 1994)
* to avoid certain pathological problems.
*/
{
TIFFDirEntry* ma;
uint16_t mb;
for (ma=dir, mb=0; mb<dircount; ma++, mb++)
{
TIFFDirEntry* na;
uint16_t nb;
for (na=ma+1, nb=mb+1; nb<dircount; na++, nb++)
{
if (ma->tdir_tag == na->tdir_tag) {
na->tdir_ignore = TRUE;
}
}
}
}
tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */
tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */
tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS;
/* free any old stuff and reinit */
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif);
/*
* Electronic Arts writes gray-scale TIFF files
* without a PlanarConfiguration directory entry.
* Thus we setup a default value here, even though
* the TIFF spec says there is no default value.
*/
TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
/*
* Setup default value and then make a pass over
* the fields to check type and tag information,
* and to extract info required to size data
* structures. A second pass is made afterwards
* to read in everything not taken in the first pass.
* But we must process the Compression tag first
* in order to merge in codec-private tag definitions (otherwise
* we may get complaints about unknown tags). However, the
* Compression tag may be dependent on the SamplesPerPixel
* tag value because older TIFF specs permitted Compression
* to be written as a SamplesPerPixel-count tag entry.
* Thus if we don't first figure out the correct SamplesPerPixel
* tag value then we may end up ignoring the Compression tag
* value because it has an incorrect count value (if the
* true value of SamplesPerPixel is not 1).
*/
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL);
if (dp)
{
if (!TIFFFetchNormalTag(tif,dp,0))
goto bad;
dp->tdir_ignore = TRUE;
}
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION);
if (dp)
{
/*
* The 5.0 spec says the Compression tag has one value, while
* earlier specs say it has one value per sample. Because of
* this, we accept the tag if one value is supplied with either
* count.
*/
uint16_t value;
enum TIFFReadDirEntryErr err;
err=TIFFReadDirEntryShort(tif,dp,&value);
if (err==TIFFReadDirEntryErrCount)
err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
if (err!=TIFFReadDirEntryErrOk)
{
TIFFReadDirEntryOutputErr(tif,err,module,"Compression",0);
goto bad;
}
if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value))
goto bad;
dp->tdir_ignore = TRUE;
}
else
{
if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE))
goto bad;
}
/*
* First real pass over the directory.
*/
for (di=0, dp=dir; di<dircount; di++, dp++)
{
if (!dp->tdir_ignore)
{
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
if (fii == FAILED_FII)
{
TIFFWarningExt(tif->tif_clientdata, module,
"Unknown field with tag %"PRIu16" (0x%"PRIx16") encountered",
dp->tdir_tag,dp->tdir_tag);
/* the following knowingly leaks the
anonymous field structure */
if (!_TIFFMergeFields(tif,
_TIFFCreateAnonField(tif,
dp->tdir_tag,
(TIFFDataType) dp->tdir_type),
1)) {
TIFFWarningExt(tif->tif_clientdata,
module,
"Registering anonymous field with tag %"PRIu16" (0x%"PRIx16") failed",
dp->tdir_tag,
dp->tdir_tag);
dp->tdir_ignore = TRUE;
} else {
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
assert(fii != FAILED_FII);
}
}
}
if (!dp->tdir_ignore)
{
fip=tif->tif_fields[fii];
if (fip->field_bit==FIELD_IGNORE)
dp->tdir_ignore = TRUE;
else
{
switch (dp->tdir_tag)
{
case TIFFTAG_STRIPOFFSETS:
case TIFFTAG_STRIPBYTECOUNTS:
case TIFFTAG_TILEOFFSETS:
case TIFFTAG_TILEBYTECOUNTS:
TIFFSetFieldBit(tif,fip->field_bit);
break;
case TIFFTAG_IMAGEWIDTH:
case TIFFTAG_IMAGELENGTH:
case TIFFTAG_IMAGEDEPTH:
case TIFFTAG_TILELENGTH:
case TIFFTAG_TILEWIDTH:
case TIFFTAG_TILEDEPTH:
case TIFFTAG_PLANARCONFIG:
case TIFFTAG_ROWSPERSTRIP:
case TIFFTAG_EXTRASAMPLES:
if (!TIFFFetchNormalTag(tif,dp,0))
goto bad;
dp->tdir_ignore = TRUE;
break;
default:
if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) )
dp->tdir_ignore = TRUE;
break;
}
}
}
}
/*
* XXX: OJPEG hack.
* If a) compression is OJPEG, b) planarconfig tag says it's separate,
* c) strip offsets/bytecounts tag are both present and
* d) both contain exactly one value, then we consistently find
* that the buggy implementation of the buggy compression scheme
* matches contig planarconfig best. So we 'fix-up' the tag here
*/
if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&&
(tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE))
{
if (!_TIFFFillStriles(tif))
goto bad;
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS);
if ((dp!=0)&&(dp->tdir_count==1))
{
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,
TIFFTAG_STRIPBYTECOUNTS);
if ((dp!=0)&&(dp->tdir_count==1))
{
tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG;
TIFFWarningExt(tif->tif_clientdata,module,
"Planarconfig tag value assumed incorrect, "
"assuming data is contig instead of chunky");
}
}
}
/*
* Allocate directory structure and setup defaults.
*/
if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
{
MissingRequired(tif,"ImageLength");
goto bad;
}
/*
* Setup appropriate structures (by strip or by tile)
*/
if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
tif->tif_flags &= ~TIFF_ISTILED;
} else {
tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
tif->tif_flags |= TIFF_ISTILED;
}
if (!tif->tif_dir.td_nstrips) {
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot handle zero number of %s",
isTiled(tif) ? "tiles" : "strips");
goto bad;
}
tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
#ifdef OJPEG_SUPPORT
if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
(isTiled(tif)==0) &&
(tif->tif_dir.td_nstrips==1)) {
/*
* XXX: OJPEG hack.
* If a) compression is OJPEG, b) it's not a tiled TIFF,
* and c) the number of strips is 1,
* then we tolerate the absence of stripoffsets tag,
* because, presumably, all required data is in the
* JpegInterchangeFormat stream.
*/
TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
} else
#endif
{
MissingRequired(tif,
isTiled(tif) ? "TileOffsets" : "StripOffsets");
goto bad;
}
}
/*
* Second pass: extract other information.
*/
for (di=0, dp=dir; di<dircount; di++, dp++)
{
if (!dp->tdir_ignore) {
switch (dp->tdir_tag)
{
case TIFFTAG_MINSAMPLEVALUE:
case TIFFTAG_MAXSAMPLEVALUE:
case TIFFTAG_BITSPERSAMPLE:
case TIFFTAG_DATATYPE:
case TIFFTAG_SAMPLEFORMAT:
/*
* The MinSampleValue, MaxSampleValue, BitsPerSample
* DataType and SampleFormat tags are supposed to be
* written as one value/sample, but some vendors
* incorrectly write one value only -- so we accept
* that as well (yuck). Other vendors write correct
* value for NumberOfSamples, but incorrect one for
* BitsPerSample and friends, and we will read this
* too.
*/
{
uint16_t value;
enum TIFFReadDirEntryErr err;
err=TIFFReadDirEntryShort(tif,dp,&value);
if (err==TIFFReadDirEntryErrCount)
err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
if (err!=TIFFReadDirEntryErrOk)
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
goto bad;
}
if (!TIFFSetField(tif,dp->tdir_tag,value))
goto bad;
if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE )
bitspersample_read = TRUE;
}
break;
case TIFFTAG_SMINSAMPLEVALUE:
case TIFFTAG_SMAXSAMPLEVALUE:
{
double *data = NULL;
enum TIFFReadDirEntryErr err;
uint32_t saved_flags;
int m;
if (dp->tdir_count != (uint64_t)tif->tif_dir.td_samplesperpixel)
err = TIFFReadDirEntryErrCount;
else
err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
if (err!=TIFFReadDirEntryErrOk)
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
goto bad;
}
saved_flags = tif->tif_flags;
tif->tif_flags |= TIFF_PERSAMPLE;
m = TIFFSetField(tif,dp->tdir_tag,data);
tif->tif_flags = saved_flags;
_TIFFfree(data);
if (!m)
goto bad;
}
break;
case TIFFTAG_STRIPOFFSETS:
case TIFFTAG_TILEOFFSETS:
switch( dp->tdir_type )
{
case TIFF_SHORT:
case TIFF_LONG:
case TIFF_LONG8:
break;
default:
/* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */
if( !(tif->tif_mode == O_RDWR &&
dp->tdir_count == 0 &&
dp->tdir_type == 0 &&
dp->tdir_offset.toff_long8 == 0) )
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFWarningExt(tif->tif_clientdata,module,
"Invalid data type for tag %s",
fip ? fip->field_name : "unknown tagname");
}
break;
}
_TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
dp, sizeof(TIFFDirEntry) );
break;
case TIFFTAG_STRIPBYTECOUNTS:
case TIFFTAG_TILEBYTECOUNTS:
switch( dp->tdir_type )
{
case TIFF_SHORT:
case TIFF_LONG:
case TIFF_LONG8:
break;
default:
/* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */
if( !(tif->tif_mode == O_RDWR &&
dp->tdir_count == 0 &&
dp->tdir_type == 0 &&
dp->tdir_offset.toff_long8 == 0) )
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFWarningExt(tif->tif_clientdata,module,
"Invalid data type for tag %s",
fip ? fip->field_name : "unknown tagname");
}
break;
}
_TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
dp, sizeof(TIFFDirEntry) );
break;
case TIFFTAG_COLORMAP:
case TIFFTAG_TRANSFERFUNCTION:
{
enum TIFFReadDirEntryErr err;
uint32_t countpersample;
uint32_t countrequired;
uint32_t incrementpersample;
uint16_t* value=NULL;
/* It would be dangerous to instantiate those tag values */
/* since if td_bitspersample has not yet been read (due to */
/* unordered tags), it could be read afterwards with a */
/* values greater than the default one (1), which may cause */
/* crashes in user code */
if( !bitspersample_read )
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFWarningExt(tif->tif_clientdata,module,
"Ignoring %s since BitsPerSample tag not found",
fip ? fip->field_name : "unknown tagname");
continue;
}
/* ColorMap or TransferFunction for high bit */
/* depths do not make much sense and could be */
/* used as a denial of service vector */
if (tif->tif_dir.td_bitspersample > 24)
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFWarningExt(tif->tif_clientdata,module,
"Ignoring %s because BitsPerSample=%"PRIu16">24",
fip ? fip->field_name : "unknown tagname",
tif->tif_dir.td_bitspersample);
continue;
}
countpersample=(1U<<tif->tif_dir.td_bitspersample);
if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64_t)countpersample))
{
countrequired=countpersample;
incrementpersample=0;
}
else
{
countrequired=3*countpersample;
incrementpersample=countpersample;
}
if (dp->tdir_count!=(uint64_t)countrequired)
err=TIFFReadDirEntryErrCount;
else
err=TIFFReadDirEntryShortArray(tif,dp,&value);
if (err!=TIFFReadDirEntryErrOk)
{
fip = TIFFFieldWithTag(tif,dp->tdir_tag);
TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
}
else
{
TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
_TIFFfree(value);
}
}
break;
/* BEGIN REV 4.0 COMPATIBILITY */
case TIFFTAG_OSUBFILETYPE:
{
uint16_t valueo;
uint32_t value;
if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk)
{
switch (valueo)
{
case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break;
case OFILETYPE_PAGE: value=FILETYPE_PAGE; break;
default: value=0; break;
}
if (value!=0)
TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value);
}
}
break;
/* END REV 4.0 COMPATIBILITY */
default:
(void) TIFFFetchNormalTag(tif, dp, TRUE);
break;
}
} /* -- if (!dp->tdir_ignore) */
} /* -- for-loop -- */
if( tif->tif_mode == O_RDWR &&
tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
{
/* Directory typically created with TIFFDeferStrileArrayWriting() */
TIFFSetupStrips(tif);
}
else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
{
if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
{
if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
tif->tif_dir.td_nstrips,
&tif->tif_dir.td_stripoffset_p))
{
goto bad;
}
}
if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
{
if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
tif->tif_dir.td_nstrips,
&tif->tif_dir.td_stripbytecount_p))
{
goto bad;
}
}
}
/*
* OJPEG hack:
* - If a) compression is OJPEG, and b) photometric tag is missing,
* then we consistently find that photometric should be YCbCr
* - If a) compression is OJPEG, and b) photometric tag says it's RGB,
* then we consistently find that the buggy implementation of the
* buggy compression scheme matches photometric YCbCr instead.
* - If a) compression is OJPEG, and b) bitspersample tag is missing,
* then we consistently find bitspersample should be 8.
* - If a) compression is OJPEG, b) samplesperpixel tag is missing,
* and c) photometric is RGB or YCbCr, then we consistently find
* samplesperpixel should be 3
* - If a) compression is OJPEG, b) samplesperpixel tag is missing,
* and c) photometric is MINISWHITE or MINISBLACK, then we consistently
* find samplesperpixel should be 3
*/
if (tif->tif_dir.td_compression==COMPRESSION_OJPEG)
{
if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
{
TIFFWarningExt(tif->tif_clientdata, module,
"Photometric tag is missing, assuming data is YCbCr");
if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR))
goto bad;
}
else if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
{
tif->tif_dir.td_photometric=PHOTOMETRIC_YCBCR;
TIFFWarningExt(tif->tif_clientdata, module,
"Photometric tag value assumed incorrect, "
"assuming data is YCbCr instead of RGB");
}
if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
{
TIFFWarningExt(tif->tif_clientdata,module,
"BitsPerSample tag is missing, assuming 8 bits per sample");
if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8))
goto bad;
}
if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
{
if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
{
TIFFWarningExt(tif->tif_clientdata,module,
"SamplesPerPixel tag is missing, "
"assuming correct SamplesPerPixel value is 3");
if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
goto bad;
}
if (tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)
{
TIFFWarningExt(tif->tif_clientdata,module,
"SamplesPerPixel tag is missing, "
"applying correct SamplesPerPixel value of 3");
if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
goto bad;
}
else if ((tif->tif_dir.td_photometric==PHOTOMETRIC_MINISWHITE)
|| (tif->tif_dir.td_photometric==PHOTOMETRIC_MINISBLACK))
{
/*
* SamplesPerPixel tag is missing, but is not required
* by spec. Assume correct SamplesPerPixel value of 1.
*/
if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1))
goto bad;
}
}
}
/*
* Make sure all non-color channels are extrasamples.
* If it's not the case, define them as such.
*/
color_channels = _TIFFGetMaxColorChannels(tif->tif_dir.td_photometric);
if (color_channels && tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples > color_channels) {
uint16_t old_extrasamples;
uint16_t *new_sampleinfo;
TIFFWarningExt(tif->tif_clientdata,module, "Sum of Photometric type-related "
"color channels and ExtraSamples doesn't match SamplesPerPixel. "
"Defining non-color channels as ExtraSamples.");
old_extrasamples = tif->tif_dir.td_extrasamples;
tif->tif_dir.td_extrasamples = (uint16_t) (tif->tif_dir.td_samplesperpixel - color_channels);
// sampleinfo should contain information relative to these new extra samples
new_sampleinfo = (uint16_t*) _TIFFcalloc(tif->tif_dir.td_extrasamples, sizeof(uint16_t));
if (!new_sampleinfo) {
TIFFErrorExt(tif->tif_clientdata, module, "Failed to allocate memory for "
"temporary new sampleinfo array "
"(%"PRIu16" 16 bit elements)",
tif->tif_dir.td_extrasamples);
goto bad;
}
memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, old_extrasamples * sizeof(uint16_t));
_TIFFsetShortArray(&tif->tif_dir.td_sampleinfo, new_sampleinfo, tif->tif_dir.td_extrasamples);
_TIFFfree(new_sampleinfo);
}
/*
* Verify Palette image has a Colormap.
*/
if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE &&
!TIFFFieldSet(tif, FIELD_COLORMAP)) {
if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3)
tif->tif_dir.td_photometric = PHOTOMETRIC_RGB;
else if (tif->tif_dir.td_bitspersample>=8)
tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK;
else {
MissingRequired(tif, "Colormap");
goto bad;
}
}
/*
* OJPEG hack:
* We do no further messing with strip/tile offsets/bytecounts in OJPEG
* TIFFs
*/
if (tif->tif_dir.td_compression!=COMPRESSION_OJPEG)
{
/*
* Attempt to deal with a missing StripByteCounts tag.
*/
if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
/*
* Some manufacturers violate the spec by not giving
* the size of the strips. In this case, assume there
* is one uncompressed strip of data.
*/
if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG &&
tif->tif_dir.td_nstrips > 1) ||
(tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE &&
tif->tif_dir.td_nstrips != (uint32_t)tif->tif_dir.td_samplesperpixel)) {
MissingRequired(tif, "StripByteCounts");
goto bad;
}
TIFFWarningExt(tif->tif_clientdata, module,
"TIFF directory is missing required "
"\"StripByteCounts\" field, calculating from imagelength");
if (EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
} else if (tif->tif_dir.td_nstrips == 1
&& !(tif->tif_flags&TIFF_ISTILED)
&& ByteCountLooksBad(tif)) {
/*
* XXX: Plexus (and others) sometimes give a value of
* zero for a tag when they don't know what the
* correct value is! Try and handle the simple case
* of estimating the size of a one strip image.
*/
TIFFWarningExt(tif->tif_clientdata, module,
"Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength");
if(EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
} 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
&& 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
* StripOffset array, for example). Catch this case
* here.
*
* We avoid this check if deferring strile loading
* as it would always force us to load the strip/tile
* information.
*/
TIFFWarningExt(tif->tif_clientdata, module,
"Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength");
if (EstimateStripByteCounts(tif, dir, dircount) < 0)
goto bad;
}
}
if (dir)
{
_TIFFfree(dir);
dir=NULL;
}
if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
{
if (tif->tif_dir.td_bitspersample>=16)
tif->tif_dir.td_maxsamplevalue=0xFFFF;
else
tif->tif_dir.td_maxsamplevalue = (uint16_t)((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 (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) && tif->tif_dir.td_nstrips > 1) {
uint32_t strip;
tif->tif_dir.td_stripbytecountsorted = 1;
for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
if (TIFFGetStrileOffset(tif, strip - 1) >
TIFFGetStrileOffset(tif, strip)) {
tif->tif_dir.td_stripbytecountsorted = 0;
break;
}
}
}
#endif
/*
* An opportunity for compression mode dependent tag fixup
*/
(*tif->tif_fixuptags)(tif);
/*
* Some manufacturers make life difficult by writing
* large amounts of uncompressed data as a single strip.
* This is contrary to the recommendations of the spec.
* The following makes an attempt at breaking such images
* into strips closer to the recommended 8k bytes. A
* side effect, however, is that the RowsPerStrip tag
* value may be changed.
*/
if ((tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&&
(tif->tif_dir.td_nstrips==1)&&
(tif->tif_dir.td_compression==COMPRESSION_NONE)&&
((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP))
{
ChopUpSingleUncompressedStrip(tif);
}
/* There are also uncompressed striped files with strips larger than */
/* 2 GB, which make them unfriendly with a lot of code. If possible, */
/* try to expose smaller "virtual" strips. */
if( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG &&
tif->tif_dir.td_compression == COMPRESSION_NONE &&
(tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP &&
TIFFStripSize64(tif) > 0x7FFFFFFFUL )
{
TryChopUpUncompressedBigTiff(tif);
}
/*
* Clear the dirty directory flag.
*/
tif->tif_flags &= ~TIFF_DIRTYDIRECT;
tif->tif_flags &= ~TIFF_DIRTYSTRIP;
/*
* Reinitialize i/o since we are starting on a new directory.
*/
tif->tif_row = (uint32_t) -1;
tif->tif_curstrip = (uint32_t) -1;
tif->tif_col = (uint32_t) -1;
tif->tif_curtile = (uint32_t) -1;
tif->tif_tilesize = (tmsize_t) -1;
tif->tif_scanlinesize = TIFFScanlineSize(tif);
if (!tif->tif_scanlinesize) {
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot handle zero scanline size");
return (0);
}
if (isTiled(tif)) {
tif->tif_tilesize = TIFFTileSize(tif);
if (!tif->tif_tilesize) {
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot handle zero tile size");
return (0);
}
} else {
if (!TIFFStripSize(tif)) {
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot handle zero strip size");
return (0);
}
}
return (1);
bad:
if (dir)
_TIFFfree(dir);
return (0);
}
static void
TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount)
{
static const char module[] = "TIFFReadDirectoryCheckOrder";
uint16_t m;
uint16_t n;
TIFFDirEntry* o;
m=0;
for (n=0, o=dir; n<dircount; n++, o++)
{
if (o->tdir_tag<m)
{
TIFFWarningExt(tif->tif_clientdata,module,
"Invalid TIFF directory; tags are not sorted in ascending order");
break;
}
m=o->tdir_tag+1;
}
}
static TIFFDirEntry*
TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount, uint16_t tagid)
{
TIFFDirEntry* m;
uint16_t n;
(void) tif;
for (m=dir, n=0; n<dircount; m++, n++)
{
if (m->tdir_tag==tagid)
return(m);
}
return(0);
}
static void
TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t* fii)
{
int32_t ma,mb,mc;
ma=-1;
mc=(int32_t)tif->tif_nfields;
while (1)
{
if (ma+1==mc)
{
*fii = FAILED_FII;
return;
}
mb=(ma+mc)/2;
if (tif->tif_fields[mb]->field_tag==(uint32_t)tagid)
break;
if (tif->tif_fields[mb]->field_tag<(uint32_t)tagid)
ma=mb;
else
mc=mb;
}
while (1)
{
if (mb==0)
break;
if (tif->tif_fields[mb-1]->field_tag!=(uint32_t)tagid)
break;
mb--;
}
*fii=mb;
}
/*
* Read custom directory from the arbitrary offset.
* The code is very similar to TIFFReadDirectory().
*/
int
TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
const TIFFFieldArray* infoarray)
{
static const char module[] = "TIFFReadCustomDirectory";
TIFFDirEntry* dir;
uint16_t dircount;
TIFFDirEntry* dp;
uint16_t di;
const TIFFField* fip;
uint32_t fii;
(*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
_TIFFSetupFields(tif, infoarray);
dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL);
if (!dircount)
{
TIFFErrorExt(tif->tif_clientdata,module,
"Failed to read custom directory at offset %" PRIu64,diroff);
return 0;
}
TIFFFreeDirectory(tif);
_TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory));
TIFFReadDirectoryCheckOrder(tif,dir,dircount);
for (di=0, dp=dir; di<dircount; di++, dp++)
{
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
if (fii == FAILED_FII)
{
TIFFWarningExt(tif->tif_clientdata, module,
"Unknown field with tag %"PRIu16" (0x%"PRIx16") encountered",
dp->tdir_tag, dp->tdir_tag);
if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif,
dp->tdir_tag,
(TIFFDataType) dp->tdir_type),
1)) {
TIFFWarningExt(tif->tif_clientdata, module,
"Registering anonymous field with tag %"PRIu16" (0x%"PRIx16") failed",
dp->tdir_tag, dp->tdir_tag);
dp->tdir_ignore = TRUE;
} else {
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
assert( fii != FAILED_FII );
}
}
if (!dp->tdir_ignore)
{
fip=tif->tif_fields[fii];
if (fip->field_bit==FIELD_IGNORE)
dp->tdir_ignore = TRUE;
else
{
/* check data type */
while ((fip->field_type!=TIFF_ANY)&&(fip->field_type!=dp->tdir_type))
{
fii++;
if ((fii==tif->tif_nfields)||
(tif->tif_fields[fii]->field_tag!=(uint32_t)dp->tdir_tag))
{
fii=0xFFFF;
break;
}
fip=tif->tif_fields[fii];
}
if (fii==0xFFFF)
{
TIFFWarningExt(tif->tif_clientdata, module,
"Wrong data type %"PRIu16" for \"%s\"; tag ignored",
dp->tdir_type,fip->field_name);
dp->tdir_ignore = TRUE;
}
else
{
/* check count if known in advance */
if ((fip->field_readcount!=TIFF_VARIABLE)&&
(fip->field_readcount!=TIFF_VARIABLE2))
{
uint32_t expected;
if (fip->field_readcount==TIFF_SPP)
expected=(uint32_t)tif->tif_dir.td_samplesperpixel;
else
expected=(uint32_t)fip->field_readcount;
if (!CheckDirCount(tif,dp,expected))
dp->tdir_ignore = TRUE;
}
}
}
if (!dp->tdir_ignore) {
switch (dp->tdir_tag)
{
case EXIFTAG_SUBJECTDISTANCE:
(void)TIFFFetchSubjectDistance(tif, dp);
break;
default:
(void)TIFFFetchNormalTag(tif, dp, TRUE);
break;
}
} /*-- if (!dp->tdir_ignore) */
}
}
if (dir)
_TIFFfree(dir);
return 1;
}
/*
* EXIF is important special case of custom IFD, so we have a special
* function to read it.
*/
int
TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff)
{
const TIFFFieldArray* exifFieldArray;
exifFieldArray = _TIFFGetExifFields();
return TIFFReadCustomDirectory(tif, diroff, exifFieldArray);
}
/*
*--: EXIF-GPS custom directory reading as another special case of custom IFD.
*/
int
TIFFReadGPSDirectory(TIFF* tif, toff_t diroff)
{
const TIFFFieldArray* gpsFieldArray;
gpsFieldArray = _TIFFGetGpsFields();
return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray);
}
static int
EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount)
{
static const char module[] = "EstimateStripByteCounts";
TIFFDirEntry *dp;
TIFFDirectory *td = &tif->tif_dir;
uint32_t strip;
/* Do not try to load stripbytecount as we will compute it */
if( !_TIFFFillStrilesInternal( tif, 0 ) )
return -1;
if (td->td_stripbytecount_p)
_TIFFfree(td->td_stripbytecount_p);
td->td_stripbytecount_p = (uint64_t*)
_TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64_t),
"for \"StripByteCounts\" array");
if( td->td_stripbytecount_p == NULL )
return -1;
if (td->td_compression != COMPRESSION_NONE) {
uint64_t space;
uint64_t filesize;
uint16_t n;
filesize = TIFFGetFileSize(tif);
if (!(tif->tif_flags&TIFF_BIGTIFF))
space=sizeof(TIFFHeaderClassic)+2+dircount*12+4;
else
space=sizeof(TIFFHeaderBig)+8+dircount*20+8;
/* calculate amount of space used by indirect values */
for (dp = dir, n = dircount; n > 0; n--, dp++)
{
uint32_t typewidth;
uint64_t datasize;
typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
if (typewidth == 0) {
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot determine size of unknown tag type %"PRIu16,
dp->tdir_type);
return -1;
}
if( dp->tdir_count > UINT64_MAX / typewidth )
return -1;
datasize= (uint64_t)typewidth * dp->tdir_count;
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
if (datasize<=4)
datasize=0;
}
else
{
if (datasize<=8)
datasize=0;
}
if( space > UINT64_MAX - datasize )
return -1;
space+=datasize;
}
if( filesize < space )
/* we should perhaps return in error ? */
space = filesize;
else
space = filesize - space;
if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
space /= td->td_samplesperpixel;
for (strip = 0; strip < td->td_nstrips; strip++)
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
* should begin. Since a strip of data must be contiguous,
* it's safe to assume that we've overestimated the amount
* of data in the strip and trim this number back accordingly.
*/
strip--;
if (td->td_stripoffset_p[strip] > UINT64_MAX - td->td_stripbytecount_p[strip])
return -1;
if (td->td_stripoffset_p[strip]+td->td_stripbytecount_p[strip] > filesize) {
if( td->td_stripoffset_p[strip] >= filesize ) {
/* Not sure what we should in that case... */
td->td_stripbytecount_p[strip] = 0;
} else {
td->td_stripbytecount_p[strip] = filesize - td->td_stripoffset_p[strip];
}
}
} else if (isTiled(tif)) {
uint64_t bytespertile = TIFFTileSize64(tif);
for (strip = 0; strip < td->td_nstrips; strip++)
td->td_stripbytecount_p[strip] = bytespertile;
} else {
uint64_t rowbytes = TIFFScanlineSize64(tif);
uint32_t rowsperstrip = td->td_imagelength / td->td_stripsperimage;
for (strip = 0; strip < td->td_nstrips; strip++)
{
if( rowbytes > 0 && rowsperstrip > UINT64_MAX / rowbytes )
return -1;
td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip;
}
}
TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
td->td_rowsperstrip = td->td_imagelength;
return 1;
}
static void
MissingRequired(TIFF* tif, const char* tagname)
{
static const char module[] = "MissingRequired";
TIFFErrorExt(tif->tif_clientdata, module,
"TIFF directory is missing required \"%s\" field",
tagname);
}
/*
* Check the directory offset against the list of already seen directory
* offsets. This is a trick to prevent IFD looping. The one can create TIFF
* file with looped directory pointers. We will maintain a list of already
* seen directories and check every IFD offset against that list.
*/
static int
TIFFCheckDirOffset(TIFF* tif, uint64_t diroff)
{
uint16_t n;
if (diroff == 0) /* no more directories */
return 0;
if (tif->tif_dirnumber == 65535) {
TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset",
"Cannot handle more than 65535 TIFF directories");
return 0;
}
for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
if (tif->tif_dirlist[n] == diroff)
return 0;
}
tif->tif_dirnumber++;
if (tif->tif_dirlist == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) {
uint64_t* new_dirlist;
/*
* XXX: Reduce memory allocation granularity of the dirlist
* array.
*/
new_dirlist = (uint64_t*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
tif->tif_dirnumber, 2 * sizeof(uint64_t), "for IFD list");
if (!new_dirlist)
return 0;
if( tif->tif_dirnumber >= 32768 )
tif->tif_dirlistsize = 65535;
else
tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
tif->tif_dirlist = new_dirlist;
}
tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
return 1;
}
/*
* Check the count field of a directory entry against a known value. The
* caller is expected to skip/ignore the tag if there is a mismatch.
*/
static int
CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32_t count)
{
if ((uint64_t)count > dir->tdir_count) {
const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
"incorrect count for field \"%s\" (%" PRIu64 ", expecting %"PRIu32"); tag ignored",
fip ? fip->field_name : "unknown tagname",
dir->tdir_count, count);
return (0);
} else if ((uint64_t)count < dir->tdir_count) {
const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
"incorrect count for field \"%s\" (%" PRIu64 ", expecting %"PRIu32"); tag trimmed",
fip ? fip->field_name : "unknown tagname",
dir->tdir_count, count);
dir->tdir_count = count;
return (1);
}
return (1);
}
/*
* Read IFD structure from the specified offset. If the pointer to
* nextdiroff variable has been specified, read it too. Function returns a
* number of fields in the directory or 0 if failed.
*/
static uint16_t
TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir,
uint64_t *nextdiroff)
{
static const char module[] = "TIFFFetchDirectory";
void* origdir;
uint16_t dircount16;
uint32_t dirsize;
TIFFDirEntry* dir;
uint8_t* ma;
TIFFDirEntry* mb;
uint16_t n;
assert(pdir);
tif->tif_diroff = diroff;
if (nextdiroff)
*nextdiroff = 0;
if (!isMapped(tif)) {
if (!SeekOK(tif, tif->tif_diroff)) {
TIFFErrorExt(tif->tif_clientdata, module,
"%s: Seek error accessing TIFF directory",
tif->tif_name);
return 0;
}
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
if (!ReadOK(tif, &dircount16, sizeof (uint16_t))) {
TIFFErrorExt(tif->tif_clientdata, module,
"%s: Can not read TIFF directory count",
tif->tif_name);
return 0;
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&dircount16);
if (dircount16>4096)
{
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on directory count failed, this is probably not a valid IFD offset");
return 0;
}
dirsize = 12;
} else {
uint64_t dircount64;
if (!ReadOK(tif, &dircount64, sizeof (uint64_t))) {
TIFFErrorExt(tif->tif_clientdata, module,
"%s: Can not read TIFF directory count",
tif->tif_name);
return 0;
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&dircount64);
if (dircount64>4096)
{
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on directory count failed, this is probably not a valid IFD offset");
return 0;
}
dircount16 = (uint16_t)dircount64;
dirsize = 20;
}
origdir = _TIFFCheckMalloc(tif, dircount16,
dirsize, "to read TIFF directory");
if (origdir == NULL)
return 0;
if (!ReadOK(tif, origdir, (tmsize_t)(dircount16*dirsize))) {
TIFFErrorExt(tif->tif_clientdata, module,
"%.100s: Can not read TIFF directory",
tif->tif_name);
_TIFFfree(origdir);
return 0;
}
/*
* Read offset to next directory for sequential scans if
* needed.
*/
if (nextdiroff)
{
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
uint32_t nextdiroff32;
if (!ReadOK(tif, &nextdiroff32, sizeof(uint32_t)))
nextdiroff32 = 0;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&nextdiroff32);
*nextdiroff=nextdiroff32;
} else {
if (!ReadOK(tif, nextdiroff, sizeof(uint64_t)))
*nextdiroff = 0;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(nextdiroff);
}
}
} else {
tmsize_t m;
tmsize_t off;
if (tif->tif_diroff > (uint64_t)INT64_MAX)
{
TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
return(0);
}
off = (tmsize_t) tif->tif_diroff;
/*
* Check for integer overflow when validating the dir_off,
* otherwise a very high offset may cause an OOB read and
* crash the client. Make two comparisons instead of
*
* off + sizeof(uint16_t) > tif->tif_size
*
* to avoid overflow.
*/
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
m=off+sizeof(uint16_t);
if ((m<off) || (m<(tmsize_t)sizeof(uint16_t)) || (m > tif->tif_size)) {
TIFFErrorExt(tif->tif_clientdata, module,
"Can not read TIFF directory count");
return 0;
} else {
_TIFFmemcpy(&dircount16, tif->tif_base + off,
sizeof(uint16_t));
}
off += sizeof (uint16_t);
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&dircount16);
if (dircount16>4096)
{
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on directory count failed, this is probably not a valid IFD offset");
return 0;
}
dirsize = 12;
}
else
{
uint64_t dircount64;
m=off+sizeof(uint64_t);
if ((m<off) || (m<(tmsize_t)sizeof(uint64_t)) || (m > tif->tif_size)) {
TIFFErrorExt(tif->tif_clientdata, module,
"Can not read TIFF directory count");
return 0;
} else {
_TIFFmemcpy(&dircount64, tif->tif_base + off,
sizeof(uint64_t));
}
off += sizeof (uint64_t);
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&dircount64);
if (dircount64>4096)
{
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on directory count failed, this is probably not a valid IFD offset");
return 0;
}
dircount16 = (uint16_t)dircount64;
dirsize = 20;
}
if (dircount16 == 0 )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Sanity check on directory count failed, zero tag directories not supported");
return 0;
}
origdir = _TIFFCheckMalloc(tif, dircount16,
dirsize,
"to read TIFF directory");
if (origdir == NULL)
return 0;
m=off+dircount16*dirsize;
if ((m<off)||(m<(tmsize_t)(dircount16*dirsize))||(m>tif->tif_size)) {
TIFFErrorExt(tif->tif_clientdata, module,
"Can not read TIFF directory");
_TIFFfree(origdir);
return 0;
} else {
_TIFFmemcpy(origdir, tif->tif_base + off,
dircount16 * dirsize);
}
if (nextdiroff) {
off += dircount16 * dirsize;
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
uint32_t nextdiroff32;
m=off+sizeof(uint32_t);
if ((m<off) || (m<(tmsize_t)sizeof(uint32_t)) || (m > tif->tif_size))
nextdiroff32 = 0;
else
_TIFFmemcpy(&nextdiroff32, tif->tif_base + off,
sizeof (uint32_t));
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&nextdiroff32);
*nextdiroff = nextdiroff32;
}
else
{
m=off+sizeof(uint64_t);
if ((m<off) || (m<(tmsize_t)sizeof(uint64_t)) || (m > tif->tif_size))
*nextdiroff = 0;
else
_TIFFmemcpy(nextdiroff, tif->tif_base + off,
sizeof (uint64_t));
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8(nextdiroff);
}
}
}
dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16,
sizeof(TIFFDirEntry),
"to read TIFF directory");
if (dir==0)
{
_TIFFfree(origdir);
return 0;
}
ma=(uint8_t*)origdir;
mb=dir;
for (n=0; n<dircount16; n++)
{
mb->tdir_ignore = FALSE;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
mb->tdir_tag=*(uint16_t*)ma;
ma+=sizeof(uint16_t);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabShort((uint16_t*)ma);
mb->tdir_type=*(uint16_t*)ma;
ma+=sizeof(uint16_t);
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong((uint32_t*)ma);
mb->tdir_count=(uint64_t)(*(uint32_t*)ma);
ma+=sizeof(uint32_t);
mb->tdir_offset.toff_long8=0;
*(uint32_t*)(&mb->tdir_offset)=*(uint32_t*)ma;
ma+=sizeof(uint32_t);
}
else
{
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong8((uint64_t*)ma);
mb->tdir_count=TIFFReadUInt64(ma);
ma+=sizeof(uint64_t);
mb->tdir_offset.toff_long8=TIFFReadUInt64(ma);
ma+=sizeof(uint64_t);
}
mb++;
}
_TIFFfree(origdir);
*pdir = dir;
return dircount16;
}
/*
* Fetch a tag that is not handled by special case code.
*/
static int
TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
{
static const char module[] = "TIFFFetchNormalTag";
enum TIFFReadDirEntryErr err;
uint32_t fii;
const TIFFField* fip = NULL;
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
if( fii == FAILED_FII )
{
TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag",
"No definition found for tag %"PRIu16,
dp->tdir_tag);
return 0;
}
fip=tif->tif_fields[fii];
assert(fip != NULL); /* should not happen */
assert(fip->set_field_type!=TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */
assert(fip->set_field_type!=TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */
err=TIFFReadDirEntryErrOk;
switch (fip->set_field_type)
{
case TIFF_SETGET_UNDEFINED:
break;
case TIFF_SETGET_ASCII:
{
uint8_t* data;
assert(fip->field_passcount==0);
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
uint32_t mb = 0;
int n;
if (data != NULL)
{
uint8_t* ma = data;
while (mb<(uint32_t)dp->tdir_count)
{
if (*ma==0)
break;
ma++;
mb++;
}
}
if (mb+1<(uint32_t)dp->tdir_count)
TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" contains null byte in value; value incorrectly truncated during reading due to implementation limitations",fip->field_name);
else if (mb+1>(uint32_t)dp->tdir_count)
{
uint8_t* o;
TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name);
if ((uint32_t)dp->tdir_count + 1 != dp->tdir_count + 1)
o=NULL;
else
o=_TIFFmalloc((uint32_t)dp->tdir_count + 1);
if (o==NULL)
{
if (data!=NULL)
_TIFFfree(data);
return(0);
}
_TIFFmemcpy(o,data,(uint32_t)dp->tdir_count);
o[(uint32_t)dp->tdir_count]=0;
if (data!=0)
_TIFFfree(data);
data=o;
}
n=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!n)
return(0);
}
}
break;
case TIFF_SETGET_UINT8:
{
uint8_t data=0;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryByte(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_UINT16:
{
uint16_t data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryShort(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_UINT32:
{
uint32_t data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryLong(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_UINT64:
{
uint64_t data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryLong8(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_FLOAT:
{
float data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryFloat(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_DOUBLE:
{
double data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryDouble(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_IFD8:
{
uint64_t data;
assert(fip->field_readcount==1);
assert(fip->field_passcount==0);
err=TIFFReadDirEntryIfd8(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
if (!TIFFSetField(tif,dp->tdir_tag,data))
return(0);
}
}
break;
case TIFF_SETGET_UINT16_PAIR:
{
uint16_t* data;
assert(fip->field_readcount==2);
assert(fip->field_passcount==0);
if (dp->tdir_count!=2) {
TIFFWarningExt(tif->tif_clientdata,module,
"incorrect count for field \"%s\", expected 2, got %"PRIu64,
fip->field_name, dp->tdir_count);
return(0);
}
err=TIFFReadDirEntryShortArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
assert(data); /* avoid CLang static Analyzer false positive */
m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]);
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C0_UINT8:
{
uint8_t* data;
assert(fip->field_readcount>=1);
assert(fip->field_passcount==0);
if (dp->tdir_count!=(uint64_t)fip->field_readcount) {
TIFFWarningExt(tif->tif_clientdata,module,
"incorrect count for field \"%s\", expected %d, got %"PRIu64,
fip->field_name,(int) fip->field_readcount, dp->tdir_count);
return 0;
}
else
{
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C0_UINT16:
{
uint16_t* data;
assert(fip->field_readcount>=1);
assert(fip->field_passcount==0);
if (dp->tdir_count!=(uint64_t)fip->field_readcount)
/* corrupt file */;
else
{
err=TIFFReadDirEntryShortArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C0_UINT32:
{
uint32_t* data;
assert(fip->field_readcount>=1);
assert(fip->field_passcount==0);
if (dp->tdir_count!=(uint64_t)fip->field_readcount)
/* corrupt file */;
else
{
err=TIFFReadDirEntryLongArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C0_FLOAT:
{
float* data;
assert(fip->field_readcount>=1);
assert(fip->field_passcount==0);
if (dp->tdir_count!=(uint64_t)fip->field_readcount)
/* corrupt file */;
else
{
err=TIFFReadDirEntryFloatArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
/*--: Rational2Double: Extend for Double Arrays and Rational-Arrays read into Double-Arrays. */
case TIFF_SETGET_C0_DOUBLE:
{
double* data;
assert(fip->field_readcount>=1);
assert(fip->field_passcount==0);
if (dp->tdir_count!=(uint64_t)fip->field_readcount)
/* corrupt file */;
else
{
err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif,dp->tdir_tag,data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_ASCII:
{
uint8_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
{
TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
data[dp->tdir_count-1] = '\0';
}
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_UINT8:
{
uint8_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_UINT16:
{
uint16_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryShortArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_UINT32:
{
uint32_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryLongArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_UINT64:
{
uint64_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryLong8Array(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_FLOAT:
{
float* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryFloatArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_DOUBLE:
{
double* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C16_IFD8:
{
uint64_t* data;
assert(fip->field_readcount==TIFF_VARIABLE);
assert(fip->field_passcount==1);
if (dp->tdir_count>0xFFFF)
err=TIFFReadDirEntryErrCount;
else
{
err=TIFFReadDirEntryIfd8Array(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
}
break;
case TIFF_SETGET_C32_ASCII:
{
uint8_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
{
TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
data[dp->tdir_count-1] = '\0';
}
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_UINT8:
{
uint8_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryByteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_SINT8:
{
int8_t* data = NULL;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntrySbyteArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_UINT16:
{
uint16_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryShortArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_SINT16:
{
int16_t* data = NULL;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntrySshortArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_UINT32:
{
uint32_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryLongArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_SINT32:
{
int32_t* data = NULL;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntrySlongArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_UINT64:
{
uint64_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryLong8Array(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_SINT64:
{
int64_t* data = NULL;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntrySlong8Array(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_FLOAT:
{
float* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryFloatArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_DOUBLE:
{
double* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
case TIFF_SETGET_C32_IFD8:
{
uint64_t* data;
assert(fip->field_readcount==TIFF_VARIABLE2);
assert(fip->field_passcount==1);
err=TIFFReadDirEntryIfd8Array(tif,dp,&data);
if (err==TIFFReadDirEntryErrOk)
{
int m;
m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
if (data!=0)
_TIFFfree(data);
if (!m)
return(0);
}
}
break;
default:
assert(0); /* we should never get here */
break;
}
if (err!=TIFFReadDirEntryErrOk)
{
TIFFReadDirEntryOutputErr(tif,err,module,fip->field_name,recover);
return(0);
}
return(1);
}
/*
* Fetch a set of offsets or lengths.
* While this routine says "strips", in fact it's also used for tiles.
*/
static int
TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32_t nstrips, uint64_t** lpp)
{
static const char module[] = "TIFFFetchStripThing";
enum TIFFReadDirEntryErr err;
uint64_t* data;
err=TIFFReadDirEntryLong8ArrayWithLimit(tif,dir,&data,nstrips);
if (err!=TIFFReadDirEntryErrOk)
{
const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag);
TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
return(0);
}
if (dir->tdir_count<(uint64_t)nstrips)
{
uint64_t* resizeddata;
const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag);
const char* pszMax = getenv("LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT");
uint32_t max_nstrips = 1000000;
if( pszMax )
max_nstrips = (uint32_t) atoi(pszMax);
TIFFReadDirEntryOutputErr(tif,TIFFReadDirEntryErrCount,
module,
fip ? fip->field_name : "unknown tagname",
( nstrips <= max_nstrips ) );
if( nstrips > max_nstrips )
{
_TIFFfree(data);
return(0);
}
resizeddata=(uint64_t*)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t), "for strip array");
if (resizeddata==0) {
_TIFFfree(data);
return(0);
}
_TIFFmemcpy(resizeddata,data, (uint32_t)dir->tdir_count * sizeof(uint64_t));
_TIFFmemset(resizeddata+(uint32_t)dir->tdir_count, 0, (nstrips - (uint32_t)dir->tdir_count) * sizeof(uint64_t));
_TIFFfree(data);
data=resizeddata;
}
*lpp=data;
return(1);
}
/*
* Fetch and set the SubjectDistance EXIF tag.
*/
static int
TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
{
static const char module[] = "TIFFFetchSubjectDistance";
enum TIFFReadDirEntryErr err;
UInt64Aligned_t m;
m.l=0;
assert(sizeof(double)==8);
assert(sizeof(uint64_t) == 8);
assert(sizeof(uint32_t) == 4);
if (dir->tdir_count!=1)
err=TIFFReadDirEntryErrCount;
else if (dir->tdir_type!=TIFF_RATIONAL)
err=TIFFReadDirEntryErrType;
else
{
if (!(tif->tif_flags&TIFF_BIGTIFF))
{
uint32_t offset;
offset=*(uint32_t*)(&dir->tdir_offset);
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabLong(&offset);
err=TIFFReadDirEntryData(tif,offset,8,m.i);
}
else
{
m.l=dir->tdir_offset.toff_long8;
err=TIFFReadDirEntryErrOk;
}
}
if (err==TIFFReadDirEntryErrOk)
{
double n;
if (tif->tif_flags&TIFF_SWAB)
TIFFSwabArrayOfLong(m.i,2);
if (m.i[0]==0)
n=0.0;
else if (m.i[0]==0xFFFFFFFF || m.i[1]==0)
/*
* XXX: Numerator 0xFFFFFFFF means that we have infinite
* distance. Indicate that with a negative floating point
* SubjectDistance value.
*/
n=-1.0;
else
n=(double)m.i[0]/(double)m.i[1];
return(TIFFSetField(tif,dir->tdir_tag,n));
}
else
{
TIFFReadDirEntryOutputErr(tif,err,module,"SubjectDistance",TRUE);
return(0);
}
}
static void allocChoppedUpStripArrays(TIFF* tif, uint32_t nstrips,
uint64_t stripbytes, uint32_t rowsperstrip)
{
TIFFDirectory *td = &tif->tif_dir;
uint64_t bytecount;
uint64_t offset;
uint64_t last_offset;
uint64_t last_bytecount;
uint32_t i;
uint64_t *newcounts;
uint64_t *newoffsets;
offset = TIFFGetStrileOffset(tif, 0);
last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1);
last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1);
if( last_offset > UINT64_MAX - last_bytecount ||
last_offset + last_bytecount < offset )
{
return;
}
bytecount = last_offset + last_bytecount - offset;
newcounts = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t),
"for chopped \"StripByteCounts\" array");
newoffsets = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t),
"for chopped \"StripOffsets\" array");
if (newcounts == NULL || newoffsets == NULL) {
/*
* Unable to allocate new strip information, give up and use
* the original one strip information.
*/
if (newcounts != NULL)
_TIFFfree(newcounts);
if (newoffsets != NULL)
_TIFFfree(newoffsets);
return;
}
/*
* Fill the strip information arrays with new bytecounts and offsets
* that reflect the broken-up format.
*/
for (i = 0; i < nstrips; i++)
{
if (stripbytes > bytecount)
stripbytes = bytecount;
newcounts[i] = stripbytes;
newoffsets[i] = stripbytes ? offset : 0;
offset += stripbytes;
bytecount -= stripbytes;
}
/*
* Replace old single strip info with multi-strip info.
*/
td->td_stripsperimage = td->td_nstrips = nstrips;
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
_TIFFfree(td->td_stripbytecount_p);
_TIFFfree(td->td_stripoffset_p);
td->td_stripbytecount_p = newcounts;
td->td_stripoffset_p = newoffsets;
#ifdef STRIPBYTECOUNTSORTED_UNUSED
td->td_stripbytecountsorted = 1;
#endif
tif->tif_flags |= TIFF_CHOPPEDUPARRAYS;
}
/*
* Replace a single strip (tile) of uncompressed data by multiple strips
* (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for
* dealing with large images or for dealing with machines with a limited
* amount memory.
*/
static void
ChopUpSingleUncompressedStrip(TIFF* tif)
{
register TIFFDirectory *td = &tif->tif_dir;
uint64_t bytecount;
uint64_t offset;
uint32_t rowblock;
uint64_t rowblockbytes;
uint64_t stripbytes;
uint32_t nstrips;
uint32_t rowsperstrip;
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 = TIFFGetStrileByteCount(tif, 0);
assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
(!isUpSampled(tif)))
rowblock = td->td_ycbcrsubsampling[1];
else
rowblock = 1;
rowblockbytes = TIFFVTileSize64(tif, rowblock);
/*
* Make the rows hold at least one scanline, but fill specified amount
* of data if possible.
*/
if (rowblockbytes > STRIP_SIZE_DEFAULT) {
stripbytes = rowblockbytes;
rowsperstrip = rowblock;
} else if (rowblockbytes > 0 ) {
uint32_t rowblocksperstrip;
rowblocksperstrip = (uint32_t) (STRIP_SIZE_DEFAULT / rowblockbytes);
rowsperstrip = rowblocksperstrip * rowblock;
stripbytes = rowblocksperstrip * rowblockbytes;
}
else
return;
/*
* never increase the number of rows per strip
*/
if (rowsperstrip >= td->td_rowsperstrip)
return;
nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
if( nstrips == 0 )
return;
/* If we are going to allocate a lot of memory, make sure that the */
/* file is as big as needed */
if( tif->tif_mode == O_RDONLY &&
nstrips > 1000000 &&
(offset >= TIFFGetFileSize(tif) ||
stripbytes > (TIFFGetFileSize(tif) - offset) / (nstrips - 1)) )
{
return;
}
allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip);
}
/*
* Replace a file with contiguous strips > 2 GB of uncompressed data by
* multiple smaller strips. This is useful for
* dealing with large images or for dealing with machines with a limited
* amount memory.
*/
static void TryChopUpUncompressedBigTiff( TIFF* tif )
{
TIFFDirectory *td = &tif->tif_dir;
uint32_t rowblock;
uint64_t rowblockbytes;
uint32_t i;
uint64_t stripsize;
uint32_t rowblocksperstrip;
uint32_t rowsperstrip;
uint64_t stripbytes;
uint32_t nstrips;
stripsize = TIFFStripSize64(tif);
assert( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG );
assert( tif->tif_dir.td_compression == COMPRESSION_NONE );
assert( (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP );
assert( stripsize > 0x7FFFFFFFUL );
/* On a newly created file, just re-opened to be filled, we */
/* don't want strip chop to trigger as it is going to cause issues */
/* later ( StripOffsets and StripByteCounts improperly filled) . */
if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY )
return;
if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
(!isUpSampled(tif)))
rowblock = td->td_ycbcrsubsampling[1];
else
rowblock = 1;
rowblockbytes = TIFFVStripSize64(tif, rowblock);
if( rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL )
{
/* In case of file with gigantic width */
return;
}
/* Check that the strips are contiguous and of the expected size */
for( i = 0; i < td->td_nstrips; i++ )
{
if( i == td->td_nstrips - 1 )
{
if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64(
tif, td->td_imagelength - i * td->td_rowsperstrip ) )
{
return;
}
}
else
{
if( TIFFGetStrileByteCount(tif, i) != stripsize )
{
return;
}
if( i > 0 && TIFFGetStrileOffset(tif, i) !=
TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) )
{
return;
}
}
}
/* Aim for 512 MB strips (that will still be manageable by 32 bit builds */
rowblocksperstrip = (uint32_t) (512 * 1024 * 1024 / rowblockbytes);
if( rowblocksperstrip == 0 )
rowblocksperstrip = 1;
rowsperstrip = rowblocksperstrip * rowblock;
stripbytes = rowblocksperstrip * rowblockbytes;
assert( stripbytes <= 0x7FFFFFFFUL );
nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
if( nstrips == 0 )
return;
/* If we are going to allocate a lot of memory, make sure that the */
/* file is as big as needed */
if( tif->tif_mode == O_RDONLY &&
nstrips > 1000000 )
{
uint64_t last_offset = TIFFGetStrileOffset(tif, td->td_nstrips - 1);
uint64_t filesize = TIFFGetFileSize(tif);
uint64_t last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips - 1);
if( last_offset > filesize ||
last_bytecount > filesize - last_offset )
{
return;
}
}
allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip);
}
TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
static uint64_t _TIFFUnsanitizedAddUInt64AndInt(uint64_t a, int b)
{
return a + b;
}
/* 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_t* 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_t nBaseOffset;
uint64_t nOffset;
uint64_t nOffsetStartPage;
uint64_t nOffsetEndPage;
tmsize_t nToRead;
tmsize_t nRead;
uint64_t nLastStripOffset;
int iStartBefore;
int i;
const uint32_t 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_t);
}
else if( dirent->tdir_type == TIFF_LONG )
{
sizeofval = sizeof(uint32_t);
}
else if( dirent->tdir_type == TIFF_LONG8 )
{
sizeofval = sizeof(uint64_t);
}
else if( dirent->tdir_type == TIFF_SLONG8 )
{
/* Non conformant but used by some images as in */
/* https://github.com/OSGeo/gdal/issues/2165 */
sizeofval = sizeof(int64_t);
}
else
{
TIFFErrorExt(tif->tif_clientdata, module,
"Invalid type for [Strip|Tile][Offset/ByteCount] tag");
panVals[strile] = 0;
return 0;
}
sizeofvalint = (int)(sizeofval);
if( tif->tif_flags&TIFF_BIGTIFF )
{
uint64_t offset = dirent->tdir_offset.toff_long8;
if( bSwab )
TIFFSwabLong8(&offset);
nBaseOffset = offset;
}
else
{
uint32_t offset = dirent->tdir_offset.toff_long;
if( bSwab )
TIFFSwabLong(&offset);
nBaseOffset = offset;
}
/* To avoid later unsigned integer overflows */
if( nBaseOffset > (uint64_t)INT64_MAX )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot read offset/size for strile %d", strile);
panVals[strile] = 0;
return 0;
}
nOffset = nBaseOffset + sizeofval * strile;
nOffsetStartPage =
(nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE;
nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE;
if( nOffset + sizeofval > nOffsetEndPage )
nOffsetEndPage += IO_CACHE_PAGE_SIZE;
#undef IO_CACHE_PAGE_SIZE
nLastStripOffset = nBaseOffset + arraySize * sizeofval;
if( nLastStripOffset < nOffsetEndPage )
nOffsetEndPage = nLastStripOffset;
if( nOffsetStartPage >= nOffsetEndPage )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot read offset/size for strile %d", strile);
panVals[strile] = 0;
return 0;
}
if (!SeekOK(tif,nOffsetStartPage))
{
panVals[strile] = 0;
return 0;
}
nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage);
nRead = TIFFReadFile(tif, buffer, nToRead);
if( nRead < nToRead )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Cannot read offset/size for strile around ~%d", strile);
return 0;
}
iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval);
if( strile + iStartBefore < 0 )
iStartBefore = -strile;
for( i = iStartBefore;
(uint32_t)(strile + i) < arraySize &&
_TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage;
++i )
{
if( dirent->tdir_type == TIFF_SHORT )
{
uint16_t val;
memcpy(&val,
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
sizeof(val));
if( bSwab )
TIFFSwabShort(&val);
panVals[strile + i] = val;
}
else if( dirent->tdir_type == TIFF_LONG )
{
uint32_t val;
memcpy(&val,
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
sizeof(val));
if( bSwab )
TIFFSwabLong(&val);
panVals[strile + i] = val;
}
else if( dirent->tdir_type == TIFF_LONG8 )
{
uint64_t val;
memcpy(&val,
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
sizeof(val));
if( bSwab )
TIFFSwabLong8(&val);
panVals[strile + i] = val;
}
else /* if( dirent->tdir_type == TIFF_SLONG8 ) */
{
/* Non conformant data type */
int64_t val;
memcpy(&val,
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
sizeof(val));
if( bSwab )
TIFFSwabLong8((uint64_t*) &val);
panVals[strile + i] = (uint64_t) val;
}
}
return 1;
}
static int _TIFFFetchStrileValue(TIFF* tif,
uint32_t strile,
TIFFDirEntry* dirent,
uint64_t** parray)
{
static const char module[] = "_TIFFFetchStrileValue";
TIFFDirectory *td = &tif->tif_dir;
if( strile >= dirent->tdir_count )
{
return 0;
}
if( strile >= td->td_stripoffsetbyteallocsize )
{
uint32_t nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize;
uint32_t nStripArrayAllocNew;
uint64_t nArraySize64;
size_t nArraySize;
uint64_t* offsetArray;
uint64_t* bytecountArray;
if( strile > 1000000 )
{
uint64_t 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_t) )
{
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_t)sizeof(uint64_t) * 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_t*)(
_TIFFrealloc( td->td_stripoffset_p, nArraySize ) );
bytecountArray = (uint64_t*)(
_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_t) );
memset(td->td_stripbytecount_p + nStripArrayAllocBefore,
0xFF,
(td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64_t) );
}
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_t _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32_t strile,
TIFFDirEntry* dirent,
uint64_t** parray,
int *pbErr)
{
TIFFDirectory *td = &tif->tif_dir;
if( pbErr )
*pbErr = 0;
if( (tif->tif_flags&TIFF_DEFERSTRILELOAD) && !(tif->tif_flags&TIFF_CHOPPEDUPARRAYS) )
{
if( !(tif->tif_flags&TIFF_LAZYSTRILELOAD) ||
/* If the values may fit in the toff_long/toff_long8 member */
/* then use _TIFFFillStriles to simplify _TIFFFetchStrileValue */
dirent->tdir_count <= 4 )
{
if( !_TIFFFillStriles(tif) )
{
if( pbErr )
*pbErr = 1;
/* Do not return, as we want this function to always */
/* return the same value if called several times with */
/* the same arguments */
}
}
else
{
if( !_TIFFFetchStrileValue(tif, strile, dirent, parray) )
{
if( pbErr )
*pbErr = 1;
return 0;
}
}
}
if( *parray == NULL || strile >= td->td_nstrips )
{
if( pbErr )
*pbErr = 1;
return 0;
}
return (*parray)[strile];
}
/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */
uint64_t TIFFGetStrileOffset(TIFF *tif, uint32_t strile)
{
return TIFFGetStrileOffsetWithErr(tif, strile, NULL);
}
/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */
uint64_t TIFFGetStrileOffsetWithErr(TIFF *tif, uint32_t 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_t TIFFGetStrileByteCount(TIFF *tif, uint32_t strile)
{
return TIFFGetStrileByteCountWithErr(tif, strile, NULL);
}
/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */
uint64_t TIFFGetStrileByteCountWithErr(TIFF *tif, uint32_t 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 )
{
return _TIFFFillStrilesInternal( tif, 1 );
}
static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount )
{
register TIFFDirectory *td = &tif->tif_dir;
int return_value = 1;
/* Do not do anything if TIFF_DEFERSTRILELOAD is not set */
if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) || (tif->tif_flags&TIFF_CHOPPEDUPARRAYS) != 0 )
return 1;
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 canceled, 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_t 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;
}
/* vim: set ts=8 sts=8 sw=8 noet: */
/*
* Local Variables:
* mode: c
* c-basic-offset: 8
* fill-column: 78
* End:
*/