/* $Id: tif_dirwrite.c,v 1.76 2011-02-18 20:53:04 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 Write Support Routines.
 */
#include "tiffiop.h"

#ifdef HAVE_IEEEFP
#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
#else
extern void TIFFCvtNativeToIEEEFloat(TIFF* tif, uint32 n, float* fp);
extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32 n, double* dp);
#endif

static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff);

static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
#if 0
static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
#endif

static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
#ifdef notdef
static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
#endif
static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
#if 0
static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
#endif
#ifdef notdef
static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
#endif
static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
#if 0
static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
#endif
static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
#ifdef notdef
static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
#endif
static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
#if 0
static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
#endif
static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
#if 0
static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
#endif
#ifdef notdef
static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
#endif
static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
#if 0
static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
#endif
#ifdef notdef
static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
#endif
static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
#ifdef notdef
static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
#endif
static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
#ifdef notdef
static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
#endif
static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
#if 0
static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
#endif
#ifdef notdef
static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
#endif
static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
#if 0
static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
#endif
static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
#ifdef notdef
static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
#endif
static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
#ifdef notdef
static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
#endif
static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);

static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
#endif
static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
#endif
static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
#endif
static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
#endif
static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
#endif
static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
#endif
static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
#endif
static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
#ifdef notdef
static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
#endif
static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);

static int TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data);

static int TIFFLinkDirectory(TIFF*);

/*
 * Write the contents of the current directory
 * to the specified file.  This routine doesn't
 * handle overwriting a directory with auxiliary
 * storage that's been changed.
 */
int
TIFFWriteDirectory(TIFF* tif)
{
    return TIFFWriteDirectorySec(tif,TRUE,TRUE,NULL);
}

/*
 * Similar to TIFFWriteDirectory(), writes the directory out
 * but leaves all data structures in memory so that it can be
 * written again.  This will make a partially written TIFF file
 * readable before it is successfully completed/closed.
 */
int
TIFFCheckpointDirectory(TIFF* tif)
{
    int rc;
    /* Setup the strips arrays, if they haven't already been. */
    if (tif->tif_dir.td_stripoffset == NULL)
        (void) TIFFSetupStrips(tif);
    rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL);
    (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
    return rc;
}

int
TIFFWriteCustomDirectory(TIFF* tif, uint64* pdiroff)
{
    return TIFFWriteDirectorySec(tif,FALSE,FALSE,pdiroff);
}

/*
 * Similar to TIFFWriteDirectory(), but if the directory has already
 * been written once, it is relocated to the end of the file, in case it
 * has changed in size.  Note that this will result in the loss of the
 * previously used directory space.
 */
int
TIFFRewriteDirectory( TIFF *tif )
{
    static const char module[] = "TIFFRewriteDirectory";

    /* We don't need to do anything special if it hasn't been written. */
    if( tif->tif_diroff == 0 )
        return TIFFWriteDirectory( tif );

    /*
     * Find and zero the pointer to this directory, so that TIFFLinkDirectory
     * will cause it to be added after this directories current pre-link.
     */

    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff)
        {
            tif->tif_header.classic.tiff_diroff = 0;
            tif->tif_diroff = 0;

            TIFFSeekFile(tif,4,SEEK_SET);
            if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff),4))
            {
                TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                    "Error updating TIFF header");
                return (0);
            }
        }
        else
        {
            uint32 nextdir;
            nextdir = tif->tif_header.classic.tiff_diroff;
            while(1) {
                uint16 dircount;
                uint32 nextnextdir;

                if (!SeekOK(tif, nextdir) ||
                    !ReadOK(tif, &dircount, 2)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory count");
                    return (0);
                }
                if (tif->tif_flags & TIFF_SWAB)
                    TIFFSwabShort(&dircount);
                (void) TIFFSeekFile(tif,
                    nextdir+2+dircount*12, SEEK_SET);
                if (!ReadOK(tif, &nextnextdir, 4)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory link");
                    return (0);
                }
                if (tif->tif_flags & TIFF_SWAB)
                    TIFFSwabLong(&nextnextdir);
                if (nextnextdir==tif->tif_diroff)
                {
                    uint32 m;
                    m=0;
                    (void) TIFFSeekFile(tif,
                        nextdir+2+dircount*12, SEEK_SET);
                    if (!WriteOK(tif, &m, 4)) {
                        TIFFErrorExt(tif->tif_clientdata, module,
                             "Error writing directory link");
                        return (0);
                    }
                    tif->tif_diroff=0;
                    break;
                }
                nextdir=nextnextdir;
            }
        }
    }
    else
    {
        if (tif->tif_header.big.tiff_diroff == tif->tif_diroff)
        {
            tif->tif_header.big.tiff_diroff = 0;
            tif->tif_diroff = 0;

            TIFFSeekFile(tif,8,SEEK_SET);
            if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff),8))
            {
                TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                    "Error updating TIFF header");
                return (0);
            }
        }
        else
        {
            uint64 nextdir;
            nextdir = tif->tif_header.big.tiff_diroff;
            while(1) {
                uint64 dircount64;
                uint16 dircount;
                uint64 nextnextdir;

                if (!SeekOK(tif, nextdir) ||
                    !ReadOK(tif, &dircount64, 8)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory count");
                    return (0);
                }
                if (tif->tif_flags & TIFF_SWAB)
                    TIFFSwabLong8(&dircount64);
                if (dircount64>0xFFFF)
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Sanity check on tag count failed, likely corrupt TIFF");
                    return (0);
                }
                dircount=(uint16)dircount64;
                (void) TIFFSeekFile(tif,
                    nextdir+8+dircount*20, SEEK_SET);
                if (!ReadOK(tif, &nextnextdir, 8)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory link");
                    return (0);
                }
                if (tif->tif_flags & TIFF_SWAB)
                    TIFFSwabLong8(&nextnextdir);
                if (nextnextdir==tif->tif_diroff)
                {
                    uint64 m;
                    m=0;
                    (void) TIFFSeekFile(tif,
                        nextdir+8+dircount*20, SEEK_SET);
                    if (!WriteOK(tif, &m, 8)) {
                        TIFFErrorExt(tif->tif_clientdata, module,
                             "Error writing directory link");
                        return (0);
                    }
                    tif->tif_diroff=0;
                    break;
                }
                nextdir=nextnextdir;
            }
        }
    }

    /*
     * Now use TIFFWriteDirectory() normally.
     */

    return TIFFWriteDirectory( tif );
}

static int
TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff)
{
    static const char module[] = "TIFFWriteDirectorySec";
    uint32 ndir;
    TIFFDirEntry* dir;
    uint32 dirsize;
    void* dirmem;
    uint32 m;
    if (tif->tif_mode == O_RDONLY)
        return (1);

        _TIFFFillStriles( tif );

    /*
     * Clear write state so that subsequent images with
     * different characteristics get the right buffers
     * setup for them.
     */
    if (imagedone)
    {
        if (tif->tif_flags & TIFF_POSTENCODE)
        {
            tif->tif_flags &= ~TIFF_POSTENCODE;
            if (!(*tif->tif_postencode)(tif))
            {
                TIFFErrorExt(tif->tif_clientdata,module,
                    "Error post-encoding before directory write");
                return (0);
            }
        }
        (*tif->tif_close)(tif);       /* shutdown encoder */
        /*
         * Flush any data that might have been written
         * by the compression close+cleanup routines.  But
                 * be careful not to write stuff if we didn't add data
                 * in the previous steps as the "rawcc" data may well be
                 * a previously read tile/strip in mixed read/write mode.
         */
        if (tif->tif_rawcc > 0
            && (tif->tif_flags & TIFF_BEENWRITING) != 0 )
        {
            if( !TIFFFlushData1(tif) )
                    {
            TIFFErrorExt(tif->tif_clientdata, module,
                "Error flushing data before directory write");
            return (0);
                    }
        }
        if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
        {
            _TIFFfree(tif->tif_rawdata);
            tif->tif_rawdata = NULL;
            tif->tif_rawcc = 0;
            tif->tif_rawdatasize = 0;
                        tif->tif_rawdataoff = 0;
                        tif->tif_rawdataloaded = 0;
        }
        tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
    }
    dir=NULL;
    dirmem=NULL;
    dirsize=0;
    while (1)
    {
        ndir=0;
        if (isimage)
        {
            if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
            {
                if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGEWIDTH,tif->tif_dir.td_imagewidth))
                    goto bad;
                if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGELENGTH,tif->tif_dir.td_imagelength))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS))
            {
                if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILEWIDTH,tif->tif_dir.td_tilewidth))
                    goto bad;
                if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILELENGTH,tif->tif_dir.td_tilelength))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_RESOLUTION))
            {
                if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XRESOLUTION,tif->tif_dir.td_xresolution))
                    goto bad;
                if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YRESOLUTION,tif->tif_dir.td_yresolution))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_POSITION))
            {
                if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XPOSITION,tif->tif_dir.td_xposition))
                    goto bad;
                if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YPOSITION,tif->tif_dir.td_yposition))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_SUBFILETYPE))
            {
                if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_SUBFILETYPE,tif->tif_dir.td_subfiletype))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
            {
                if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_BITSPERSAMPLE,tif->tif_dir.td_bitspersample))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_COMPRESSION))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_COMPRESSION,tif->tif_dir.td_compression))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PHOTOMETRIC,tif->tif_dir.td_photometric))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_THRESHHOLDING))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_THRESHHOLDING,tif->tif_dir.td_threshholding))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_FILLORDER))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_FILLORDER,tif->tif_dir.td_fillorder))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_ORIENTATION))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_ORIENTATION,tif->tif_dir.td_orientation))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_SAMPLESPERPIXEL,tif->tif_dir.td_samplesperpixel))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP))
            {
                if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_ROWSPERSTRIP,tif->tif_dir.td_rowsperstrip))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE))
            {
                if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MINSAMPLEVALUE,tif->tif_dir.td_minsamplevalue))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE))
            {
                if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MAXSAMPLEVALUE,tif->tif_dir.td_maxsamplevalue))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_PLANARCONFIG))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PLANARCONFIG,tif->tif_dir.td_planarconfig))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_RESOLUTIONUNIT,tif->tif_dir.td_resolutionunit))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_PAGENUMBER))
            {
                if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_PAGENUMBER,2,&tif->tif_dir.td_pagenumber[0]))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_STRIPBYTECOUNTS))
            {
                if (!isTiled(tif))
                {
                    if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
                        goto bad;
                }
                else
                {
                    if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
                        goto bad;
                }
            }
            if (TIFFFieldSet(tif,FIELD_STRIPOFFSETS))
            {
                if (!isTiled(tif))
                {
                    if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
                        goto bad;
                }
                else
                {
                    if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
                        goto bad;
                }
            }
            if (TIFFFieldSet(tif,FIELD_COLORMAP))
            {
                if (!TIFFWriteDirectoryTagColormap(tif,&ndir,dir))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES))
            {
                if (tif->tif_dir.td_extrasamples)
                {
                    uint16 na;
                    uint16* nb;
                    TIFFGetFieldDefaulted(tif,TIFFTAG_EXTRASAMPLES,&na,&nb);
                    if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_EXTRASAMPLES,na,nb))
                        goto bad;
                }
            }
            if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT))
            {
                if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_SAMPLEFORMAT,tif->tif_dir.td_sampleformat))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE))
            {
                if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMINSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_sminsamplevalue))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE))
            {
                if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMAXSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_smaxsamplevalue))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH))
            {
                if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_IMAGEDEPTH,tif->tif_dir.td_imagedepth))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_TILEDEPTH))
            {
                if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_TILEDEPTH,tif->tif_dir.td_tiledepth))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS))
            {
                if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_HALFTONEHINTS,2,&tif->tif_dir.td_halftonehints[0]))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING))
            {
                if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_YCBCRSUBSAMPLING,2,&tif->tif_dir.td_ycbcrsubsampling[0]))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING))
            {
                if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_YCBCRPOSITIONING,tif->tif_dir.td_ycbcrpositioning))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE))
            {
                if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,TIFFTAG_REFERENCEBLACKWHITE,6,tif->tif_dir.td_refblackwhite))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION))
            {
                if (!TIFFWriteDirectoryTagTransferfunction(tif,&ndir,dir))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_INKNAMES))
            {
                if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames))
                    goto bad;
            }
            if (TIFFFieldSet(tif,FIELD_SUBIFD))
            {
                if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir))
                    goto bad;
            }
            {
                uint32 n;
                for (n=0; n<tif->tif_nfields; n++) {
                    const TIFFField* o;
                    o = tif->tif_fields[n];
                    if ((o->field_bit>=FIELD_CODEC)&&(TIFFFieldSet(tif,o->field_bit)))
                    {
                        switch (o->get_field_type)
                        {
                            case TIFF_SETGET_ASCII:
                                {
                                    uint32 pa;
                                    char* pb;
                                    assert(o->field_type==TIFF_ASCII);
                                    assert(o->field_readcount==TIFF_VARIABLE);
                                    assert(o->field_passcount==0);
                                    TIFFGetField(tif,o->field_tag,&pb);
                                    pa=(uint32)(strlen(pb));
                                    if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,o->field_tag,pa,pb))
                                        goto bad;
                                }
                                break;
                            case TIFF_SETGET_UINT16:
                                {
                                    uint16 p;
                                    assert(o->field_type==TIFF_SHORT);
                                    assert(o->field_readcount==1);
                                    assert(o->field_passcount==0);
                                    TIFFGetField(tif,o->field_tag,&p);
                                    if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,o->field_tag,p))
                                        goto bad;
                                }
                                break;
                            case TIFF_SETGET_UINT32:
                                {
                                    uint32 p;
                                    assert(o->field_type==TIFF_LONG);
                                    assert(o->field_readcount==1);
                                    assert(o->field_passcount==0);
                                    TIFFGetField(tif,o->field_tag,&p);
                                    if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,o->field_tag,p))
                                        goto bad;
                                }
                                break;
                            case TIFF_SETGET_C32_UINT8:
                                {
                                    uint32 pa;
                                    void* pb;
                                    assert(o->field_type==TIFF_UNDEFINED);
                                    assert(o->field_readcount==TIFF_VARIABLE2);
                                    assert(o->field_passcount==1);
                                    TIFFGetField(tif,o->field_tag,&pa,&pb);
                                    if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,o->field_tag,pa,pb))
                                        goto bad;
                                }
                                break;
                            default:
                                assert(0);   /* we should never get here */
                                break;
                        }
                    }
                }
            }
        }
        for (m=0; m<(uint32)(tif->tif_dir.td_customValueCount); m++)
        {
            switch (tif->tif_dir.td_customValues[m].info->field_type)
            {
                case TIFF_ASCII:
                    if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_UNDEFINED:
                    if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_BYTE:
                    if (!TIFFWriteDirectoryTagByteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SBYTE:
                    if (!TIFFWriteDirectoryTagSbyteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SHORT:
                    if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SSHORT:
                    if (!TIFFWriteDirectoryTagSshortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_LONG:
                    if (!TIFFWriteDirectoryTagLongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SLONG:
                    if (!TIFFWriteDirectoryTagSlongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_LONG8:
                    if (!TIFFWriteDirectoryTagLong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SLONG8:
                    if (!TIFFWriteDirectoryTagSlong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_RATIONAL:
                    if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_SRATIONAL:
                    if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_FLOAT:
                    if (!TIFFWriteDirectoryTagFloatArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_DOUBLE:
                    if (!TIFFWriteDirectoryTagDoubleArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_IFD:
                    if (!TIFFWriteDirectoryTagIfdArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                case TIFF_IFD8:
                    if (!TIFFWriteDirectoryTagIfdIfd8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
                        goto bad;
                    break;
                default:
                    assert(0);   /* we should never get here */
                    break;
            }
        }
        if (dir!=NULL)
            break;
        dir=_TIFFmalloc(ndir*sizeof(TIFFDirEntry));
        if (dir==NULL)
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
            goto bad;
        }
        if (isimage)
        {
            if ((tif->tif_diroff==0)&&(!TIFFLinkDirectory(tif)))
                goto bad;
        }
        else
            tif->tif_diroff=(TIFFSeekFile(tif,0,SEEK_END)+1)&(~1);
        if (pdiroff!=NULL)
            *pdiroff=tif->tif_diroff;
        if (!(tif->tif_flags&TIFF_BIGTIFF))
            dirsize=2+ndir*12+4;
        else
            dirsize=8+ndir*20+8;
        tif->tif_dataoff=tif->tif_diroff+dirsize;
        if (!(tif->tif_flags&TIFF_BIGTIFF))
            tif->tif_dataoff=(uint32)tif->tif_dataoff;
        if ((tif->tif_dataoff<tif->tif_diroff)||(tif->tif_dataoff<(uint64)dirsize))
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
            goto bad;
        }
        if (tif->tif_dataoff&1)
            tif->tif_dataoff++;
        if (isimage)
            tif->tif_curdir++;
    }
    if (isimage)
    {
        if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0))
        {
            uint32 na;
            TIFFDirEntry* nb;
            for (na=0, nb=dir; ; na++, nb++)
            {
                assert(na<ndir);
                if (nb->tdir_tag==TIFFTAG_SUBIFD)
                    break;
            }
            if (!(tif->tif_flags&TIFF_BIGTIFF))
                tif->tif_subifdoff=tif->tif_diroff+2+na*12+8;
            else
                tif->tif_subifdoff=tif->tif_diroff+8+na*20+12;
        }
    }
    dirmem=_TIFFmalloc(dirsize);
    if (dirmem==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        goto bad;
    }
    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        uint8* n;
        uint32 nTmp;
        TIFFDirEntry* o;
        n=dirmem;
        *(uint16*)n=ndir;
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabShort((uint16*)n);
        n+=2;
        o=dir;
        for (m=0; m<ndir; m++)
        {
            *(uint16*)n=o->tdir_tag;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabShort((uint16*)n);
            n+=2;
            *(uint16*)n=o->tdir_type;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabShort((uint16*)n);
            n+=2;
            nTmp = (uint32)o->tdir_count;
            _TIFFmemcpy(n,&nTmp,4);
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabLong((uint32*)n);
            n+=4;
            /* This is correct. The data has been */
            /* swabbed previously in TIFFWriteDirectoryTagData */
            _TIFFmemcpy(n,&o->tdir_offset,4);
            n+=4;
            o++;
        }
        nTmp = (uint32)tif->tif_nextdiroff;
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong(&nTmp);
        _TIFFmemcpy(n,&nTmp,4);
    }
    else
    {
        uint8* n;
        TIFFDirEntry* o;
        n=dirmem;
        *(uint64*)n=ndir;
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8((uint64*)n);
        n+=8;
        o=dir;
        for (m=0; m<ndir; m++)
        {
            *(uint16*)n=o->tdir_tag;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabShort((uint16*)n);
            n+=2;
            *(uint16*)n=o->tdir_type;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabShort((uint16*)n);
            n+=2;
            _TIFFmemcpy(n,&o->tdir_count,8);
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabLong8((uint64*)n);
            n+=8;
            _TIFFmemcpy(n,&o->tdir_offset,8);
            n+=8;
            o++;
        }
        _TIFFmemcpy(n,&tif->tif_nextdiroff,8);
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8((uint64*)n);
    }
    _TIFFfree(dir);
    dir=NULL;
    if (!SeekOK(tif,tif->tif_diroff))
    {
        TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
        goto bad;
    }
    if (!WriteOK(tif,dirmem,(tmsize_t)dirsize))
    {
        TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
        goto bad;
    }
    _TIFFfree(dirmem);
    if (imagedone)
    {
        TIFFFreeDirectory(tif);
        tif->tif_flags &= ~TIFF_DIRTYDIRECT;
        tif->tif_flags &= ~TIFF_DIRTYSTRIP;
        (*tif->tif_cleanup)(tif);
        /*
        * Reset directory-related state for subsequent
        * directories.
        */
        TIFFCreateDirectory(tif);
    }
    return(1);
bad:
    if (dir!=NULL)
        _TIFFfree(dir);
    if (dirmem!=NULL)
        _TIFFfree(dirmem);
    return(0);
}

static int
TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
{
    static const char module[] = "TIFFWriteDirectoryTagSampleformatArray";
    void* conv;
    uint32 i;
    int ok;
    conv = _TIFFmalloc(count*sizeof(double));
    if (conv == NULL)
    {
        TIFFErrorExt(tif->tif_clientdata, module, "Out of memory");
        return (0);
    }

    switch (tif->tif_dir.td_sampleformat)
    {
        case SAMPLEFORMAT_IEEEFP:
            if (tif->tif_dir.td_bitspersample<=32)
            {
                for (i = 0; i < count; ++i)
                    ((float*)conv)[i] = (float)value[i];
                ok = TIFFWriteDirectoryTagFloatArray(tif,ndir,dir,tag,count,(float*)conv);
            }
            else
            {
                ok = TIFFWriteDirectoryTagDoubleArray(tif,ndir,dir,tag,count,value);
            }
            break;
        case SAMPLEFORMAT_INT:
            if (tif->tif_dir.td_bitspersample<=8)
            {
                for (i = 0; i < count; ++i)
                    ((int8*)conv)[i] = (int8)value[i];
                ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8*)conv);
            }
            else if (tif->tif_dir.td_bitspersample<=16)
            {
                for (i = 0; i < count; ++i)
                    ((int16*)conv)[i] = (int16)value[i];
                ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16*)conv);
            }
            else
            {
                for (i = 0; i < count; ++i)
                    ((int32*)conv)[i] = (int32)value[i];
                ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32*)conv);
            }
            break;
        case SAMPLEFORMAT_UINT:
            if (tif->tif_dir.td_bitspersample<=8)
            {
                for (i = 0; i < count; ++i)
                    ((uint8*)conv)[i] = (uint8)value[i];
                ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8*)conv);
            }
            else if (tif->tif_dir.td_bitspersample<=16)
            {
                for (i = 0; i < count; ++i)
                    ((uint16*)conv)[i] = (uint16)value[i];
                ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16*)conv);
            }
            else
            {
                for (i = 0; i < count; ++i)
                    ((uint32*)conv)[i] = (uint32)value[i];
                ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32*)conv);
            }
            break;
        default:
            ok = 0;
    }

    _TIFFfree(conv);
    return (ok);
}

#if 0
static int
TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    switch (tif->tif_dir.td_sampleformat)
    {
        case SAMPLEFORMAT_IEEEFP:
            if (tif->tif_dir.td_bitspersample<=32)
                return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value));
            else
                return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value));
        case SAMPLEFORMAT_INT:
            if (tif->tif_dir.td_bitspersample<=8)
                return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8)value));
            else if (tif->tif_dir.td_bitspersample<=16)
                return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16)value));
            else
                return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32)value));
        case SAMPLEFORMAT_UINT:
            if (tif->tif_dir.td_bitspersample<=8)
                return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8)value));
            else if (tif->tif_dir.td_bitspersample<=16)
                return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16)value));
            else
                return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32)value));
        default:
            return(1);
    }
}
#endif

static int
TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value));
}

static int
TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int
TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
{
    static const char module[] = "TIFFWriteDirectoryTagBytePerSample";
    uint8* m;
    uint8* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

#ifdef notdef
static int
TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int
TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
{
    static const char module[] = "TIFFWriteDirectoryTagSbytePerSample";
    int8* m;
    int8* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

static int
TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value));
}

static int
TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value));
}

static int
TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
{
    static const char module[] = "TIFFWriteDirectoryTagShortPerSample";
    uint16* m;
    uint16* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}

#ifdef notdef
static int
TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int
TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
{
    static const char module[] = "TIFFWriteDirectoryTagSshortPerSample";
    int16* m;
    int16* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

static int
TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
}

static int
TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int
TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
{
    static const char module[] = "TIFFWriteDirectoryTagLongPerSample";
    uint32* m;
    uint32* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

#ifdef notdef
static int
TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int
TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
{
    static const char module[] = "TIFFWriteDirectoryTagSlongPerSample";
    int32* m;
    int32* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

#ifdef notdef
static int
TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value));
}
#endif

static int
TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value));
}

static int
TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value));
}

static int
TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value));
}

static int
TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedSrationalArray(tif,ndir,dir,tag,count,value));
}

#ifdef notdef
static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value));
}
#endif

static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
{
    static const char module[] = "TIFFWriteDirectoryTagFloatPerSample";
    float* m;
    float* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

#ifdef notdef
static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value));
}
#endif

static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value));
}

#if 0
static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    static const char module[] = "TIFFWriteDirectoryTagDoublePerSample";
    double* m;
    double* na;
    uint16 nb;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
        *na=value;
    o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
    _TIFFfree(m);
    return(o);
}
#endif

static int
TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value));
}
#endif

static int
TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
{
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    if (value<=0xFFFF)
        return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16)value));
    else
        return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
}

/************************************************************************/
/*                TIFFWriteDirectoryTagLongLong8Array()                 */
/*                                                                      */
/*      Write out LONG8 array as LONG8 for BigTIFF or LONG for          */
/*      Classic TIFF with some checking.                                */
/************************************************************************/

static int
TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    static const char module[] = "TIFFWriteDirectoryTagLongLong8Array";
    uint64* ma;
    uint32 mb;
    uint32* p;
    uint32* q;
    int o;

    /* is this just a counting pass? */
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }

    /* We always write LONG8 for BigTIFF, no checking needed. */
    if( tif->tif_flags&TIFF_BIGTIFF )
        return TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,
                                                      tag,count,value);

    /*
    ** For classic tiff we want to verify everything is in range for LONG
    ** and convert to long format.
    */

    p = _TIFFmalloc(count*sizeof(uint32));
    if (p==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }

    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
    {
        if (*ma>0xFFFFFFFF)
        {
            TIFFErrorExt(tif->tif_clientdata,module,
                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
            _TIFFfree(p);
            return(0);
        }
        *q= (uint32)(*ma);
    }

    o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
    _TIFFfree(p);

    return(o);
}

/************************************************************************/
/*                 TIFFWriteDirectoryTagIfdIfd8Array()                  */
/*                                                                      */
/*      Write either IFD8 or IFD array depending on file type.          */
/************************************************************************/

static int
TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array";
    uint64* ma;
    uint32 mb;
    uint32* p;
    uint32* q;
    int o;

    /* is this just a counting pass? */
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }

    /* We always write IFD8 for BigTIFF, no checking needed. */
    if( tif->tif_flags&TIFF_BIGTIFF )
        return TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,
                                                     tag,count,value);

    /*
    ** For classic tiff we want to verify everything is in range for IFD
    ** and convert to long format.
    */

    p = _TIFFmalloc(count*sizeof(uint32));
    if (p==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }

    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
    {
        if (*ma>0xFFFFFFFF)
        {
            TIFFErrorExt(tif->tif_clientdata,module,
                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
            _TIFFfree(p);
            return(0);
        }
        *q= (uint32)(*ma);
    }

    o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p);
    _TIFFfree(p);

    return(o);
}

#ifdef notdef
static int
TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array";
    uint64* ma;
    uint32 mb;
    uint8 n;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    n=0;
    for (ma=value, mb=0; mb<count; ma++, mb++)
    {
        if ((n==0)&&(*ma>0xFFFF))
            n=1;
        if ((n==1)&&(*ma>0xFFFFFFFF))
        {
            n=2;
            break;
        }
    }
    if (n==0)
    {
        uint16* p;
        uint16* q;
        p=_TIFFmalloc(count*sizeof(uint16));
        if (p==NULL)
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
            return(0);
        }
        for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
            *q=(uint16)(*ma);
        o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p);
        _TIFFfree(p);
    }
    else if (n==1)
    {
        uint32* p;
        uint32* q;
        p=_TIFFmalloc(count*sizeof(uint32));
        if (p==NULL)
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
            return(0);
        }
        for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
            *q=(uint32)(*ma);
        o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
        _TIFFfree(p);
    }
    else
    {
        assert(n==2);
        o=TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value);
    }
    return(o);
}
#endif
static int
TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
{
    static const char module[] = "TIFFWriteDirectoryTagColormap";
    uint32 m;
    uint16* n;
    int o;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=(1<<tif->tif_dir.td_bitspersample);
    n=_TIFFmalloc(3*m*sizeof(uint16));
    if (n==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    _TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16));
    _TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16));
    _TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16));
    o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n);
    _TIFFfree(n);
    return(o);
}

static int
TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
{
    static const char module[] = "TIFFWriteDirectoryTagTransferfunction";
    uint32 m;
    uint16 n;
    uint16* o;
    int p;
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=(1<<tif->tif_dir.td_bitspersample);
    n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples;
    /*
     * Check if the table can be written as a single column,
     * or if it must be written as 3 columns.  Note that we
     * write a 3-column tag if there are 2 samples/pixel and
     * a single column of data won't suffice--hmm.
     */
    if (n>3)
        n=3;
    if (n==3)
    {
        if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16)))
            n=2;
    }
    if (n==2)
    {
        if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16)))
            n=1;
    }
    if (n==0)
        n=1;
    o=_TIFFmalloc(n*m*sizeof(uint16));
    if (o==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    _TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16));
    if (n>1)
        _TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16));
    if (n>2)
        _TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16));
    p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o);
    _TIFFfree(o);
    return(p);
}

static int
TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
{
    static const char module[] = "TIFFWriteDirectoryTagSubifd";
    uint64 m;
    int n;
    if (tif->tif_dir.td_nsubifd==0)
        return(1);
    if (dir==NULL)
    {
        (*ndir)++;
        return(1);
    }
    m=tif->tif_dataoff;
    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        uint32* o;
        uint64* pa;
        uint32* pb;
        uint16 p;
        o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32));
        if (o==NULL)
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
            return(0);
        }
        pa=tif->tif_dir.td_subifd;
        pb=o;
        for (p=0; p < tif->tif_dir.td_nsubifd; p++)
        {
                        assert(pa != 0);
            assert(*pa <= 0xFFFFFFFFUL);
            *pb++=(uint32)(*pa++);
        }
        n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o);
        _TIFFfree(o);
    }
    else
        n=TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,tif->tif_dir.td_subifd);
    if (!n)
        return(0);
    /*
     * Total hack: if this directory includes a SubIFD
     * tag then force the next <n> directories to be
     * written as ``sub directories'' of this one.  This
     * is used to write things like thumbnails and
     * image masks that one wants to keep out of the
     * normal directory linkage access mechanism.
     */
    tif->tif_flags|=TIFF_INSUBIFD;
    tif->tif_nsubifd=tif->tif_dir.td_nsubifd;
    if (tif->tif_dir.td_nsubifd==1)
        tif->tif_subifdoff=0;
    else
        tif->tif_subifdoff=m;
    return(1);
}

static int
TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
{
    assert(sizeof(char)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value));
}

static int
TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
{
    assert(sizeof(uint8)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
{
    assert(sizeof(uint8)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value));
}
#endif

static int
TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
{
    assert(sizeof(uint8)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
{
    assert(sizeof(int8)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value));
}
#endif

static int
TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
{
    assert(sizeof(int8)==1);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value));
}

static int
TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
{
    uint16 m;
    assert(sizeof(uint16)==2);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabShort(&m);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,1,2,&m));
}

static int
TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
{
    assert(count<0x80000000);
    assert(sizeof(uint16)==2);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfShort(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
{
    int16 m;
    assert(sizeof(int16)==2);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabShort((uint16*)(&m));
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
{
    assert(count<0x80000000);
    assert(sizeof(int16)==2);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfShort((uint16*)value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value));
}

static int
TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
{
    uint32 m;
    assert(sizeof(uint32)==4);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabLong(&m);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,1,4,&m));
}

static int
TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
{
    assert(count<0x40000000);
    assert(sizeof(uint32)==4);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
{
    int32 m;
    assert(sizeof(int32)==4);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabLong((uint32*)(&m));
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
{
    assert(count<0x40000000);
    assert(sizeof(int32)==4);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong((uint32*)value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
{
    uint64 m;
    assert(sizeof(uint64)==8);
    assert(tif->tif_flags&TIFF_BIGTIFF);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabLong8(&m);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    assert(count<0x20000000);
    assert(sizeof(uint64)==8);
    assert(tif->tif_flags&TIFF_BIGTIFF);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong8(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
{
    int64 m;
    assert(sizeof(int64)==8);
    assert(tif->tif_flags&TIFF_BIGTIFF);
    m=value;
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabLong8((uint64*)(&m));
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
{
    assert(count<0x20000000);
    assert(sizeof(int64)==8);
    assert(tif->tif_flags&TIFF_BIGTIFF);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong8((uint64*)value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value));
}

static int
TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    uint32 m[2];
    assert(value>=0.0);
    assert(sizeof(uint32)==4);
    if (value<=0.0)
    {
        m[0]=0;
        m[1]=1;
    }
    else if (value==(double)(uint32)value)
    {
        m[0]=(uint32)value;
        m[1]=1;
    }
    else if (value<1.0)
    {
        m[0]=(uint32)(value*0xFFFFFFFF);
        m[1]=0xFFFFFFFF;
    }
    else
    {
        m[0]=0xFFFFFFFF;
        m[1]=(uint32)(0xFFFFFFFF/value);
    }
    if (tif->tif_flags&TIFF_SWAB)
    {
        TIFFSwabLong(&m[0]);
        TIFFSwabLong(&m[1]);
    }
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,1,8,&m[0]));
}

static int
TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray";
    uint32* m;
    float* na;
    uint32* nb;
    uint32 nc;
    int o;
    assert(sizeof(uint32)==4);
    m=_TIFFmalloc(count*2*sizeof(uint32));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
    {
        if (*na<=0.0)
        {
            nb[0]=0;
            nb[1]=1;
        }
        else if (*na==(float)(uint32)(*na))
        {
            nb[0]=(uint32)(*na);
            nb[1]=1;
        }
        else if (*na<1.0)
        {
            nb[0]=(uint32)((*na)*0xFFFFFFFF);
            nb[1]=0xFFFFFFFF;
        }
        else
        {
            nb[0]=0xFFFFFFFF;
            nb[1]=(uint32)(0xFFFFFFFF/(*na));
        }
    }
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong(m,count*2);
    o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]);
    _TIFFfree(m);
    return(o);
}

static int
TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray";
    int32* m;
    float* na;
    int32* nb;
    uint32 nc;
    int o;
    assert(sizeof(int32)==4);
    m=_TIFFmalloc(count*2*sizeof(int32));
    if (m==NULL)
    {
        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
        return(0);
    }
    for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
    {
        if (*na<0.0)
        {
            if (*na==(int32)(*na))
            {
                nb[0]=(int32)(*na);
                nb[1]=1;
            }
            else if (*na>-1.0)
            {
                nb[0]=-(int32)((-*na)*0x7FFFFFFF);
                nb[1]=0x7FFFFFFF;
            }
            else
            {
                nb[0]=-0x7FFFFFFF;
                nb[1]=(int32)(0x7FFFFFFF/(-*na));
            }
        }
        else
        {
            if (*na==(int32)(*na))
            {
                nb[0]=(int32)(*na);
                nb[1]=1;
            }
            else if (*na<1.0)
            {
                nb[0]=(int32)((*na)*0x7FFFFFFF);
                nb[1]=0x7FFFFFFF;
            }
            else
            {
                nb[0]=0x7FFFFFFF;
                nb[1]=(int32)(0x7FFFFFFF/(*na));
            }
        }
    }
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong((uint32*)m,count*2);
    o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]);
    _TIFFfree(m);
    return(o);
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
{
    float m;
    assert(sizeof(float)==4);
    m=value;
    TIFFCvtNativeToIEEEFloat(tif,1,&m);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabFloat(&m);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
{
    assert(count<0x40000000);
    assert(sizeof(float)==4);
    TIFFCvtNativeToIEEEFloat(tif,count,&value);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfFloat(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,count,count*4,value));
}

#ifdef notdef
static int
TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
{
    double m;
    assert(sizeof(double)==8);
    m=value;
    TIFFCvtNativeToIEEEDouble(tif,1,&m);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabDouble(&m);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m));
}
#endif

static int
TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
{
    assert(count<0x20000000);
    assert(sizeof(double)==8);
    TIFFCvtNativeToIEEEDouble(tif,count,&value);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfDouble(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,count,count*8,value));
}

static int
TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
{
    assert(count<0x40000000);
    assert(sizeof(uint32)==4);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD,count,count*4,value));
}

static int
TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{
    assert(count<0x20000000);
    assert(sizeof(uint64)==8);
    assert(tif->tif_flags&TIFF_BIGTIFF);
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabArrayOfLong8(value,count);
    return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD8,count,count*8,value));
}

static int
TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data)
{
    static const char module[] = "TIFFWriteDirectoryTagData";
    uint32 m;
    m=0;
    while (m<(*ndir))
    {
        assert(dir[m].tdir_tag!=tag);
        if (dir[m].tdir_tag>tag)
            break;
        m++;
    }
    if (m<(*ndir))
    {
        uint32 n;
        for (n=*ndir; n>m; n--)
            dir[n]=dir[n-1];
    }
    dir[m].tdir_tag=tag;
    dir[m].tdir_type=datatype;
    dir[m].tdir_count=count;
    dir[m].tdir_offset.toff_long8 = 0;
    if (datalength<=((tif->tif_flags&TIFF_BIGTIFF)?0x8U:0x4U))
        _TIFFmemcpy(&dir[m].tdir_offset,data,datalength);
    else
    {
        uint64 na,nb;
        na=tif->tif_dataoff;
        nb=na+datalength;
        if (!(tif->tif_flags&TIFF_BIGTIFF))
            nb=(uint32)nb;
        if ((nb<na)||(nb<datalength))
        {
            TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
            return(0);
        }
        if (!SeekOK(tif,na))
        {
            TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
            return(0);
        }
        assert(datalength<0x80000000UL);
        if (!WriteOK(tif,data,(tmsize_t)datalength))
        {
            TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
            return(0);
        }
        tif->tif_dataoff=nb;
        if (tif->tif_dataoff&1)
            tif->tif_dataoff++;
        if (!(tif->tif_flags&TIFF_BIGTIFF))
        {
            uint32 o;
            o=(uint32)na;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabLong(&o);
            _TIFFmemcpy(&dir[m].tdir_offset,&o,4);
        }
        else
        {
            dir[m].tdir_offset.toff_long8 = na;
            if (tif->tif_flags&TIFF_SWAB)
                TIFFSwabLong8(&dir[m].tdir_offset.toff_long8);
        }
    }
    (*ndir)++;
    return(1);
}

/*
 * Link the current directory into the directory chain for the file.
 */
static int
TIFFLinkDirectory(TIFF* tif)
{
    static const char module[] = "TIFFLinkDirectory";

    tif->tif_diroff = (TIFFSeekFile(tif,0,SEEK_END)+1) &~ 1;

    /*
     * Handle SubIFDs
     */
    if (tif->tif_flags & TIFF_INSUBIFD)
    {
        if (!(tif->tif_flags&TIFF_BIGTIFF))
        {
            uint32 m;
            m = (uint32)tif->tif_diroff;
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong(&m);
            (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
            if (!WriteOK(tif, &m, 4)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                     "Error writing SubIFD directory link");
                return (0);
            }
            /*
             * Advance to the next SubIFD or, if this is
             * the last one configured, revert back to the
             * normal directory linkage.
             */
            if (--tif->tif_nsubifd)
                tif->tif_subifdoff += 4;
            else
                tif->tif_flags &= ~TIFF_INSUBIFD;
            return (1);
        }
        else
        {
            uint64 m;
            m = tif->tif_diroff;
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong8(&m);
            (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
            if (!WriteOK(tif, &m, 8)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                     "Error writing SubIFD directory link");
                return (0);
            }
            /*
             * Advance to the next SubIFD or, if this is
             * the last one configured, revert back to the
             * normal directory linkage.
             */
            if (--tif->tif_nsubifd)
                tif->tif_subifdoff += 8;
            else
                tif->tif_flags &= ~TIFF_INSUBIFD;
            return (1);
        }
    }

    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        uint32 m;
        uint32 nextdir;
        m = (uint32)(tif->tif_diroff);
        if (tif->tif_flags & TIFF_SWAB)
            TIFFSwabLong(&m);
        if (tif->tif_header.classic.tiff_diroff == 0) {
            /*
             * First directory, overwrite offset in header.
             */
            tif->tif_header.classic.tiff_diroff = (uint32) tif->tif_diroff;
            (void) TIFFSeekFile(tif,4, SEEK_SET);
            if (!WriteOK(tif, &m, 4)) {
                TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                         "Error writing TIFF header");
                return (0);
            }
            return (1);
        }
        /*
         * Not the first directory, search to the last and append.
         */
        nextdir = tif->tif_header.classic.tiff_diroff;
        while(1) {
            uint16 dircount;
            uint32 nextnextdir;

            if (!SeekOK(tif, nextdir) ||
                !ReadOK(tif, &dircount, 2)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory count");
                return (0);
            }
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabShort(&dircount);
            (void) TIFFSeekFile(tif,
                nextdir+2+dircount*12, SEEK_SET);
            if (!ReadOK(tif, &nextnextdir, 4)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory link");
                return (0);
            }
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong(&nextnextdir);
            if (nextnextdir==0)
            {
                (void) TIFFSeekFile(tif,
                    nextdir+2+dircount*12, SEEK_SET);
                if (!WriteOK(tif, &m, 4)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error writing directory link");
                    return (0);
                }
                break;
            }
            nextdir=nextnextdir;
        }
    }
    else
    {
        uint64 m;
        uint64 nextdir;
        m = tif->tif_diroff;
        if (tif->tif_flags & TIFF_SWAB)
            TIFFSwabLong8(&m);
        if (tif->tif_header.big.tiff_diroff == 0) {
            /*
             * First directory, overwrite offset in header.
             */
            tif->tif_header.big.tiff_diroff = tif->tif_diroff;
            (void) TIFFSeekFile(tif,8, SEEK_SET);
            if (!WriteOK(tif, &m, 8)) {
                TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                         "Error writing TIFF header");
                return (0);
            }
            return (1);
        }
        /*
         * Not the first directory, search to the last and append.
         */
        nextdir = tif->tif_header.big.tiff_diroff;
        while(1) {
            uint64 dircount64;
            uint16 dircount;
            uint64 nextnextdir;

            if (!SeekOK(tif, nextdir) ||
                !ReadOK(tif, &dircount64, 8)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory count");
                return (0);
            }
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong8(&dircount64);
            if (dircount64>0xFFFF)
            {
                TIFFErrorExt(tif->tif_clientdata, module,
                         "Sanity check on tag count failed, likely corrupt TIFF");
                return (0);
            }
            dircount=(uint16)dircount64;
            (void) TIFFSeekFile(tif,
                nextdir+8+dircount*20, SEEK_SET);
            if (!ReadOK(tif, &nextnextdir, 8)) {
                TIFFErrorExt(tif->tif_clientdata, module,
                         "Error fetching directory link");
                return (0);
            }
            if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong8(&nextnextdir);
            if (nextnextdir==0)
            {
                (void) TIFFSeekFile(tif,
                    nextdir+8+dircount*20, SEEK_SET);
                if (!WriteOK(tif, &m, 8)) {
                    TIFFErrorExt(tif->tif_clientdata, module,
                         "Error writing directory link");
                    return (0);
                }
                break;
            }
            nextdir=nextnextdir;
        }
    }
    return (1);
}

/************************************************************************/
/*                          TIFFRewriteField()                          */
/*                                                                      */
/*      Rewrite a field in the directory on disk without regard to      */
/*      updating the TIFF directory structure in memory.  Currently     */
/*      only supported for field that already exist in the on-disk      */
/*      directory.  Mainly used for updating stripoffset /              */
/*      stripbytecount values after the directory is already on         */
/*      disk.                                                           */
/*                                                                      */
/*      Returns zero on failure, and one on success.                    */
/************************************************************************/

int
_TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype,
                  tmsize_t count, void* data)
{
    static const char module[] = "TIFFResetField";
    const TIFFField* fip = NULL;
    uint16 dircount;
    tmsize_t dirsize;
    uint8 direntry_raw[20];
    uint16 entry_tag = 0;
    uint16 entry_type = 0;
    uint64 entry_count = 0;
    uint64 entry_offset = 0;
    int    value_in_entry = 0;
    uint64 read_offset;
    uint8 *buf_to_write = NULL;
    TIFFDataType datatype;

/* -------------------------------------------------------------------- */
/*      Find field definition.                                          */
/* -------------------------------------------------------------------- */
    fip = TIFFFindField(tif, tag, TIFF_ANY);

/* -------------------------------------------------------------------- */
/*      Do some checking this is a straight forward case.               */
/* -------------------------------------------------------------------- */
    if( isMapped(tif) )
    {
        TIFFErrorExt( tif->tif_clientdata, module,
                      "Memory mapped files not currently supported for this operation." );
        return 0;
    }

    if( tif->tif_diroff == 0 )
    {
        TIFFErrorExt( tif->tif_clientdata, module,
                      "Attempt to reset field on directory not already on disk." );
        return 0;
    }

/* -------------------------------------------------------------------- */
/*      Read the directory entry count.                                 */
/* -------------------------------------------------------------------- */
    if (!SeekOK(tif, tif->tif_diroff)) {
        TIFFErrorExt(tif->tif_clientdata, module,
                     "%s: Seek error accessing TIFF directory",
                     tif->tif_name);
        return 0;
    }

    read_offset = tif->tif_diroff;

    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        if (!ReadOK(tif, &dircount, 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(&dircount);
        dirsize = 12;
        read_offset += 2;
    } 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);
        dircount = (uint16)dircount64;
        dirsize = 20;
        read_offset += 8;
    }

/* -------------------------------------------------------------------- */
/*      Read through directory to find target tag.                      */
/* -------------------------------------------------------------------- */
    while( dircount > 0 )
    {
        if (!ReadOK(tif, direntry_raw, dirsize)) {
            TIFFErrorExt(tif->tif_clientdata, module,
                         "%s: Can not read TIFF directory entry.",
                         tif->tif_name);
            return 0;
        }

        memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabShort( &entry_tag );

        if( entry_tag == tag )
            break;

        read_offset += dirsize;
    }

    if( entry_tag != tag )
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                     "%s: Could not find tag %d.",
                     tif->tif_name, tag );
        return 0;
    }

/* -------------------------------------------------------------------- */
/*      Extract the type, count and offset for this entry.              */
/* -------------------------------------------------------------------- */
    memcpy( &entry_type, direntry_raw + 2, sizeof(uint16) );
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabShort( &entry_type );

    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        uint32 value;

        memcpy( &value, direntry_raw + 4, sizeof(uint32) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong( &value );
        entry_count = value;

        memcpy( &value, direntry_raw + 8, sizeof(uint32) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong( &value );
        entry_offset = value;
    }
    else
    {
        memcpy( &entry_count, direntry_raw + 4, sizeof(uint64) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8( &entry_count );

        memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8( &entry_offset );
    }

/* -------------------------------------------------------------------- */
/*      What data type do we want to write this as?                     */
/* -------------------------------------------------------------------- */
    if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) )
    {
        if( in_datatype == TIFF_LONG8 )
            datatype = TIFF_LONG;
        else if( in_datatype == TIFF_SLONG8 )
            datatype = TIFF_SLONG;
        else if( in_datatype == TIFF_IFD8 )
            datatype = TIFF_IFD;
        else
            datatype = in_datatype;
    }
    else
        datatype = in_datatype;

/* -------------------------------------------------------------------- */
/*      Prepare buffer of actual data to write.  This includes          */
/*      swabbing as needed.                                             */
/* -------------------------------------------------------------------- */
    buf_to_write =
        (uint8 *)_TIFFCheckMalloc(tif, count, TIFFDataWidth(datatype),
                      "for field buffer.");
    if (!buf_to_write)
        return 0;

    if( datatype == in_datatype )
        memcpy( buf_to_write, data, count * TIFFDataWidth(datatype) );
    else if( datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8 )
    {
    tmsize_t i;

        for( i = 0; i < count; i++ )
        {
            ((int32 *) buf_to_write)[i] =
                (int32) ((int64 *) data)[i];
            if( (int64) ((int32 *) buf_to_write)[i] != ((int64 *) data)[i] )
            {
                _TIFFfree( buf_to_write );
                TIFFErrorExt( tif->tif_clientdata, module,
                              "Value exceeds 32bit range of output type." );
                return 0;
            }
        }
    }
    else if( (datatype == TIFF_LONG && in_datatype == TIFF_LONG8)
             || (datatype == TIFF_IFD && in_datatype == TIFF_IFD8) )
    {
    tmsize_t i;

        for( i = 0; i < count; i++ )
        {
            ((uint32 *) buf_to_write)[i] =
                (uint32) ((uint64 *) data)[i];
            if( (uint64) ((uint32 *) buf_to_write)[i] != ((uint64 *) data)[i] )
            {
                _TIFFfree( buf_to_write );
                TIFFErrorExt( tif->tif_clientdata, module,
                              "Value exceeds 32bit range of output type." );
                return 0;
            }
        }
    }

    if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) )
    {
        if( TIFFDataWidth(datatype) == 2 )
            TIFFSwabArrayOfShort( (uint16 *) buf_to_write, count );
        else if( TIFFDataWidth(datatype) == 4 )
            TIFFSwabArrayOfLong( (uint32 *) buf_to_write, count );
        else if( TIFFDataWidth(datatype) == 8 )
            TIFFSwabArrayOfLong8( (uint64 *) buf_to_write, count );
    }

/* -------------------------------------------------------------------- */
/*      Is this a value that fits into the directory entry?             */
/* -------------------------------------------------------------------- */
    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        if( TIFFDataWidth(datatype) * count <= 4 )
        {
            entry_offset = read_offset + 8;
            value_in_entry = 1;
        }
    }
    else
    {
        if( TIFFDataWidth(datatype) * count <= 8 )
        {
            entry_offset = read_offset + 12;
            value_in_entry = 1;
        }
    }

/* -------------------------------------------------------------------- */
/*      If the tag type, and count match, then we just write it out     */
/*      over the old values without altering the directory entry at     */
/*      all.                                                            */
/* -------------------------------------------------------------------- */
    if( entry_count == (uint64)count && entry_type == (uint16) datatype )
    {
        if (!SeekOK(tif, entry_offset)) {
            _TIFFfree( buf_to_write );
            TIFFErrorExt(tif->tif_clientdata, module,
                         "%s: Seek error accessing TIFF directory",
                         tif->tif_name);
            return 0;
        }
        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
            _TIFFfree( buf_to_write );
            TIFFErrorExt(tif->tif_clientdata, module,
                         "Error writing directory link");
            return (0);
        }

        _TIFFfree( buf_to_write );
        return 1;
    }

/* -------------------------------------------------------------------- */
/*      Otherwise, we write the new tag data at the end of the file.    */
/* -------------------------------------------------------------------- */
    if( !value_in_entry )
    {
        entry_offset = TIFFSeekFile(tif,0,SEEK_END);

        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
            _TIFFfree( buf_to_write );
            TIFFErrorExt(tif->tif_clientdata, module,
                         "Error writing directory link");
            return (0);
        }

        _TIFFfree( buf_to_write );
    }
    else
    {
        memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype));
    }

/* -------------------------------------------------------------------- */
/*      Adjust the directory entry.                                     */
/* -------------------------------------------------------------------- */
    entry_type = datatype;
    memcpy( direntry_raw + 2, &entry_type, sizeof(uint16) );
    if (tif->tif_flags&TIFF_SWAB)
        TIFFSwabShort( (uint16 *) (direntry_raw + 2) );

    if (!(tif->tif_flags&TIFF_BIGTIFF))
    {
        uint32 value;

        value = (uint32) entry_count;
        memcpy( direntry_raw + 4, &value, sizeof(uint32) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong( (uint32 *) (direntry_raw + 4) );

        value = (uint32) entry_offset;
        memcpy( direntry_raw + 8, &value, sizeof(uint32) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong( (uint32 *) (direntry_raw + 8) );
    }
    else
    {
        memcpy( direntry_raw + 4, &entry_count, sizeof(uint64) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8( (uint64 *) (direntry_raw + 4) );

        memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64) );
        if (tif->tif_flags&TIFF_SWAB)
            TIFFSwabLong8( (uint64 *) (direntry_raw + 12) );
    }

/* -------------------------------------------------------------------- */
/*      Write the directory entry out to disk.                          */
/* -------------------------------------------------------------------- */
    if (!SeekOK(tif, read_offset )) {
        TIFFErrorExt(tif->tif_clientdata, module,
                     "%s: Seek error accessing TIFF directory",
                     tif->tif_name);
        return 0;
    }

    if (!WriteOK(tif, direntry_raw,dirsize))
    {
        TIFFErrorExt(tif->tif_clientdata, module,
                     "%s: Can not write TIFF directory entry.",
                     tif->tif_name);
        return 0;
    }

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