/* $Id: tif_dirread.c,v 1.174 2012-02-01 02:24:47 fwarmerdam Exp $ */

/*
 * 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 'ignore' to the TIFFDirEntry structure, to flag status,
 *   eliminating current use of the IGNORE value, and therefore eliminating
 *   current irrational behaviour on tags with tag id code 0
 * - add a field 'field_info' to the TIFFDirEntry structure, and set that with
 *   the pointer to the appropriate TIFFField structure early on in
 *   TIFFReadDirectory, so as to eliminate current possibly repetitive lookup.
 */

#include "tiffiop.h"

#define IGNORE 0          /* tag placeholder used below */
#define FAILED_FII    ((uint32) -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 uint64 TIFFReadUInt64(const uint8 *value);

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:
            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);
                *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);
    }
}

static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value)
{
    int typesize;
    uint32 datasize;
    void* data;
    typesize=TIFFDataWidth(direntry->tdir_type);
    if ((direntry->tdir_count==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)<direntry->tdir_count)
        return(TIFFReadDirEntryErrSizesan);
    if ((uint64)(2147483647/desttypesize)<direntry->tdir_count)
        return(TIFFReadDirEntryErrSizesan);

    *count=(uint32)direntry->tdir_count;
    datasize=(*count)*typesize;
    assert((tmsize_t)datasize>0);
    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);
            err=TIFFReadDirEntryData(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);
            err=TIFFReadDirEntryData(tif,offset,(tmsize_t)datasize,data);
            if (err!=TIFFReadDirEntryErrOk)
            {
                _TIFFfree(data);
                return(err);
            }
        }
    }
    *value=data;
    return(TIFFReadDirEntryErrOk);
}

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 TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
{
    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=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
    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 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);
    if (err!=TIFFReadDirEntryErrOk)
    {
        _TIFFfree(data);
        return(err);
    }
    *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++)
                    *mb++=(float)(*ma++);
            }
            break;
    }
    _TIFFfree(origdata);
    if (err!=TIFFReadDirEntryErrOk)
    {
        _TIFFfree(data);
        return(err);
    }
    *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);
    if (err!=TIFFReadDirEntryErrOk)
    {
        _TIFFfree(data);
        return(err);
    }
    *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);
    if (err!=TIFFReadDirEntryErrOk)
    {
        _TIFFfree(data);
        return(err);
    }
    *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)
        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);
    if (m.i[0]==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);
    if ((int32)m.i[0]==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);
}

/*
 * Largest 32-bit unsigned integer value.
 */
#if defined(__WIN32__) && defined(_MSC_VER)
# define TIFF_UINT32_MAX 0xFFFFFFFFI64
#else
# define TIFF_UINT32_MAX 0xFFFFFFFFLL
#endif

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 > TIFF_UINT32_MAX))
        return(TIFFReadDirEntryErrRange);
    else
        return(TIFFReadDirEntryErrOk);
}

#undef TIFF_UINT32_MAX

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

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

static enum TIFFReadDirEntryErr
TIFFReadDirEntryCheckRangeSlongSlong8(int64 value)
{
    if ((value < 0L-0x80000000L) || (value > 0x7FFFFFFFL))
        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);
}

/*
 * Largest 64-bit signed integer value.
 */
#if defined(__WIN32__) && defined(_MSC_VER)
# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFI64
#else
# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFLL
#endif

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

#undef TIFF_INT64_MAX

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 {
        tmsize_t ma,mb;
        ma=(tmsize_t)offset;
        mb=ma+size;
        if (((uint64)ma!=offset)||(mb<ma)||(mb<size)||(mb>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:
                TIFFErrorExt(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;
        }
    }
}

/*
 * 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;
    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_tag=IGNORE;
            }
        }
    }

    tif->tif_flags &= ~TIFF_BEENWRITING;    /* reset before new dir */
    tif->tif_flags &= ~TIFF_BUF4WRITE;      /* reset before new dir */
    /* 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 everthing 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 permited 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_tag=IGNORE;
    }
    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_tag=IGNORE;
    }
    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_tag!=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_tag=IGNORE;
                } else {
                    TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
                    assert(fii != FAILED_FII);
                }
            }
        }
        if (dp->tdir_tag!=IGNORE)
        {
            fip=tif->tif_fields[fii];
            if (fip->field_bit==FIELD_IGNORE)
                dp->tdir_tag=IGNORE;
            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_tag=IGNORE;
                        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)) {
        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 {
            MissingRequired(tif,
                isTiled(tif) ? "TileOffsets" : "StripOffsets");
            goto bad;
        }
    }
    /*
     * Second pass: extract other information.
     */
    for (di=0, dp=dir; di<dircount; di++, dp++)
    {
        switch (dp->tdir_tag)
        {
            case IGNORE:
                break;
            case TIFFTAG_MINSAMPLEVALUE:
            case TIFFTAG_MAXSAMPLEVALUE:
            case TIFFTAG_BITSPERSAMPLE:
            case TIFFTAG_DATATYPE:
            case TIFFTAG_SAMPLEFORMAT:
                /*
                 * The MinSampleValue, MaxSampleValue, BitsPerSample
                 * DataType and SampleFormat tags are supposed to be
                 * written as one value/sample, but some vendors
                 * incorrectly write one value only -- so we accept
                 * that as well (yech). 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;
                }
                break;
            case TIFFTAG_SMINSAMPLEVALUE:
            case TIFFTAG_SMAXSAMPLEVALUE:
                {

                    double *data;
                    enum TIFFReadDirEntryErr err;
                    uint32 saved_flags;
                    int m;
                    if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
                        err = TIFFReadDirEntryErrCount;
                    else
                        err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
                    if (err!=TIFFReadDirEntryErrOk)
                    {
                        fip = TIFFFieldWithTag(tif,dp->tdir_tag);
                        TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
                        goto bad;
                    }
                    saved_flags = tif->tif_flags;
                    tif->tif_flags |= TIFF_PERSAMPLE;
                    m = TIFFSetField(tif,dp->tdir_tag,data);
                    tif->tif_flags = saved_flags;
                    _TIFFfree(data);
                    if (!m)
                        goto bad;
                }
                break;
            case TIFFTAG_STRIPOFFSETS:
            case TIFFTAG_TILEOFFSETS:
#if defined(DEFER_STRILE_LOAD)
                                _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
                                             dp, sizeof(TIFFDirEntry) );
#else
                if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset))
                    goto bad;
#endif
                break;
            case TIFFTAG_STRIPBYTECOUNTS:
            case TIFFTAG_TILEBYTECOUNTS:
#if defined(DEFER_STRILE_LOAD)
                                _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
                                             dp, sizeof(TIFFDirEntry) );
#else
                if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount))
                    goto bad;
#endif
                break;
            case TIFFTAG_COLORMAP:
            case TIFFTAG_TRANSFERFUNCTION:
                {
                    enum TIFFReadDirEntryErr err;
                    uint32 countpersample;
                    uint32 countrequired;
                    uint32 incrementpersample;
                    uint16* value=NULL;
                    countpersample=(1L<<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;
        }
    }
    /*
     * 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;
            }
        }
    }
    /*
     * 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;
        /*
         * Assume we have wrong StripByteCount value (in case
         * of single strip) in following cases:
         *   - it is equal to zero along with StripOffset;
         *   - it is larger than file itself (in case of uncompressed
         *     image);
         *   - it is smaller than the size of the bytes per row
         *     multiplied on the number of rows.  The last case should
         *     not be checked in the case of writing new image,
         *     because we may do not know the exact strip size
         *     until the whole image will be written and directory
         *     dumped out.
         */
        #define	BYTECOUNTLOOKSBAD \
            ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \
              (tif->tif_dir.td_compression == COMPRESSION_NONE && \
               tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0]) || \
              (tif->tif_mode == O_RDONLY && \
               tif->tif_dir.td_compression == COMPRESSION_NONE && \
               tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) )

        } else if (tif->tif_dir.td_nstrips == 1
                           && _TIFFFillStriles(tif)
               && tif->tif_dir.td_stripoffset[0] != 0
               && BYTECOUNTLOOKSBAD) {
            /*
             * 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;

#if !defined(DEFER_STRILE_LOAD)
        } else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG
               && tif->tif_dir.td_nstrips > 2
               && tif->tif_dir.td_compression == COMPRESSION_NONE
               && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1]
               && tif->tif_dir.td_stripbytecount[0] != 0
               && tif->tif_dir.td_stripbytecount[1] != 0 ) {
            /*
             * 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;
#endif /* !defined(DEFER_STRILE_LOAD) */
        }
    }
    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);
    }
    /*
     * XXX: We can optimize checking for the strip bounds using the sorted
     * bytecounts array. See also comments for TIFFAppendToStrip()
     * function in tif_write.c.
     */
#if !defined(DEFER_STRILE_LOAD)
    if (tif->tif_dir.td_nstrips > 1) {
        uint32 strip;

        tif->tif_dir.td_stripbytecountsorted = 1;
        for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
            if (tif->tif_dir.td_stripoffset[strip - 1] >
                tif->tif_dir.td_stripoffset[strip]) {
                tif->tif_dir.td_stripbytecountsorted = 0;
                break;
            }
        }
    }
#endif /* !defined(DEFER_STRILE_LOAD) */

    /*
     * 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))
    {
        if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount )
            return 0;
        ChopUpSingleUncompressedStrip(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 arbitarry 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_tag=IGNORE;
            } else {
                TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
                assert( fii != FAILED_FII );
            }
        }
        if (dp->tdir_tag!=IGNORE)
        {
            fip=tif->tif_fields[fii];
            if (fip->field_bit==FIELD_IGNORE)
                dp->tdir_tag=IGNORE;
            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_tag=IGNORE;
                }
                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_tag=IGNORE;
                    }
                }
            }
            switch (dp->tdir_tag)
            {
                case IGNORE:
                    break;
                case EXIFTAG_SUBJECTDISTANCE:
                    (void) TIFFFetchSubjectDistance(tif,dp);
                    break;
                default:
                    (void) TIFFFetchNormalTag(tif, dp, TRUE);
                    break;
            }
        }
    }
    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;

    _TIFFFillStriles( tif );

    if (td->td_stripbytecount)
        _TIFFfree(td->td_stripbytecount);
    td->td_stripbytecount = (uint64*)
        _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64),
        "for \"StripByteCounts\" array");
        if( td->td_stripbytecount == 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 = TIFFDataWidth((TIFFDataType) dp->tdir_type);
            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;
            }
            datasize=(uint64)typewidth*dp->tdir_count;
            if (!(tif->tif_flags&TIFF_BIGTIFF))
            {
                if (datasize<=4)
                    datasize=0;
            }
            else
            {
                if (datasize<=8)
                    datasize=0;
            }
            space+=datasize;
        }
        space = filesize - space;
        if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
            space /= td->td_samplesperpixel;
        for (strip = 0; strip < td->td_nstrips; strip++)
            td->td_stripbytecount[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[strip]+td->td_stripbytecount[strip] > filesize)
            td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip];
    } else if (isTiled(tif)) {
        uint64 bytespertile = TIFFTileSize64(tif);

        for (strip = 0; strip < td->td_nstrips; strip++)
            td->td_stripbytecount[strip] = bytespertile;
    } else {
        uint64 rowbytes = TIFFScanlineSize64(tif);
        uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
        for (strip = 0; strip < td->td_nstrips; strip++)
            td->td_stripbytecount[strip] = rowbytes * rowsperstrip;
    }
    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;

    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_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;
        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 = (tmsize_t) tif->tif_diroff;
        if ((uint64)off!=tif->tif_diroff)
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
            return(0);
        }

        /*
         * 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
        {
            tmsize_t m;
            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++)
    {
        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);
            *(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->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)
                {
                    uint8* ma;
                    uint32 mb;
                    int n;
                    ma=data;
                    mb=0;
                    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;
                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)
                    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)
                                    /* corrupt file */;
                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;
                        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;
                    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 ? fip->field_name : "unknown tagname",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=TIFFReadDirEntryLong8Array(tif,dir,&data);
    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;
        resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array");
        if (resizeddata==0) {
            _TIFFfree(data);
            return(0);
        }
        if (dir->tdir_count<(uint64)nstrips)
        {
            _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64));
            _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64));
        }
        else
            _TIFFmemcpy(resizeddata,data,nstrips*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)
            /*
             * 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);
    }
}

/*
 * 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 strip;
    uint64 nstrips64;
    uint32 nstrips32;
    uint32 rowsperstrip;
    uint64* newcounts;
    uint64* newoffsets;

    bytecount = td->td_stripbytecount[0];
    offset = td->td_stripoffset[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 strips in an image
     */
    if (rowsperstrip >= td->td_rowsperstrip)
        return;
    nstrips64 = TIFFhowmany_64(bytecount, stripbytes);
    if ((nstrips64==0)||(nstrips64>0xFFFFFFFF)) /* something is wonky, do nothing. */
        return;
    nstrips32 = (uint32)nstrips64;

    newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
                "for chopped \"StripByteCounts\" array");
    newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
                "for chopped \"StripOffsets\" array");
    if (newcounts == NULL || newoffsets == NULL) {
        /*
         * Unable to allocate new strip information, give up and use
         * the original one strip information.
         */
        if (newcounts != NULL)
            _TIFFfree(newcounts);
        if (newoffsets != NULL)
            _TIFFfree(newoffsets);
        return;
    }
    /*
     * Fill the strip information arrays with new bytecounts and offsets
     * that reflect the broken-up format.
     */
    for (strip = 0; strip < nstrips32; strip++) {
        if (stripbytes > bytecount)
            stripbytes = bytecount;
        newcounts[strip] = stripbytes;
        newoffsets[strip] = offset;
        offset += stripbytes;
        bytecount -= stripbytes;
    }
    /*
     * Replace old single strip info with multi-strip info.
     */
    td->td_stripsperimage = td->td_nstrips = nstrips32;
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

    _TIFFfree(td->td_stripbytecount);
    _TIFFfree(td->td_stripoffset);
    td->td_stripbytecount = newcounts;
    td->td_stripoffset = newoffsets;
    td->td_stripbytecountsorted = 1;
}

int _TIFFFillStriles( TIFF *tif )
{
#if defined(DEFER_STRILE_LOAD)
        register TIFFDirectory *td = &tif->tif_dir;
        int return_value = 1;

        if( td->td_stripoffset != NULL )
                return 1;

        if( td->td_stripoffset_entry.tdir_count == 0 )
                return 0;

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

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

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

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

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

        return return_value;
#else /* !defined(DEFER_STRILE_LOAD) */
        (void) tif;
        return 1;
#endif
}


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