/*
 * 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 "tiffiop.h"
#include <float.h>
#include <stdlib.h>

#define FAILED_FII    ((uint32) -1)

/*
 * Largest 64-bit signed integer value.
 */
#define TIFF_INT64_MAX ((int64)(TIFF_UINT64_MAX >> 1))

#ifdef HAVE_IEEEFP
# define TIFFCvtIEEEFloatToNative(tif, n, fp)
# define TIFFCvtIEEEDoubleToNative(tif, n, dp)
#else
extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);
extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, 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* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* 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* value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value);
static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** 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** value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
#if 0
static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
#endif

static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value);
static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value);
static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value);
static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* 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 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32 value);
static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value);

static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64 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 dircount);
static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid);
static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii);

static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount);
static void MissingRequired(TIFF*, const char*);
static int TIFFCheckDirOffset(TIFF* tif, uint64 diroff);
static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
static uint16 TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, uint64* nextdiroff);
static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp);
static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
static void ChopUpSingleUncompressedStrip(TIFF*);
static void TryChopUpUncompressedBigTiff(TIFF*);
static uint64 TIFFReadUInt64(const uint8 *value);
static int _TIFFGetMaxColorChannels(uint16 photometric);

static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount );

typedef union _UInt64Aligned_t
{
        double d;
	uint64 l;
	uint32 i[2];
	uint16 s[4];
	uint8  c[8];
} UInt64Aligned_t;

/*
  Unaligned safe copy of a uint64 value from an octet array.
*/
static uint64 TIFFReadUInt64(const uint8 *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* 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 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeByteSbyte(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			{
				uint16 m;
				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeByteShort(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeByteSshort(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeByteLong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeByteSlong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			{
				uint64 m;
				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeByteLong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG8:
			{
				int64 m;
				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeByteSlong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint8)m;
				return(TIFFReadDirEntryErrOk);
			}
		default:
			return(TIFFReadDirEntryErrType);
	}
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
{
	enum TIFFReadDirEntryErr err;
	if (direntry->tdir_count!=1)
		return(TIFFReadDirEntryErrCount);
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8 m;
				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			{
				int8 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeShortSbyte(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			TIFFReadDirEntryCheckedShort(tif,direntry,value);
			return(TIFFReadDirEntryErrOk);
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeShortSshort(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeShortLong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeShortSlong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			{
				uint64 m;
				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeShortLong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG8:
			{
				int64 m;
				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeShortSlong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint16)m;
				return(TIFFReadDirEntryErrOk);
			}
		default:
			return(TIFFReadDirEntryErrType);
	}
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
{
	enum TIFFReadDirEntryErr err;
	if (direntry->tdir_count!=1)
		return(TIFFReadDirEntryErrCount);
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8 m;
				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			{
				int8 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLongSbyte(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			{
				uint16 m;
				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLongSshort(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			TIFFReadDirEntryCheckedLong(tif,direntry,value);
			return(TIFFReadDirEntryErrOk);
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLongSlong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			{
				uint64 m;
				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeLongLong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG8:
			{
				int64 m;
				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeLongSlong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint32)m;
				return(TIFFReadDirEntryErrOk);
			}
		default:
			return(TIFFReadDirEntryErrType);
	}
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
{
	enum TIFFReadDirEntryErr err;
	if (direntry->tdir_count!=1)
		return(TIFFReadDirEntryErrCount);
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8 m;
				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			{
				int8 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLong8Sbyte(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			{
				uint16 m;
				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLong8Sshort(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				err=TIFFReadDirEntryCheckRangeLong8Slong(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint64)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
			return(err);
		case TIFF_SLONG8:
			{
				int64 m;
				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				err=TIFFReadDirEntryCheckRangeLong8Slong8(m);
				if (err!=TIFFReadDirEntryErrOk)
					return(err);
				*value=(uint64)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 m;
				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			{
				int8 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			{
				uint16 m;
				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				*value=(float)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			{
				uint64 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 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_MIN))
					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 m;
				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			{
				int8 m;
				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SHORT:
			{
				uint16 m;
				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			{
				int16 m;
				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			{
				int32 m;
				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
				*value=(double)m;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_LONG8:
			{
				uint64 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 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* value)
{
	enum TIFFReadDirEntryErr err;
	if (direntry->tdir_count!=1)
		return(TIFFReadDirEntryErrCount);
	switch (direntry->tdir_type)
	{
		case TIFF_LONG:
		case TIFF_IFD:
			{
				uint32 m;
				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
				*value=(uint64)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 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*) _TIFFrealloc(
                            *pdest, already_read + to_read);
            if( new_dest == NULL )
            {
                TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                            "Failed to allocate memory for %s "
                            "(%ld elements of %ld bytes each)",
                            "TIFFReadDirEntryArray",
                             (long) 1, (long) (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* count, uint32 desttypesize,
    void** value, uint64 maxcount)
{
	int typesize;
	uint32 datasize;
	void* data;
        uint64 target_count64;
	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;

        /* 
         * 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)(2147483647/typesize)<target_count64)
		return(TIFFReadDirEntryErrSizesan);
	if ((uint64)(2147483647/desttypesize)<target_count64)
		return(TIFFReadDirEntryErrSizesan);

	*count=(uint32)target_count64;
	datasize=(*count)*typesize;
	assert((tmsize_t)datasize>0);

	if( isMapped(tif) && datasize > (uint32)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))
	{
		if (datasize<=4)
			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
		else
		{
			enum TIFFReadDirEntryErr err;
			uint32 offset = direntry->tdir_offset.toff_long;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabLong(&offset);
			if( isMapped(tif) )
				err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data);
			else
				err=TIFFReadDirEntryDataAndRealloc(tif,(uint64)offset,(tmsize_t)datasize,&data);
			if (err!=TIFFReadDirEntryErrOk)
			{
				_TIFFfree(data);
				return(err);
			}
		}
	}
	else
	{
		if (datasize<=8)
			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
		else
		{
			enum TIFFReadDirEntryErr err;
			uint64 offset = direntry->tdir_offset.toff_long8;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabLong8(&offset);
			if( isMapped(tif) )
				err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data);
			else
				err=TIFFReadDirEntryDataAndRealloc(tif,(uint64)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* count, uint32 desttypesize, void** value)
{
    return TIFFReadDirEntryArrayWithLimit(tif, direntry, count,
                                          desttypesize, value, ~((uint64)0));
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	uint8* 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*)origdata;
			return(TIFFReadDirEntryErrOk);
		case TIFF_SBYTE:
			{
				int8* m;
				uint32 n;
				m=(int8*)origdata;
				for (n=0; n<count; n++)
				{
					err=TIFFReadDirEntryCheckRangeByteSbyte(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(uint8*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
	}
	data=(uint8*)_TIFFmalloc(count);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_SHORT:
			{
				uint16* ma;
				uint8* mb;
				uint32 n;
				ma=(uint16*)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)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				uint8* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					err=TIFFReadDirEntryCheckRangeByteSshort(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint8)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				uint8* mb;
				uint32 n;
				ma=(uint32*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				uint8* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					err=TIFFReadDirEntryCheckRangeByteSlong(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint8)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				uint8* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				uint8* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeByteSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint8)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	int8* 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* m;
				uint32 n;
				m=(uint8*)origdata;
				for (n=0; n<count; n++)
				{
					err=TIFFReadDirEntryCheckRangeSbyteByte(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(int8*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SBYTE:
			*value=(int8*)origdata;
			return(TIFFReadDirEntryErrOk);
	}
	data=(int8*)_TIFFmalloc(count);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_SHORT:
			{
				uint16* ma;
				int8* mb;
				uint32 n;
				ma=(uint16*)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)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				int8* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int8)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				int8* mb;
				uint32 n;
				ma=(uint32*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				int8* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int8)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				int8* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				int8* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int8)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	uint16* 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*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfShort(*value,count);  
			return(TIFFReadDirEntryErrOk);
		case TIFF_SSHORT:
			{
				int16* m;
				uint32 n;
				m=(int16*)origdata;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)m);
					err=TIFFReadDirEntryCheckRangeShortSshort(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(uint16*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
	}
	data=(uint16*)_TIFFmalloc(count*2);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				uint16* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(uint16)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				uint16* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					err=TIFFReadDirEntryCheckRangeShortSbyte(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint16)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				uint16* mb;
				uint32 n;
				ma=(uint32*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				uint16* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					err=TIFFReadDirEntryCheckRangeShortSlong(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint16)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				uint16* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				uint16* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeShortSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint16)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	int16* 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* m;
				uint32 n;
				m=(uint16*)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*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SSHORT:
			*value=(int16*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfShort((uint16*)(*value),count);
			return(TIFFReadDirEntryErrOk);
	}
	data=(int16*)_TIFFmalloc(count*2);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				int16* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int16)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				int16* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int16)(*ma++);
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				int16* mb;
				uint32 n;
				ma=(uint32*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				int16* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					err=TIFFReadDirEntryCheckRangeSshortSlong(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int16)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				int16* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				int16* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int16)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	uint32* 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*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfLong(*value,count);
			return(TIFFReadDirEntryErrOk);
		case TIFF_SLONG:
			{
				int32* m;
				uint32 n;
				m=(int32*)origdata;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)m);
					err=TIFFReadDirEntryCheckRangeLongSlong(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(uint32*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
	}
	data=(uint32*)_TIFFmalloc(count*4);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				uint32* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(uint32)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				uint32* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					err=TIFFReadDirEntryCheckRangeLongSbyte(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint32)(*ma++);
				}
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				uint32* mb;
				uint32 n;
				ma=(uint16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort(ma);
					*mb++=(uint32)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				uint32* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					err=TIFFReadDirEntryCheckRangeLongSshort(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint32)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				uint32* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				uint32* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeLongSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint32)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	int32* 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* m;
				uint32 n;
				m=(uint32*)origdata;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)m);
					err=TIFFReadDirEntryCheckRangeSlongLong(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(int32*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG:
			*value=(int32*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfLong((uint32*)(*value),count);
			return(TIFFReadDirEntryErrOk);
	}
	data=(int32*)_TIFFmalloc(count*4);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				int32* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int32)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				int32* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int32)(*ma++);
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				int32* mb;
				uint32 n;
				ma=(uint16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort(ma);
					*mb++=(int32)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				int32* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					*mb++=(int32)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				int32* mb;
				uint32 n;
				ma=(uint64*)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)(*ma++);
				}
			}
			break;
		case TIFF_SLONG8:
			{
				int64* ma;
				int32* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(int32)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8ArrayWithLimit(
        TIFF* tif, TIFFDirEntry* direntry, uint64** value, uint64 maxcount)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	uint64* 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*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfLong8(*value,count);
			return(TIFFReadDirEntryErrOk);
		case TIFF_SLONG8:
			{
				int64* m;
				uint32 n;
				m=(int64*)origdata;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)m);
					err=TIFFReadDirEntryCheckRangeLong8Slong8(*m);
					if (err!=TIFFReadDirEntryErrOk)
					{
						_TIFFfree(origdata);
						return(err);
					}
					m++;
				}
				*value=(uint64*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
	}
	data=(uint64*)_TIFFmalloc(count*8);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				uint64* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(uint64)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				uint64* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					err=TIFFReadDirEntryCheckRangeLong8Sbyte(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint64)(*ma++);
				}
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				uint64* mb;
				uint32 n;
				ma=(uint16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort(ma);
					*mb++=(uint64)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				uint64* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint64)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				uint64* mb;
				uint32 n;
				ma=(uint32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong(ma);
					*mb++=(uint64)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				uint64* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					err=TIFFReadDirEntryCheckRangeLong8Slong(*ma);
					if (err!=TIFFReadDirEntryErrOk)
						break;
					*mb++=(uint64)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	if (err!=TIFFReadDirEntryErrOk)
	{
		_TIFFfree(data);
		return(err);
	}
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
{
    return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, ~((uint64)0));
}

static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	int64* 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* m;
				uint32 n;
				m=(uint64*)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*)origdata;
				return(TIFFReadDirEntryErrOk);
			}
		case TIFF_SLONG8:
			*value=(int64*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfLong8((uint64*)(*value),count);
			return(TIFFReadDirEntryErrOk);
	}
	data=(int64*)_TIFFmalloc(count*8);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_BYTE:
			{
				uint8* ma;
				int64* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int64)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				int64* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(int64)(*ma++);
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				int64* mb;
				uint32 n;
				ma=(uint16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort(ma);
					*mb++=(int64)(*ma++);
				}
			}
			break;
		case TIFF_SSHORT:
			{
				int16* ma;
				int64* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					*mb++=(int64)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				int64* mb;
				uint32 n;
				ma=(uint32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong(ma);
					*mb++=(int64)(*ma++);
				}
			}
			break;
		case TIFF_SLONG:
			{
				int32* ma;
				int64* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					*mb++=(int64)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 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*)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* ma;
				float* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(float)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				float* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(float)(*ma++);
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				float* mb;
				uint32 n;
				ma=(uint16*)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* ma;
				float* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					*mb++=(float)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				float* mb;
				uint32 n;
				ma=(uint32*)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* ma;
				float* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					*mb++=(float)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				float* mb;
				uint32 n;
				ma=(uint64*)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* ma;
				float* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					*mb++=(float)(*ma++);
				}
			}
			break;
		case TIFF_RATIONAL:
			{
				uint32* ma;
				uint32 maa;
				uint32 mab;
				float* mb;
				uint32 n;
				ma=(uint32*)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* ma;
				int32 maa;
				uint32 mab;
				float* mb;
				uint32 n;
				ma=(uint32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong(ma);
					maa=*(int32*)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 n;
				if (tif->tif_flags&TIFF_SWAB)
					TIFFSwabArrayOfLong8((uint64*)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 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*)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* ma;
				double* mb;
				uint32 n;
				ma=(uint8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(double)(*ma++);
			}
			break;
		case TIFF_SBYTE:
			{
				int8* ma;
				double* mb;
				uint32 n;
				ma=(int8*)origdata;
				mb=data;
				for (n=0; n<count; n++)
					*mb++=(double)(*ma++);
			}
			break;
		case TIFF_SHORT:
			{
				uint16* ma;
				double* mb;
				uint32 n;
				ma=(uint16*)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* ma;
				double* mb;
				uint32 n;
				ma=(int16*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabShort((uint16*)ma);
					*mb++=(double)(*ma++);
				}
			}
			break;
		case TIFF_LONG:
			{
				uint32* ma;
				double* mb;
				uint32 n;
				ma=(uint32*)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* ma;
				double* mb;
				uint32 n;
				ma=(int32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong((uint32*)ma);
					*mb++=(double)(*ma++);
				}
			}
			break;
		case TIFF_LONG8:
			{
				uint64* ma;
				double* mb;
				uint32 n;
				ma=(uint64*)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* ma;
				double* mb;
				uint32 n;
				ma=(int64*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong8((uint64*)ma);
					*mb++=(double)(*ma++);
				}
			}
			break;
		case TIFF_RATIONAL:
			{
				uint32* ma;
				uint32 maa;
				uint32 mab;
				double* mb;
				uint32 n;
				ma=(uint32*)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* ma;
				int32 maa;
				uint32 mab;
				double* mb;
				uint32 n;
				ma=(uint32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong(ma);
					maa=*(int32*)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 n;
				if (tif->tif_flags&TIFF_SWAB)
					TIFFSwabArrayOfLong((uint32*)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** value)
{
	enum TIFFReadDirEntryErr err;
	uint32 count;
	void* origdata;
	uint64* 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*)origdata;
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabArrayOfLong8(*value,count);
			return(TIFFReadDirEntryErrOk);
	}
	data=(uint64*)_TIFFmalloc(count*8);
	if (data==0)
	{
		_TIFFfree(origdata);
		return(TIFFReadDirEntryErrAlloc);
	}
	switch (direntry->tdir_type)
	{
		case TIFF_LONG:
		case TIFF_IFD:
			{
				uint32* ma;
				uint64* mb;
				uint32 n;
				ma=(uint32*)origdata;
				mb=data;
				for (n=0; n<count; n++)
				{
					if (tif->tif_flags&TIFF_SWAB)
						TIFFSwabLong(ma);
					*mb++=(uint64)(*ma++);
				}
			}
			break;
	}
	_TIFFfree(origdata);
	*value=data;
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
{
	enum TIFFReadDirEntryErr err;
	uint16* m;
	uint16* na;
	uint16 nb;
	if (direntry->tdir_count<(uint64)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 nb;
	if (direntry->tdir_count<(uint64)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* value)
{
	(void) tif;
	*value=*(uint8*)(&direntry->tdir_offset);
}

static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value)
{
	(void) tif;
	*value=*(int8*)(&direntry->tdir_offset);
}

static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
{
	*value = direntry->tdir_offset.toff_short;
	/* *value=*(uint16*)(&direntry->tdir_offset); */
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabShort(value);
}

static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value)
{
	*value=*(int16*)(&direntry->tdir_offset);
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabShort((uint16*)value);
}

static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
{
	*value=*(uint32*)(&direntry->tdir_offset);
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabLong(value);
}

static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value)
{
	*value=*(int32*)(&direntry->tdir_offset);
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabLong((uint32*)value);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
{
	if (!(tif->tif_flags&TIFF_BIGTIFF))
	{
		enum TIFFReadDirEntryErr err;
		uint32 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* value)
{
	if (!(tif->tif_flags&TIFF_BIGTIFF))
	{
		enum TIFFReadDirEntryErr err;
		uint32 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*)(&direntry->tdir_offset);
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabLong8((uint64*)value);
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
	UInt64Aligned_t m;

	assert(sizeof(double)==8);
	assert(sizeof(uint64)==8);
	assert(sizeof(uint32)==4);
	if (!(tif->tif_flags&TIFF_BIGTIFF))
	{
		enum TIFFReadDirEntryErr err;
		uint32 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)==8);
	assert(sizeof(int32)==4);
	assert(sizeof(uint32)==4);
	if (!(tif->tif_flags&TIFF_BIGTIFF))
	{
		enum TIFFReadDirEntryErr err;
		uint32 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)m.i[0]==0 || m.i[1]==0)
		*value=0.0;
	else
		*value=(double)((int32)m.i[0])/(double)m.i[1];
	return(TIFFReadDirEntryErrOk);
}

static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
{
         union
	 {
	   float  f;
	   uint32 i;
	 } float_union;
	assert(sizeof(float)==4);
	assert(sizeof(uint32)==4);
	assert(sizeof(float_union)==4);
	float_union.i=*(uint32*)(&direntry->tdir_offset);
	*value=float_union.f;
	if (tif->tif_flags&TIFF_SWAB)
		TIFFSwabLong((uint32*)value);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
{
	assert(sizeof(double)==8);
	assert(sizeof(uint64)==8);
	assert(sizeof(UInt64Aligned_t)==8);
	if (!(tif->tif_flags&TIFF_BIGTIFF))
	{
		enum TIFFReadDirEntryErr err;
		uint32 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*)value);
	return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value)
{
	if (value>0xFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value)
{
	if ((value<0)||(value>0xFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value)
{
	if (value>0xFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value)
{
	if ((value<0)||(value>0xFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value)
{
	if (value>0xFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value)
{
	if ((value<0)||(value>0xFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value)
{
	if (value>0x7F)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value)
{
	if (value>0x7F)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value)
{
	if ((value<-0x80)||(value>0x7F))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value)
{
	if (value>0x7F)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value)
{
	if ((value<-0x80)||(value>0x7F))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value)
{
	if (value>0x7F)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value)
{
	if ((value<-0x80)||(value>0x7F))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value)
{
	if (value>0xFFFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value)
{
	if ((value<0)||(value>0xFFFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value)
{
	if (value>0xFFFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value)
{
	if ((value<0)||(value>0xFFFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value)
{
	if (value>0x7FFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value)
{
	if (value>0x7FFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value)
{
	if ((value<-0x8000)||(value>0x7FFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value)
{
	if (value>0x7FFF)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value)
{
	if ((value<-0x8000)||(value>0x7FFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value)
{
	if (value<0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLongLong8(uint64 value)
{
	if (value > TIFF_UINT32_MAX)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLongSlong8(int64 value)
{
	if ((value < 0) || (value > (int64) TIFF_UINT32_MAX))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlongLong(uint32 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 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 value)
{
        if ((value < 0-((int64) 0x7FFFFFFF+1)) || (value > 0x7FFFFFFF))
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value)
{
	if (value < 0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Sshort(int16 value)
{
	if (value < 0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Slong(int32 value)
{
	if (value < 0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeLong8Slong8(int64 value)
{
	if (value < 0)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value)
{
	if (value > TIFF_INT64_MAX)
		return(TIFFReadDirEntryErrRange);
	else
		return(TIFFReadDirEntryErrOk);
}

static enum TIFFReadDirEntryErr
TIFFReadDirEntryData(TIFF* tif, uint64 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)ma!=offset ||
                    ma > (~(size_t)0) - (size_t)size )
                {
                    return TIFFReadDirEntryErrIo;
                }
		mb=ma+size;
		if (mb > (size_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 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 bytecount = TIFFGetStrileByteCount(tif, 0);
    uint64 offset = TIFFGetStrileOffset(tif, 0);
    uint64 filesize;

    if( offset == 0 )
        return 0;
    if (bytecount == 0)
        return 1;
    if ( tif->tif_dir.td_compression != COMPRESSION_NONE )
        return 0;
    filesize = TIFFGetFileSize(tif);
    if( offset <= filesize && bytecount > filesize - offset )
        return 1;
    if( tif->tif_mode == O_RDONLY )
    {
        uint64 scanlinesize = TIFFScanlineSize64(tif);
        if( tif->tif_dir.td_imagelength > 0 &&
            scanlinesize > TIFF_UINT64_MAX / tif->tif_dir.td_imagelength )
        {
            return 1;
        }
        if( bytecount < scanlinesize * tif->tif_dir.td_imagelength)
            return 1;
    }
    return 0;
}


/*
 * Read the next TIFF directory from a file and convert it to the internal
 * format. We read directories sequentially.
 */
int
TIFFReadDirectory(TIFF* tif)
{
	static const char module[] = "TIFFReadDirectory";
	TIFFDirEntry* dir;
	uint16 dircount;
	TIFFDirEntry* dp;
	uint16 di;
	const TIFFField* fip;
	uint32 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 " TIFF_UINT64_FORMAT,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 mb;
		for (ma=dir, mb=0; mb<dircount; ma++, mb++)
		{
			TIFFDirEntry* na;
			uint16 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 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 %d (0x%x) 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 %d (0x%x) 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 value;
						enum TIFFReadDirEntryErr err;
						err=TIFFReadDirEntryShort(tif,dp,&value);
						if (err==TIFFReadDirEntryErrCount)
							err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
						if (err!=TIFFReadDirEntryErrOk)
						{
							fip = TIFFFieldWithTag(tif,dp->tdir_tag);
							TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
							goto bad;
						}
						if (!TIFFSetField(tif,dp->tdir_tag,value))
							goto bad;
						if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE )
						    bitspersample_read = TRUE;
					}
					break;
				case TIFFTAG_SMINSAMPLEVALUE:
				case TIFFTAG_SMAXSAMPLEVALUE:
					{

						double *data = NULL;
						enum TIFFReadDirEntryErr err;
						uint32 saved_flags;
						int m;
						if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
							err = TIFFReadDirEntryErrCount;
						else
							err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
						if (err!=TIFFReadDirEntryErrOk)
						{
							fip = TIFFFieldWithTag(tif,dp->tdir_tag);
							TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
							goto bad;
						}
						saved_flags = tif->tif_flags;
						tif->tif_flags |= TIFF_PERSAMPLE;
						m = TIFFSetField(tif,dp->tdir_tag,data);
						tif->tif_flags = saved_flags;
						_TIFFfree(data);
						if (!m)
							goto bad;
					}
					break;
				case TIFFTAG_STRIPOFFSETS:
				case TIFFTAG_TILEOFFSETS:
					_TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
					   dp, sizeof(TIFFDirEntry) );
					break;
				case TIFFTAG_STRIPBYTECOUNTS:
				case TIFFTAG_TILEBYTECOUNTS:
					_TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
					   dp, sizeof(TIFFDirEntry) );
					break;
				case TIFFTAG_COLORMAP:
				case TIFFTAG_TRANSFERFUNCTION:
					{
						enum TIFFReadDirEntryErr err;
						uint32 countpersample;
						uint32 countrequired;
						uint32 incrementpersample;
						uint16* value=NULL;
						/* It would be dangerous to instantiate those tag values */
						/* since if td_bitspersample has not yet been read (due to */
						/* unordered tags), it could be read afterwards with a */
						/* values greater than the default one (1), which may cause */
						/* crashes in user code */
						if( !bitspersample_read )
						{
							fip = TIFFFieldWithTag(tif,dp->tdir_tag);
							TIFFWarningExt(tif->tif_clientdata,module,
								"Ignoring %s since BitsPerSample tag not found",
								fip ? fip->field_name : "unknown tagname");
							continue;
						}
						/* ColorMap or TransferFunction for high bit */
						/* depths do not make much sense and could be */
						/* used as a denial of service vector */
						if (tif->tif_dir.td_bitspersample > 24)
						{
							fip = TIFFFieldWithTag(tif,dp->tdir_tag);
							TIFFWarningExt(tif->tif_clientdata,module,
								"Ignoring %s because BitsPerSample=%d>24",
								fip ? fip->field_name : "unknown tagname",
								tif->tif_dir.td_bitspersample);
							continue;
						}
						countpersample=(1U<<tif->tif_dir.td_bitspersample);
						if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
						{
							countrequired=countpersample;
							incrementpersample=0;
						}
						else
						{
							countrequired=3*countpersample;
							incrementpersample=countpersample;
						}
						if (dp->tdir_count!=(uint64)countrequired)
							err=TIFFReadDirEntryErrCount;
						else
							err=TIFFReadDirEntryShortArray(tif,dp,&value);
						if (err!=TIFFReadDirEntryErrOk)
						{
							fip = TIFFFieldWithTag(tif,dp->tdir_tag);
							TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
						}
						else
						{
							TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
							_TIFFfree(value);
						}
					}
					break;
/* BEGIN REV 4.0 COMPATIBILITY */
				case TIFFTAG_OSUBFILETYPE:
					{
						uint16 valueo;
						uint32 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 old_extrasamples;
                uint16 *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) (tif->tif_dir.td_samplesperpixel - color_channels);

                // sampleinfo should contain information relative to these new extra samples
                new_sampleinfo = (uint16*) _TIFFcalloc(tif->tif_dir.td_extrasamples, sizeof(uint16));
                if (!new_sampleinfo) {
                    TIFFErrorExt(tif->tif_clientdata, module, "Failed to allocate memory for "
                                "temporary new sampleinfo array (%d 16 bit elements)",
                                tif->tif_dir.td_extrasamples);
                    goto bad;
                }

                memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, old_extrasamples * sizeof(uint16));
                _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)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)((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 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) -1;
	tif->tif_curstrip = (uint32) -1;
	tif->tif_col = (uint32) -1;
	tif->tif_curtile = (uint32) -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 dircount)
{
	static const char module[] = "TIFFReadDirectoryCheckOrder";
	uint16 m;
	uint16 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 dircount, uint16 tagid)
{
	TIFFDirEntry* m;
	uint16 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 tagid, uint32* fii)
{
	int32 ma,mb,mc;
	ma=-1;
	mc=(int32)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)tagid)
			break;
		if (tif->tif_fields[mb]->field_tag<(uint32)tagid)
			ma=mb;
		else
			mc=mb;
	}
	while (1)
	{
		if (mb==0)
			break;
		if (tif->tif_fields[mb-1]->field_tag!=(uint32)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 dircount;
	TIFFDirEntry* dp;
	uint16 di;
	const TIFFField* fip;
	uint32 fii;
	_TIFFSetupFields(tif, infoarray);
	dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL);
	if (!dircount)
	{
		TIFFErrorExt(tif->tif_clientdata,module,
		    "Failed to read custom directory at offset " TIFF_UINT64_FORMAT,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 %d (0x%x) 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 %d (0x%x) 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)dp->tdir_tag))
					{
						fii=0xFFFF;
						break;
					}
					fip=tif->tif_fields[fii];
				}
				if (fii==0xFFFF)
				{
					TIFFWarningExt(tif->tif_clientdata, module,
					    "Wrong data type %d 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 expected;
						if (fip->field_readcount==TIFF_SPP)
							expected=(uint32)tif->tif_dir.td_samplesperpixel;
						else
							expected=(uint32)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);  
}

static int
EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
{
	static const char module[] = "EstimateStripByteCounts";

	TIFFDirEntry *dp;
	TIFFDirectory *td = &tif->tif_dir;
	uint32 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*)
	    _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64),
		"for \"StripByteCounts\" array");
        if( td->td_stripbytecount_p == NULL )
            return -1;

	if (td->td_compression != COMPRESSION_NONE) {
		uint64 space;
		uint64 filesize;
		uint16 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 typewidth;
			uint64 datasize;
			typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
			if (typewidth == 0) {
				TIFFErrorExt(tif->tif_clientdata, module,
				    "Cannot determine size of unknown tag type %d",
				    dp->tdir_type);
				return -1;
			}
			if( dp->tdir_count > TIFF_UINT64_MAX / typewidth )
                            return -1;
			datasize=(uint64)typewidth*dp->tdir_count;
			if (!(tif->tif_flags&TIFF_BIGTIFF))
			{
				if (datasize<=4)
					datasize=0;
			}
			else
			{
				if (datasize<=8)
					datasize=0;
			}
			if( space > TIFF_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] > TIFF_UINT64_MAX - td->td_stripbytecount_p[strip])
                    return -1;
		if (td->td_stripoffset_p[strip]+td->td_stripbytecount_p[strip] > filesize) {
                    if( td->td_stripoffset_p[strip] >= filesize ) {
                        /* Not sure what we should in that case... */
                        td->td_stripbytecount_p[strip] = 0;
                    } else {
                        td->td_stripbytecount_p[strip] = filesize - td->td_stripoffset_p[strip];
                    }
                }
	} else if (isTiled(tif)) {
		uint64 bytespertile = TIFFTileSize64(tif);

		for (strip = 0; strip < td->td_nstrips; strip++)
		    td->td_stripbytecount_p[strip] = bytespertile;
	} else {
		uint64 rowbytes = TIFFScanlineSize64(tif);
		uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
		for (strip = 0; strip < td->td_nstrips; strip++)
                {
                    if( rowbytes > 0 && rowsperstrip > TIFF_UINT64_MAX / rowbytes )
                        return -1;
                    td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip;
                }
	}
	TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
	if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
		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 diroff)
{
	uint16 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* new_dirlist;

		/*
		 * XXX: Reduce memory allocation granularity of the dirlist
		 * array.
		 */
		new_dirlist = (uint64*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
		    tif->tif_dirnumber, 2 * sizeof(uint64), "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 count)
{
	if ((uint64)count > dir->tdir_count) {
		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag ignored",
		    fip ? fip->field_name : "unknown tagname",
		    dir->tdir_count, count);
		return (0);
	} else if ((uint64)count < dir->tdir_count) {
		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); 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
TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
                   uint64 *nextdiroff)
{
	static const char module[] = "TIFFFetchDirectory";

	void* origdir;
	uint16 dircount16;
	uint32 dirsize;
	TIFFDirEntry* dir;
	uint8* ma;
	TIFFDirEntry* mb;
	uint16 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))) {
				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 dircount64;
			if (!ReadOK(tif, &dircount64, sizeof (uint64))) {
				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)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 nextdiroff32;
				if (!ReadOK(tif, &nextdiroff32, sizeof(uint32)))
					nextdiroff32 = 0;
				if (tif->tif_flags&TIFF_SWAB)
					TIFFSwabLong(&nextdiroff32);
				*nextdiroff=nextdiroff32;
			} else {
				if (!ReadOK(tif, nextdiroff, sizeof(uint64)))
					*nextdiroff = 0;
				if (tif->tif_flags&TIFF_SWAB)
					TIFFSwabLong8(nextdiroff);
			}
		}
	} else {
		tmsize_t m;
		tmsize_t off;
		if (tif->tif_diroff > (uint64)TIFF_INT64_MAX)
		{
			TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
			return(0);
		}
		off = (tmsize_t) tif->tif_diroff;

		/*
		 * Check for integer overflow when validating the dir_off,
		 * otherwise a very high offset may cause an OOB read and
		 * crash the client. Make two comparisons instead of
		 *
		 *  off + sizeof(uint16) > tif->tif_size
		 *
		 * to avoid overflow.
		 */
		if (!(tif->tif_flags&TIFF_BIGTIFF))
		{
			m=off+sizeof(uint16);
			if ((m<off)||(m<(tmsize_t)sizeof(uint16))||(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));
			}
			off += sizeof (uint16);
			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 dircount64;
			m=off+sizeof(uint64);
			if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(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));
			}
			off += sizeof (uint64);
			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)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 nextdiroff32;
				m=off+sizeof(uint32);
				if ((m<off)||(m<(tmsize_t)sizeof(uint32))||(m>tif->tif_size))
					nextdiroff32 = 0;
				else
					_TIFFmemcpy(&nextdiroff32, tif->tif_base + off,
						    sizeof (uint32));
				if (tif->tif_flags&TIFF_SWAB)
					TIFFSwabLong(&nextdiroff32);
				*nextdiroff = nextdiroff32;
			}
			else
			{
				m=off+sizeof(uint64);
				if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size))
					*nextdiroff = 0;
				else
					_TIFFmemcpy(nextdiroff, tif->tif_base + off,
						    sizeof (uint64));
				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*)origdir;
	mb=dir;
	for (n=0; n<dircount16; n++)
	{
		mb->tdir_ignore = FALSE;
		if (tif->tif_flags&TIFF_SWAB)
			TIFFSwabShort((uint16*)ma);
		mb->tdir_tag=*(uint16*)ma;
		ma+=sizeof(uint16);
		if (tif->tif_flags&TIFF_SWAB)
			TIFFSwabShort((uint16*)ma);
		mb->tdir_type=*(uint16*)ma;
		ma+=sizeof(uint16);
		if (!(tif->tif_flags&TIFF_BIGTIFF))
		{
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabLong((uint32*)ma);
			mb->tdir_count=(uint64)(*(uint32*)ma);
			ma+=sizeof(uint32);
			mb->tdir_offset.toff_long8=0;
			*(uint32*)(&mb->tdir_offset)=*(uint32*)ma;
			ma+=sizeof(uint32);
		}
		else
		{
			if (tif->tif_flags&TIFF_SWAB)
				TIFFSwabLong8((uint64*)ma);
                        mb->tdir_count=TIFFReadUInt64(ma);
			ma+=sizeof(uint64);
			mb->tdir_offset.toff_long8=TIFFReadUInt64(ma);
			ma+=sizeof(uint64);
		}
		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 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 %d",
                         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* data;
				assert(fip->field_passcount==0);
				err=TIFFReadDirEntryByteArray(tif,dp,&data);
				if (err==TIFFReadDirEntryErrOk)
				{
					uint32 mb = 0;
					int n;
					if (data != NULL)
					{
					    uint8* ma = data;
					    while (mb<(uint32)dp->tdir_count)
					    {
					            if (*ma==0)
					                    break;
					            ma++;
					            mb++;
					    }
					}
					if (mb+1<(uint32)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)dp->tdir_count)
					{
						uint8* o;
						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name);
						if ((uint32)dp->tdir_count+1!=dp->tdir_count+1)
							o=NULL;
						else
							o=_TIFFmalloc((uint32)dp->tdir_count+1);
						if (o==NULL)
						{
							if (data!=NULL)
								_TIFFfree(data);
							return(0);
						}
						_TIFFmemcpy(o,data,(uint32)dp->tdir_count);
						o[(uint32)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 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 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 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 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 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* 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 %d",
						       fip->field_name,(int)dp->tdir_count);
					return(0);
				}
				err=TIFFReadDirEntryShortArray(tif,dp,&data);
				if (err==TIFFReadDirEntryErrOk)
				{
					int m;
					m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]);
					_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C0_UINT8:
			{
				uint8* data;
				assert(fip->field_readcount>=1);
				assert(fip->field_passcount==0);
				if (dp->tdir_count!=(uint64)fip->field_readcount) {
					TIFFWarningExt(tif->tif_clientdata,module,
						       "incorrect count for field \"%s\", expected %d, got %d",
						       fip->field_name,(int) fip->field_readcount, (int)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* data;
				assert(fip->field_readcount>=1);
				assert(fip->field_passcount==0);
				if (dp->tdir_count!=(uint64)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* data;
				assert(fip->field_readcount>=1);
				assert(fip->field_passcount==0);
				if (dp->tdir_count!=(uint64)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)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;
		case TIFF_SETGET_C16_ASCII:
			{
				uint8* 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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C16_UINT8:
			{
				uint8* 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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C16_UINT16:
			{
				uint16* 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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C16_UINT32:
			{
				uint32* 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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C16_UINT64:
			{
				uint64* 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)(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)(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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C16_IFD8:
			{
				uint64* 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)(dp->tdir_count),data);
						if (data!=0)
							_TIFFfree(data);
						if (!m)
							return(0);
					}
				}
			}
			break;
		case TIFF_SETGET_C32_ASCII:
			{
				uint8* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_UINT8:
			{
				uint8* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_SINT8:
			{
				int8* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_UINT16:
			{
				uint16* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_SINT16:
			{
				int16* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_UINT32:
			{
				uint32* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_SINT32:
			{
				int32* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_UINT64:
			{
				uint64* 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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_SINT64:
			{
				int64* 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)(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)(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)(dp->tdir_count),data);
					if (data!=0)
						_TIFFfree(data);
					if (!m)
						return(0);
				}
			}
			break;
		case TIFF_SETGET_C32_IFD8:
			{
				uint64* 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)(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 nstrips, uint64** lpp)
{
	static const char module[] = "TIFFFetchStripThing";
	enum TIFFReadDirEntryErr err;
	uint64* 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)nstrips)
	{
		uint64* resizeddata;
		const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag);
		const char* pszMax = getenv("LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT");
		uint32 max_nstrips = 1000000;
		if( pszMax )
			max_nstrips = (uint32) 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*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array");
		if (resizeddata==0) {
			_TIFFfree(data);
			return(0);
		}
                _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64));
                _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64));
		_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)==8);
	assert(sizeof(uint32)==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 offset;
			offset=*(uint32*)(&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 nstrips,
                                      uint64 stripbytes, uint32 rowsperstrip)
{
    TIFFDirectory *td = &tif->tif_dir;
    uint64 bytecount;
    uint64 offset;
    uint64 last_offset;
    uint64 last_bytecount;
    uint32 i;
    uint64 *newcounts;
    uint64 *newoffsets;

    offset = TIFFGetStrileOffset(tif, 0);
    last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1);
    last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1);
    if( last_offset > TIFF_UINT64_MAX - last_bytecount ||
        last_offset + last_bytecount < offset )
    {
        return;
    }
    bytecount = last_offset + last_bytecount - offset;

    newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
                            "for chopped \"StripByteCounts\" array");
    newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
                            "for chopped \"StripOffsets\" array");
    if (newcounts == NULL || newoffsets == NULL) {
        /*
        * Unable to allocate new strip information, give up and use
        * the original one strip information.
        */
        if (newcounts != NULL)
            _TIFFfree(newcounts);
        if (newoffsets != NULL)
            _TIFFfree(newoffsets);
        return;
    }

    /*
     * Fill the strip information arrays with new bytecounts and offsets
     * that reflect the broken-up format.
     */
    for (i = 0; i < nstrips; i++)
    {
        if (stripbytes > bytecount)
            stripbytes = bytecount;
        newcounts[i] = stripbytes;
        newoffsets[i] = stripbytes ? offset : 0;
        offset += stripbytes;
        bytecount -= stripbytes;
    }

    /*
     * Replace old single strip info with multi-strip info.
     */
    td->td_stripsperimage = td->td_nstrips = nstrips;
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

    _TIFFfree(td->td_stripbytecount_p);
    _TIFFfree(td->td_stripoffset_p);
    td->td_stripbytecount_p = newcounts;
    td->td_stripoffset_p = newoffsets;
#ifdef STRIPBYTECOUNTSORTED_UNUSED
    td->td_stripbytecountsorted = 1;
#endif
    tif->tif_flags |= TIFF_CHOPPEDUPARRAYS;
}


/*
 * Replace a single strip (tile) of uncompressed data by multiple strips
 * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for
 * 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 bytecount;
	uint64 offset;
	uint32 rowblock;
	uint64 rowblockbytes;
	uint64 stripbytes;
	uint32 nstrips;
	uint32 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 rowblocksperstrip;
		rowblocksperstrip = (uint32) (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 rowblock;
    uint64 rowblockbytes;
    uint32 i;
    uint64 stripsize;
    uint32 rowblocksperstrip;
    uint32 rowsperstrip;
    uint64 stripbytes;
    uint32 nstrips;

    stripsize = TIFFStripSize64(tif);

    assert( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG );
    assert( tif->tif_dir.td_compression == COMPRESSION_NONE );
    assert( (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP );
    assert( stripsize > 0x7FFFFFFFUL );

    /* On a newly created file, just re-opened to be filled, we */
    /* don't want strip chop to trigger as it is going to cause issues */
    /* later ( StripOffsets and StripByteCounts improperly filled) . */
    if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY )
        return;

    if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
        (!isUpSampled(tif)))
        rowblock = td->td_ycbcrsubsampling[1];
    else
        rowblock = 1;
    rowblockbytes = TIFFVStripSize64(tif, rowblock);
    if( rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL )
    {
        /* In case of file with gigantic width */
        return;
    }

    /* Check that the strips are contiguous and of the expected size */
    for( i = 0; i < td->td_nstrips; i++ )
    {
        if( i == td->td_nstrips - 1 )
        {
            if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64(
                    tif, td->td_imagelength - i * td->td_rowsperstrip ) )
            {
                return;
            }
        }
        else
        {
            if( TIFFGetStrileByteCount(tif, i) != stripsize )
            {
                return;
            }
            if( i > 0 && TIFFGetStrileOffset(tif, i) !=
                    TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) )
            {
                return;
            }
        }
    }

    /* Aim for 512 MB strips (that will still be manageable by 32 bit builds */
    rowblocksperstrip = (uint32) (512 * 1024 * 1024 / rowblockbytes);
    if( rowblocksperstrip == 0 )
        rowblocksperstrip = 1;
    rowsperstrip = rowblocksperstrip * rowblock;
    stripbytes = rowblocksperstrip * rowblockbytes;
    assert( stripbytes <= 0x7FFFFFFFUL );

    nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
    if( nstrips == 0 )
        return;

    /* If we are going to allocate a lot of memory, make sure that the */
    /* file is as big as needed */
    if( tif->tif_mode == O_RDONLY &&
        nstrips > 1000000 )
    {
        uint64 last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1);
        uint64 filesize = TIFFGetFileSize(tif);
        uint64 last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1);
        if( last_offset > filesize ||
            last_bytecount > filesize - last_offset )
        {
            return;
        }
    }

    allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip);
}


TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
static uint64 _TIFFUnsanitizedAddUInt64AndInt(uint64 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* panVals )
{
    static const char module[] = "_TIFFPartialReadStripArray";
#define IO_CACHE_PAGE_SIZE 4096

    size_t sizeofval;
    const int bSwab = (tif->tif_flags & TIFF_SWAB) != 0;
    int sizeofvalint;
    uint64 nBaseOffset;
    uint64 nOffset;
    uint64 nOffsetStartPage;
    uint64 nOffsetEndPage;
    tmsize_t nToRead;
    tmsize_t nRead;
    uint64 nLastStripOffset;
    int iStartBefore;
    int i;
    const uint32 arraySize = tif->tif_dir.td_stripoffsetbyteallocsize;
    unsigned char buffer[2 * IO_CACHE_PAGE_SIZE];

    assert( dirent->tdir_count > 4 );

    if( dirent->tdir_type == TIFF_SHORT )
    {
        sizeofval = sizeof(uint16);
    }
    else if( dirent->tdir_type == TIFF_LONG )
    {
        sizeofval = sizeof(uint32);
    }
    else if( dirent->tdir_type == TIFF_LONG8 )
    {
        sizeofval = sizeof(uint64);
    }
    else
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                 "Invalid type for [Strip|Tile][Offset/ByteCount] tag");
        panVals[strile] = 0;
        return 0;
    }
    sizeofvalint = (int)(sizeofval);

    if( tif->tif_flags&TIFF_BIGTIFF )
    {
        uint64 offset = dirent->tdir_offset.toff_long8;
        if( bSwab )
            TIFFSwabLong8(&offset);
        nBaseOffset = offset;
    }
    else
    {
        uint32 offset = dirent->tdir_offset.toff_long;
        if( bSwab )
            TIFFSwabLong(&offset);
        nBaseOffset = offset;
    }
    /* To avoid later unsigned integer overflows */
    if( nBaseOffset > (uint64)TIFF_INT64_MAX )
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                 "Cannot read offset/size for strile %d", strile);
        panVals[strile] = 0;
        return 0;
    }
    nOffset = nBaseOffset + sizeofval * strile;
    nOffsetStartPage =
        (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE;
    nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE;

    if( nOffset + sizeofval > nOffsetEndPage )
        nOffsetEndPage += IO_CACHE_PAGE_SIZE;
#undef IO_CACHE_PAGE_SIZE

    nLastStripOffset = nBaseOffset + arraySize * sizeofval;
    if( nLastStripOffset < nOffsetEndPage )
        nOffsetEndPage = nLastStripOffset;
    if( nOffsetStartPage >= nOffsetEndPage )
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                 "Cannot read offset/size for strile %d", strile);
        panVals[strile] = 0;
        return 0;
    }
    if (!SeekOK(tif,nOffsetStartPage))
    {
        panVals[strile] = 0;
        return 0;
    }

    nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage);
    nRead = TIFFReadFile(tif, buffer, nToRead);
    if( nRead < nToRead )
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                 "Cannot read offset/size for strile around ~%d", strile);
        return 0;
    }
    iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval);
    if( strile + iStartBefore < 0 )
        iStartBefore = -strile;
    for( i = iStartBefore;
         (uint32)(strile + i) < arraySize &&
         _TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage;
         ++i )
    {
        if( sizeofval == sizeof(uint16) )
        {
            uint16 val;
            memcpy(&val,
                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
                   sizeof(val));
            if( bSwab )
                TIFFSwabShort(&val);
            panVals[strile + i] = val;
        }
        else if( sizeofval == sizeof(uint32) )
        {
            uint32 val;
            memcpy(&val,
                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
                   sizeof(val));
            if( bSwab )
                TIFFSwabLong(&val);
            panVals[strile + i] = val;
        }
        else
        {
            uint64 val;
            memcpy(&val,
                   buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint,
                   sizeof(val));
            if( bSwab )
                TIFFSwabLong8(&val);
            panVals[strile + i] = val;
        }
    }
    return 1;
}

static int _TIFFFetchStrileValue(TIFF* tif,
                                 uint32 strile,
                                 TIFFDirEntry* dirent,
                                 uint64** parray)
{
    static const char module[] = "_TIFFFetchStrileValue";
    TIFFDirectory *td = &tif->tif_dir;
    if( strile >= dirent->tdir_count )
    {
        return 0;
    }
    if( strile >= td->td_stripoffsetbyteallocsize )
    {
        uint32 nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize;
        uint32 nStripArrayAllocNew;
        uint64 nArraySize64;
        size_t nArraySize;
        uint64* offsetArray;
        uint64* bytecountArray;

        if( strile > 1000000 )
        {
            uint64 filesize = TIFFGetFileSize(tif);
            /* Avoid excessive memory allocation attempt */
            /* For such a big blockid we need at least a TIFF_LONG per strile */
            /* for the offset array. */
            if( strile > filesize / sizeof(uint32) )
            {
                TIFFErrorExt(tif->tif_clientdata, module, "File too short");
                return 0;
            }
        }

        if( td->td_stripoffsetbyteallocsize == 0 &&
            td->td_nstrips < 1024 * 1024 )
        {
            nStripArrayAllocNew = td->td_nstrips;
        }
        else
        {
#define TIFF_MAX(a,b) (((a)>(b)) ? (a) : (b))
#define TIFF_MIN(a,b) (((a)<(b)) ? (a) : (b))
            nStripArrayAllocNew = TIFF_MAX(strile + 1, 1024U * 512U );
            if( nStripArrayAllocNew < 0xFFFFFFFFU / 2  )
                nStripArrayAllocNew *= 2;
            nStripArrayAllocNew = TIFF_MIN(nStripArrayAllocNew, td->td_nstrips);
        }
        assert( strile < nStripArrayAllocNew );
        nArraySize64 = (uint64)sizeof(uint64) * nStripArrayAllocNew;
        nArraySize = (size_t)(nArraySize64);
#if SIZEOF_SIZE_T == 4
        if( nArraySize != nArraySize64 )
        {
            TIFFErrorExt(tif->tif_clientdata, module,
                        "Cannot allocate strip offset and bytecount arrays");
            return 0;
        }
#endif
        offsetArray = (uint64*)(
            _TIFFrealloc( td->td_stripoffset_p, nArraySize ) );
        bytecountArray = (uint64*)(
            _TIFFrealloc( td->td_stripbytecount_p, nArraySize ) );
        if( offsetArray )
            td->td_stripoffset_p = offsetArray;
        if( bytecountArray )
            td->td_stripbytecount_p = bytecountArray;
        if( offsetArray && bytecountArray )
        {
            td->td_stripoffsetbyteallocsize = nStripArrayAllocNew;
            /* Initialize new entries to ~0 / -1 */
            memset(td->td_stripoffset_p + nStripArrayAllocBefore,
                0xFF,
                (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) );
            memset(td->td_stripbytecount_p + nStripArrayAllocBefore,
                0xFF,
                (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) );
        }
        else
        {
            TIFFErrorExt(tif->tif_clientdata, module,
                        "Cannot allocate strip offset and bytecount arrays");
            _TIFFfree(td->td_stripoffset_p);
            td->td_stripoffset_p = NULL;
            _TIFFfree(td->td_stripbytecount_p);
            td->td_stripbytecount_p = NULL;
            td->td_stripoffsetbyteallocsize = 0;
        }
    }
    if( *parray == NULL || strile >= td->td_stripoffsetbyteallocsize )
        return 0;

    if( ~((*parray)[strile]) == 0 )
    {
        if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) )
        {
            (*parray)[strile] = 0;
            return 0;
        }
    }

    return 1;
}

static uint64 _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32 strile,
                                                   TIFFDirEntry* dirent,
                                                   uint64** parray,
                                                   int *pbErr)
{
    TIFFDirectory *td = &tif->tif_dir;
    if( pbErr )
        *pbErr = 0;
    if( (tif->tif_flags&TIFF_DEFERSTRILELOAD) && !(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 TIFFGetStrileOffset(TIFF *tif, uint32 strile)
{
    return TIFFGetStrileOffsetWithErr(tif, strile, NULL);
}

/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */
uint64 TIFFGetStrileOffsetWithErr(TIFF *tif, uint32 strile, int *pbErr)
{
    TIFFDirectory *td = &tif->tif_dir;
    return _TIFFGetStrileOffsetOrByteCountValue(tif, strile,
                               &(td->td_stripoffset_entry),
                               &(td->td_stripoffset_p), pbErr);
}

/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */
uint64 TIFFGetStrileByteCount(TIFF *tif, uint32 strile)
{
    return TIFFGetStrileByteCountWithErr(tif, strile, NULL);
}

/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */
uint64 TIFFGetStrileByteCountWithErr(TIFF *tif, uint32 strile, int *pbErr)
{
    TIFFDirectory *td = &tif->tif_dir;
    return _TIFFGetStrileOffsetOrByteCountValue(tif, strile,
                               &(td->td_stripbytecount_entry),
                               &(td->td_stripbytecount_p), pbErr);
}


int _TIFFFillStriles( TIFF *tif )
{
    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 cancelled, then we already got there, but in error */
    if( td->td_stripoffset_entry.tdir_count == 0 )
            return 0;

    if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
                                td->td_nstrips,&td->td_stripoffset_p))
    {
            return_value = 0;
    }

    if (loadStripByteCount &&
        !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
                                td->td_nstrips,&td->td_stripbytecount_p))
    {
            return_value = 0;
    }

    _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
    _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));

#ifdef STRIPBYTECOUNTSORTED_UNUSED
    if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) {
            uint32 strip;

            tif->tif_dir.td_stripbytecountsorted = 1;
            for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
                    if (tif->tif_dir.td_stripoffset_p[strip - 1] >
                        tif->tif_dir.td_stripoffset_p[strip]) {
                            tif->tif_dir.td_stripbytecountsorted = 0;
                            break;
                    }
            }
    }
#endif

    return return_value;
}


/* vim: set ts=8 sts=8 sw=8 noet: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 8
 * fill-column: 78
 * End:
 */
