Esempio n. 1
0
/*
 * 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.
 */
static int
_TIFFWriteDirectory(TIFF* tif, int done)
{
	uint16 dircount;
	toff_t diroff;
	ttag_t tag;
	uint32 nfields;
	tsize_t dirsize;
	char* data;
	TIFFDirEntry* dir;
	TIFFDirectory* td;
	u_long b, fields[FIELD_SETLONGS];
	int fi, nfi;

	if (tif->tif_mode == O_RDONLY)
		return (1);
	/*
	 * Clear write state so that subsequent images with
	 * different characteristics get the right buffers
	 * setup for them.
	 */
	if (done)
	{
	    if (tif->tif_flags & TIFF_POSTENCODE) {
		    tif->tif_flags &= ~TIFF_POSTENCODE;
		    if (!(*tif->tif_postencode)(tif)) {
			    TIFFError(tif->tif_name,
				"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.
	     */
	    if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) {
		    TIFFError(tif->tif_name,
			"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_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
	}

	td = &tif->tif_dir;
	/*
	 * Size the directory so that we can calculate
	 * offsets for the data items that aren't kept
	 * in-place in each field.
	 */
	nfields = 0;
	for (b = 0; b <= FIELD_LAST; b++)
		if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM)
			nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
        nfields += td->td_customValueCount;
	dirsize = nfields * sizeof (TIFFDirEntry);
	data = (char*) _TIFFmalloc(dirsize);
	if (data == NULL) {
		TIFFError(tif->tif_name,
		    "Cannot write directory, out of space");
		return (0);
	}
	/*
	 * Directory hasn't been placed yet, put
	 * it at the end of the file and link it
	 * into the existing directory structure.
	 */
	if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif))
		goto bad;
	tif->tif_dataoff = (toff_t)(
	    tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
	if (tif->tif_dataoff & 1)
		tif->tif_dataoff++;
	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
	tif->tif_curdir++;
	dir = (TIFFDirEntry*) data;
	/*
	 * Setup external form of directory
	 * entries and write data items.
	 */
	_TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields));
	/*
	 * Write out ExtraSamples tag only if
	 * extra samples are present in the data.
	 */
	if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) {
		ResetFieldBit(fields, FIELD_EXTRASAMPLES);
		nfields--;
		dirsize -= sizeof (TIFFDirEntry);
	}								/*XXX*/
	for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
		const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];

                /*
                ** For custom fields, we test to see if the custom field
                ** is set or not.  For normal fields, we just use the
                ** FieldSet test. 
                */
                if( fip->field_bit == FIELD_CUSTOM )
                {
                    int ci, is_set = FALSE;

                    for( ci = 0; ci < td->td_customValueCount; ci++ )
                        is_set |= (td->td_customValues[ci].info == fip);

                    if( !is_set )
                        continue;
                }
		else if (!FieldSet(fields, fip->field_bit))
                    continue;


                /*
                ** Handle other fields.
                */
		switch (fip->field_bit)
                {
		case FIELD_STRIPOFFSETS:
			/*
			 * We use one field bit for both strip and tile

			 * offsets, and so must be careful in selecting
			 * the appropriate field descriptor (so that tags
			 * are written in sorted order).
			 */
			tag = isTiled(tif) ?
			    TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS;
			if (tag != fip->field_tag)
				continue;
			if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir,
			    (uint32) td->td_nstrips, td->td_stripoffset))
				goto bad;
			break;
		case FIELD_STRIPBYTECOUNTS:
			/*
			 * We use one field bit for both strip and tile
			 * byte counts, and so must be careful in selecting
			 * the appropriate field descriptor (so that tags
			 * are written in sorted order).
			 */
			tag = isTiled(tif) ?
			    TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS;
			if (tag != fip->field_tag)
				continue;
			if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir,
			    (uint32) td->td_nstrips, td->td_stripbytecount))
				goto bad;
			break;
		case FIELD_ROWSPERSTRIP:
			TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP,
			    dir, td->td_rowsperstrip);
			break;
		case FIELD_COLORMAP:
			if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir,
			    3, td->td_colormap))
				goto bad;
			break;
		case FIELD_IMAGEDIMENSIONS:
			TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH,
			    dir++, td->td_imagewidth);
			TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH,
			    dir, td->td_imagelength);
			break;
		case FIELD_TILEDIMENSIONS:
			TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH,
			    dir++, td->td_tilewidth);
			TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH,
			    dir, td->td_tilelength);
			break;
		case FIELD_COMPRESSION:
			TIFFSetupShort(tif, TIFFTAG_COMPRESSION,
			    dir, td->td_compression);
			break;
		case FIELD_PHOTOMETRIC:
			TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC,
			    dir, td->td_photometric);
			break;
		case FIELD_POSITION:
			WriteRationalPair(TIFF_RATIONAL,
			    TIFFTAG_XPOSITION, td->td_xposition,
			    TIFFTAG_YPOSITION, td->td_yposition);
			break;
		case FIELD_RESOLUTION:
			WriteRationalPair(TIFF_RATIONAL,
			    TIFFTAG_XRESOLUTION, td->td_xresolution,
			    TIFFTAG_YRESOLUTION, td->td_yresolution);
			break;
		case FIELD_BITSPERSAMPLE:
		case FIELD_MINSAMPLEVALUE:
		case FIELD_MAXSAMPLEVALUE:
		case FIELD_SAMPLEFORMAT:
			if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir))
				goto bad;
			break;
		case FIELD_SMINSAMPLEVALUE:
		case FIELD_SMAXSAMPLEVALUE:
			if (!TIFFWritePerSampleAnys(tif,
			    _TIFFSampleToTagType(tif), fip->field_tag, dir))
				goto bad;
			break;
		case FIELD_PAGENUMBER:
		case FIELD_HALFTONEHINTS:
#ifdef YCBCR_SUPPORT
		case FIELD_YCBCRSUBSAMPLING:
#endif
#ifdef CMYK_SUPPORT
		case FIELD_DOTRANGE:
#endif
			if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
				goto bad;
			break;
#ifdef CMYK_SUPPORT
		case FIELD_INKNAMES:
			if (!TIFFWriteInkNames(tif, dir))
				goto bad;
			break;
#endif
#ifdef COLORIMETRY_SUPPORT
		case FIELD_TRANSFERFUNCTION:
			if (!TIFFWriteTransferFunction(tif, dir))
				goto bad;
			break;
#endif
#if SUBIFD_SUPPORT
		case FIELD_SUBIFD:
			if (!TIFFWriteNormalTag(tif, dir, fip))
				goto bad;
			/*
			 * 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.
			 */
			if (dir->tdir_count > 0) {
				tif->tif_flags |= TIFF_INSUBIFD;
				tif->tif_nsubifd = (uint16) dir->tdir_count;
				if (dir->tdir_count > 1)
					tif->tif_subifdoff = dir->tdir_offset;
				else
					tif->tif_subifdoff = (uint32)(
					      tif->tif_diroff
					    + sizeof (uint16)
					    + ((char*)&dir->tdir_offset-data));
			}
			break;
#endif
		default:
			if (!TIFFWriteNormalTag(tif, dir, fip))
				goto bad;
			break;
		}
		dir++;
                
                if( fip->field_bit != FIELD_CUSTOM )
                    ResetFieldBit(fields, fip->field_bit);
	}

	/*
	 * Write directory.
	 */
	dircount = (uint16) nfields;
	diroff = (uint32) tif->tif_nextdiroff;
	if (tif->tif_flags & TIFF_SWAB) {
		/*
		 * The file's byte order is opposite to the
		 * native machine architecture.  We overwrite
		 * the directory information with impunity
		 * because it'll be released below after we
		 * write it to the file.  Note that all the
		 * other tag construction routines assume that
		 * we do this byte-swapping; i.e. they only
		 * byte-swap indirect data.
		 */
		for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
			TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
			TIFFSwabArrayOfLong(&dir->tdir_count, 2);
		}
		dircount = (uint16) nfields;
		TIFFSwabShort(&dircount);
		TIFFSwabLong(&diroff);
	}
	(void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET);
	if (!WriteOK(tif, &dircount, sizeof (dircount))) {
		TIFFError(tif->tif_name, "Error writing directory count");
		goto bad;
	}
	if (!WriteOK(tif, data, dirsize)) {
		TIFFError(tif->tif_name, "Error writing directory contents");
		goto bad;
	}
	if (!WriteOK(tif, &diroff, sizeof (diroff))) {
		TIFFError(tif->tif_name, "Error writing directory link");
		goto bad;
	}
	if (done) {
		TIFFFreeDirectory(tif);
		tif->tif_flags &= ~TIFF_DIRTYDIRECT;
		(*tif->tif_cleanup)(tif);

		/*
		* Reset directory-related state for subsequent
		* directories.
		*/
		TIFFCreateDirectory(tif);
	}
	_TIFFfree(data);
	return (1);
bad:
	_TIFFfree(data);
	return (0);
}
Esempio n. 2
0
/* This function will write an entire directory to the disk, and return the
   offset value indicating where in the file it wrote the beginning of the
   directory structure. This is NOT the same as the offset value before
   calling this function, because some of the fields may have caused various
   data items to be written out BEFORE writing the directory structure.

   This code was basically written by ripping of the TIFFWriteDirectory() 
   code and generalizing it, using RPS's TIFFWritePliIfd() code for
   inspiration.  My original goal was to make this code general enough that
   the original TIFFWriteDirectory() could be rewritten to just call this
   function with the appropriate field and field-accessing arguments.

   However, now I realize that there's a lot of code that gets executed for
   the main, standard TIFF directories that does not apply to special
   private subdirectories, so such a reimplementation for the sake of
   eliminating redundant or duplicate code is probably not possible,
   unless we also pass in a Main flag to indiciate which type of handling
   to do, which would be kind of a hack. I've marked those places where I
   changed or ripped out code which would have to be re-inserted to
   generalize this function. If it can be done in a clean and graceful way,
   it would be a great way to generalize the TIFF library. Otherwise, I'll
   just leave this code here where it duplicates but remains on top of and
   hopefully mostly independent of the main TIFF library.

   The caller will probably want to free the sub directory structure after
   returning from this call, since otherwise once written out, the user
   is likely to forget about it and leave data lying around.
*/
toff_t
TIFFWritePrivateDataSubDirectory(TIFF* tif,
				 uint32 pdir_fieldsset[], int pdir_fields_last,
				 TIFFFieldInfo *field_info,
				 int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
{
	uint16 dircount;
	uint32 diroff, nextdiroff;
	ttag_t tag;
	uint32 nfields;
	tsize_t dirsize;
	char* data;
	TIFFDirEntry* dir;
	u_long b, *fields, fields_size;
	toff_t directory_offset;
	TIFFFieldInfo* fip;

	/*
	 * Deleted out all of the encoder flushing and such code from here -
	 * not necessary for subdirectories.
	 */

	/* Finish writing out any image data. */
	TIFFFlushData(tif);

	/*
	 * Size the directory so that we can calculate
	 * offsets for the data items that aren't kept
	 * in-place in each field.
	 */
	nfields = 0;
	for (b = 0; b <= pdir_fields_last; b++)
		if (FieldSet(pdir_fieldsset, b))
			/* Deleted code to make size of first 4 tags 2
			   instead of 1. */
			nfields += 1;
	dirsize = nfields * sizeof (TIFFDirEntry);
	data = (char*) _TIFFmalloc(dirsize);
	if (data == NULL) {
		TIFFError(tif->tif_name,
		    "Cannot write private subdirectory, out of space");
		return (0);
	}
	/*
	 * Place directory in data section of the file. If there isn't one
	 * yet, place it at the end of the file. The directory is treated as
	 * data, so we don't link it into the directory structure at all.
	 */
	if (tif->tif_dataoff == 0)
	    tif->tif_dataoff =(TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
	diroff = tif->tif_dataoff;
	tif->tif_dataoff = (toff_t)(
	    diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
	if (tif->tif_dataoff & 1)
		tif->tif_dataoff++;
	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
	/*tif->tif_curdir++;*/
	dir = (TIFFDirEntry*) data;
	/*
	 * Setup external form of directory
	 * entries and write data items.
	 */
	/*
	 * We make a local copy of the fieldsset here so that we don't mess
	 * up the original one when we call ResetFieldBit(). But I'm not sure
	 * why the original code calls ResetFieldBit(), since we're already
	 * going through the fields in order...
	 *
	 * fields_size is the number of uint32's we will need to hold the
	 * bit-mask for all of the fields. If our highest field number is
	 * 100, then we'll need 100 / (8*4)+1 == 4 uint32's to hold the
	 * fieldset.
	 *
	 * Unlike the original code, we allocate fields dynamically based
	 * on the requested pdir_fields_last value, allowing private
	 * data subdirectories to contain more than the built-in code's limit
	 * of 95 tags in a directory.
	 */
	fields_size = pdir_fields_last / (8*sizeof(uint32)) + 1;
	fields = _TIFFmalloc(fields_size*sizeof(uint32));
	_TIFFmemcpy(fields, pdir_fieldsset, fields_size * sizeof(uint32));

	/* Deleted "write out extra samples tag" code here. */

	/* Deleted code for checking a billion little special cases for the
	 * standard TIFF tags. Should add a general mechanism for overloading
	 * write function for each field, just like Brian kept telling me!!!
	 */
	for (fip = field_info; fip->field_tag; fip++) {
		/* Deleted code to check for FIELD_IGNORE!! */
		if (/* fip->field_bit == FIELD_IGNORE || */
		    !FieldSet(fields, fip->field_bit))
			continue;
		if (!TIFFWriteNormalSubTag(tif, dir, fip, getFieldFn))
			goto bad;
		dir++;
		ResetFieldBit(fields, fip->field_bit);
	}

	/* Now we've written all of the referenced data, and are about to
	   write the main directory structure, so grab the tif_dataoff value
	   now so we can remember where we wrote the directory. */
	directory_offset = tif->tif_dataoff;

	/*
	 * Write directory.
	 */
	dircount = (uint16) nfields;
	/* Deleted code to link to the next directory - we set it to zero! */
	nextdiroff = 0;
	if (tif->tif_flags & TIFF_SWAB) {
		/*
		 * The file's byte order is opposite to the
		 * native machine architecture.  We overwrite
		 * the directory information with impunity
		 * because it'll be released below after we
		 * write it to the file.  Note that all the
		 * other tag construction routines assume that
		 * we do this byte-swapping; i.e. they only
		 * byte-swap indirect data.
		 */
		for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
			TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
			TIFFSwabArrayOfLong(&dir->tdir_count, 2);
		}
		dircount = (uint16) nfields;
		TIFFSwabShort(&dircount);
		TIFFSwabLong(&nextdiroff);
	}

	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
	if (!WriteOK(tif, &dircount, sizeof (dircount))) {
		TIFFError(tif->tif_name, "Error writing private subdirectory count");
		goto bad;
	}
	if (!WriteOK(tif, data, dirsize)) {
		TIFFError(tif->tif_name, "Error writing private subdirectory contents");
		goto bad;
	}
	if (!WriteOK(tif, &nextdiroff, sizeof (nextdiroff))) {
		TIFFError(tif->tif_name, "Error writing private subdirectory link");
		goto bad;
	}
	tif->tif_dataoff += sizeof(dircount) + dirsize + sizeof(nextdiroff);

	_TIFFfree(data);
	_TIFFfree(fields);
	tif->tif_flags &= ~TIFF_DIRTYDIRECT;

#if (0)
	/* This stuff commented out because I don't think we want it for
	   subdirectories, but I could be wrong. */
	(*tif->tif_cleanup)(tif);

	/*
	 * Reset directory-related state for subsequent
	 * directories.
	 */
	TIFFDefaultDirectory(tif);
	tif->tif_curoff = 0;
	tif->tif_row = (uint32) -1;
	tif->tif_curstrip = (tstrip_t) -1;
#endif

	return (directory_offset);
bad:
	_TIFFfree(data);
	_TIFFfree(fields);
	return (0);
}
Esempio n. 3
0
static int
_TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff)
{
    uint16 dircount;
    uint32 nfields;
    tsize_t dirsize;
    char* data;
    TIFFDirEntry* dir;
    TIFFDirectory* td;
    unsigned long b, fields[FIELD_SETLONGS];
    int fi, nfi;

    if (tif->tif_mode == O_RDONLY)
        return (1);

    td = &tif->tif_dir;
    /*
     * Size the directory so that we can calculate
     * offsets for the data items that aren't kept
     * in-place in each field.
     */
    nfields = 0;
    for (b = 0; b <= FIELD_LAST; b++)
        if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM)
            nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
    nfields += td->td_customValueCount;
    dirsize = nfields * sizeof (TIFFDirEntry);
    data = (char*) _TIFFmalloc(dirsize);
    if (data == NULL) {
        TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                     "Cannot write directory, out of space");
        return (0);
    }
    /*
     * Put the directory  at the end of the file.
     */
    tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
    tif->tif_dataoff = (toff_t)(
                           tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
    if (tif->tif_dataoff & 1)
        tif->tif_dataoff++;
    (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
    dir = (TIFFDirEntry*) data;
    /*
     * Setup external form of directory
     * entries and write data items.
     */
    _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields));

    for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
        const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];

        /*
         * For custom fields, we test to see if the custom field
         * is set or not.  For normal fields, we just use the
         * FieldSet test.
        */
        if( fip->field_bit == FIELD_CUSTOM )
        {
            int ci, is_set = FALSE;

            for( ci = 0; ci < td->td_customValueCount; ci++ )
                is_set |= (td->td_customValues[ci].info == fip);

            if( !is_set )
                continue;
        }
        else if (!FieldSet(fields, fip->field_bit))
            continue;

        if( fip->field_bit != FIELD_CUSTOM )
            ResetFieldBit(fields, fip->field_bit);
    }

    /*
     * Write directory.
     */
    dircount = (uint16) nfields;
    *pdiroff = (uint32) tif->tif_nextdiroff;
    if (tif->tif_flags & TIFF_SWAB) {
        /*
         * The file's byte order is opposite to the
         * native machine architecture.  We overwrite
         * the directory information with impunity
         * because it'll be released below after we
         * write it to the file.  Note that all the
         * other tag construction routines assume that
         * we do this byte-swapping; i.e. they only
         * byte-swap indirect data.
         */
        for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
            TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
            TIFFSwabArrayOfLong(&dir->tdir_count, 2);
        }
        dircount = (uint16) nfields;
        TIFFSwabShort(&dircount);
        TIFFSwabLong(pdiroff);
    }
    (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET);
    if (!WriteOK(tif, &dircount, sizeof (dircount))) {
        TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                     "Error writing directory count");
        goto bad;
    }
    if (!WriteOK(tif, data, dirsize)) {
        TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                     "Error writing directory contents");
        goto bad;
    }
    if (!WriteOK(tif, pdiroff, sizeof (uint32))) {
        TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
                     "Error writing directory link");
        goto bad;
    }
    _TIFFfree(data);
    return (1);
bad:
    _TIFFfree(data);
    return (0);
}
Esempio n. 4
0
/*
 * 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.
 */
static int
_TIFFWriteDirectory(TIFF* tif, int done)
{
	uint64 dircount;	/* 16-bit or 64-bit directory entry count */
	toff_t diroff;		/* 32-bit or 64-bit directory offset */
	ttag_t tag;
	uint32 nfields;
	tsize_t dirsize;
	char* data;
	TIFFDirEntry* dir;
	TIFFDirectory* td;
	unsigned long b, fields[FIELD_SETLONGS];
	int fi, nfi;

	if (tif->tif_mode == O_RDONLY)
		return (1);
	/*
	 * Clear write state so that subsequent images with
	 * different characteristics get the right buffers
	 * setup for them.
	 */
	if (done)
	{
	    if (tif->tif_flags & TIFF_POSTENCODE) {
		    tif->tif_flags &= ~TIFF_POSTENCODE;
		    if (!(*tif->tif_postencode)(tif)) {
				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
				"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.
	     */
	    if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) {
			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
			"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_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
	}


	/*
	 * Loop to allow retry in case transition to BigTIFF required
	 */
	while (1) {

	/*
	 * Directory hasn't been placed yet, put
	 * it at the end of the file and link it
	 * into the existing directory structure.
	 */
	if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif))
		goto bad2;

	td = &tif->tif_dir;
	/*
	 * Size the directory so that we can calculate
	 * offsets for the data items that aren't kept
	 * in-place in each field.
	 */
	nfields = 0;
	for (b = 0; b <= FIELD_LAST; b++)
		if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM)
			nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
        nfields += td->td_customValueCount;
	dirsize = nfields * TDIREntryLen(tif);
	data = (char*) _TIFFmalloc(dirsize);
	if (data == NULL) {
		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
		    "Cannot write directory, out of space");
		goto bad2;
	}
	_TIFFmemset(data, 0, dirsize);
	/*
	 * Setup external form of directory
	 * entries and write data items.
	 */
	_TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields));
	/*
	 * Write out ExtraSamples tag only if
	 * extra samples are present in the data.
	 */
	if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) {
		ResetFieldBit(fields, FIELD_EXTRASAMPLES);
		nfields--;
		dirsize -= TDIREntryLen(tif);
	}								/*XXX*/

	tif->tif_dataoff = tif->tif_diroff + TIFFDirCntLen(tif) + dirsize + TIFFDirOffLen(tif);
	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
	dir = (TIFFDirEntry*) data;
	for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
		const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];

                /*
                ** For custom fields, we test to see if the custom field
                ** is set or not.  For normal fields, we just use the
                ** FieldSet test. 
                */
                if( fip->field_bit == FIELD_CUSTOM )
                {
                    int ci, is_set = FALSE;

                    for( ci = 0; ci < td->td_customValueCount; ci++ )
                        is_set |= (td->td_customValues[ci].info == fip);

                    if( !is_set )
                        continue;
                }
		else if (!FieldSet(fields, fip->field_bit))
                    continue;

                /*
                ** Handle other fields.
                */
		switch (fip->field_bit)
                {
		case FIELD_STRIPOFFSETS:
			/*
			 * We use one field bit for both strip and tile
			 * offsets, and so must be careful in selecting
			 * the appropriate field descriptor (so that tags
			 * are written in sorted order).
			 */
			tag = (isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS);
			if (tag != fip->field_tag)
				continue;
			
			dir->s.tdir_tag = (uint16) tag;
			TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips);
			/*
			 * If file is BigTIFF strip/tile offsets are written as 64-bit, 
			 * else convert to array of 32-bit offsets.
			 */
			if (isBigTIFF(tif)) {
				dir->s.tdir_type = (uint16) TIFF_LONG8;
				if (!TIFFWriteLong8Array(tif, dir, td->td_stripoffset))
					goto bad;
			} else {
				uint32 tdi;
				int status;
				uint32 *soff = _TIFFCheckMalloc(tif, td->td_nstrips, 
						sizeof(uint32), "32-bit offset array");

				dir->s.tdir_type = (uint16) TIFF_LONG;
				for (tdi = 0; tdi < td->td_nstrips; tdi++)
					soff[tdi] = (uint32) td->td_stripoffset[tdi];
				status = TIFFWriteLongArray(tif, dir, soff);
				_TIFFfree(soff);
				if (!status)
					goto bad;
			}
			break;
		case FIELD_STRIPBYTECOUNTS:
			/*
			 * We use one field bit for both strip and tile
			 * byte counts, and so must be careful in selecting
			 * the appropriate field descriptor (so that tags
			 * are written in sorted order).
			 */
			tag = (isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS);
			if (tag != fip->field_tag)
				continue;
			dir->s.tdir_tag = (uint16) tag;
			dir->s.tdir_type = (uint16) TIFF_LONG;
			TDIRSetEntryCount(tif,dir, (uint32) td->td_nstrips);
			if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount))
				goto bad;
			break;
		case FIELD_ROWSPERSTRIP:
			TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP,
			    dir, td->td_rowsperstrip);
			break;
		case FIELD_COLORMAP:
			if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir,
			    3, td->td_colormap))
				goto bad;
			break;
		case FIELD_IMAGEDIMENSIONS:
			TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH,
			    dir, td->td_imagewidth);
			TDIREntryNext(tif,dir);
			TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH,
			    dir, td->td_imagelength);
			break;
		case FIELD_TILEDIMENSIONS:
			TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH,
			    dir, td->td_tilewidth);
			TDIREntryNext(tif,dir);
			TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH,
			    dir, td->td_tilelength);
			break;
		case FIELD_COMPRESSION:
			TIFFSetupShort(tif, TIFFTAG_COMPRESSION,
			    dir, td->td_compression);
			break;
		case FIELD_PHOTOMETRIC:
			TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC,
			    dir, td->td_photometric);
			break;
		case FIELD_POSITION:
			WriteRationalPair(TIFF_RATIONAL,
			    TIFFTAG_XPOSITION, td->td_xposition,
			    TIFFTAG_YPOSITION, td->td_yposition);
			break;
		case FIELD_RESOLUTION:
			WriteRationalPair(TIFF_RATIONAL,
			    TIFFTAG_XRESOLUTION, td->td_xresolution,
			    TIFFTAG_YRESOLUTION, td->td_yresolution);
			break;
		case FIELD_BITSPERSAMPLE:
		case FIELD_MINSAMPLEVALUE:
		case FIELD_MAXSAMPLEVALUE:
		case FIELD_SAMPLEFORMAT:
			if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir))
				goto bad;
			break;
		case FIELD_SMINSAMPLEVALUE:
		case FIELD_SMAXSAMPLEVALUE:
			if (!TIFFWritePerSampleAnys(tif,
			    _TIFFSampleToTagType(tif), fip->field_tag, dir))
				goto bad;
			break;
		case FIELD_PAGENUMBER:
		case FIELD_HALFTONEHINTS:
		case FIELD_YCBCRSUBSAMPLING:
			if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
				goto bad;
			break;
		case FIELD_INKNAMES:
			if (!TIFFWriteInkNames(tif, dir))
				goto bad;
			break;
		case FIELD_TRANSFERFUNCTION:
			if (!TIFFWriteTransferFunction(tif, dir))
				goto bad;
			break;
		case FIELD_SUBIFD:
			/*
			 * 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.
			 *
			 * If file is BigTIFF subdirectory offsets are written as 64-bit, 
			 * else as array of 32-bit offsets.  At this point the actual
			 * offset values are unknown (will be set in TIFFLinkDirectory).
			 */
			dir->s.tdir_tag = (uint16) fip->field_tag;
			TDIRSetEntryCount(tif,dir, (uint32) td->td_nsubifd);
			TDIRSetEntryOff(tif,dir, 0);
			if (td->td_nsubifd > 0) {
				tif->tif_flags |= TIFF_INSUBIFD;
				if (isBigTIFF(tif)) {
					toff_t *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(toff_t),
						"Allocate SubIFD offset array");
					if (!doff) 
						goto bad;
					_TIFFmemset(doff, 0, td->td_nsubifd * sizeof(toff_t));
					dir->b.tdir_type = TIFF_IFD8;
					if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(toff_t))
						tif->tif_subifdoff = tif->tif_dataoff;
					else
						tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + 
							(char*) &dir->b.tdir_offset - data;
					if (!TIFFWriteLong8Array(tif, dir, (toff_t*) doff))
						goto bad;
					_TIFFfree(doff);
				} else {
					uint32 *doff = _TIFFCheckMalloc(tif, td->td_nsubifd, sizeof(uint32),
						"Allocate SubIFD offset array");
					if (!doff) 
						goto bad;
					_TIFFmemset(doff, 0, td->td_nsubifd * sizeof(uint32));
					dir->b.tdir_type = TIFF_LONG;
					if (td->td_nsubifd > TIFFDirOffLen(tif) / sizeof(uint32))
						tif->tif_subifdoff = tif->tif_dataoff;
					else
						tif->tif_subifdoff = tif->tif_diroff + TIFFDirCntLen(tif) + 
							(char*) &dir->s.tdir_offset - data;
					if (!TIFFWriteLongArray(tif, dir, doff))
						goto bad;
					_TIFFfree(doff);
				}
			}
			break;
		default:
			/* XXX: Should be fixed and removed. */
			if (fip->field_tag == TIFFTAG_DOTRANGE) {
				if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
					goto bad;
			}
			else if (!TIFFWriteNormalTag(tif, dir, fip))
				goto bad;
			break;
		}
		TDIREntryNext(tif,dir);
                
                if( fip->field_bit != FIELD_CUSTOM )
                    ResetFieldBit(fields, fip->field_bit);
	}

	/*
	 * Check if BigTIFF now required based on data location.  If so reset 
	 * data offset to overwrite already-written data for directory, then
	 * convert file to BigTIFF and loop to recreate directory.
	 */
	if (isBigTIFF(tif) || !isBigOff(tif->tif_dataoff + sizeof(uint32)))
		break;

	_TIFFfree(data);
	tif->tif_dataoff = tif->tif_diroff;
	if (!TIFFMakeBigTIFF(tif))
		goto bad2;
	tif->tif_diroff = 0;
	}			/* bottom of BigTIFF retry loop */

	/*
	 * Write directory.
	 */
	tif->tif_curdir++;
	TIFFSetDirCnt(tif,dircount, (uint32) nfields);
	TIFFSetDirOff(tif,diroff,tif->tif_nextdiroff);
	if (tif->tif_flags & TIFF_SWAB) {
		/*
		 * The file's byte order is opposite to the
		 * native machine architecture.  We overwrite
		 * the directory information with impunity
		 * because it'll be released below after we
		 * write it to the file.  Note that all the
		 * other tag construction routines assume that
		 * we do this byte-swapping; i.e. they only
		 * byte-swap indirect data.
		 */
		uint32 di;
		for (dir = (TIFFDirEntry*) data, di = 0; di < nfields; TDIREntryNext(tif,dir), di++) {
			TIFFSwabShort(&dir->s.tdir_tag);
			TIFFSwabShort(&dir->s.tdir_type);
			TDIRSwabEntryCount(tif,dir);
			TDIRSwabEntryOff(tif,dir);
		}
		TIFFSwabDirCnt(tif,&dircount);
		TIFFSwabDirOff(tif,&diroff);
	}
	(void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET);
	if (!WriteOK(tif, &dircount, TIFFDirCntLen(tif))) {
		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, 
			"Error writing directory count (%d)", TIFFGetErrno(tif));
		goto bad;
	}
	if (!WriteOK(tif, data, dirsize)) {
		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, 
			"Error writing directory contents (%d)", TIFFGetErrno(tif));
		goto bad;
	}
	if (!WriteOK(tif, &diroff, TIFFDirOffLen(tif))) {
		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, 
			"Error writing directory link (%d)", TIFFGetErrno(tif));
		goto bad;
	}
	if (done) {
		TIFFFreeDirectory(tif);
		tif->tif_flags &= ~TIFF_DIRTYDIRECT;
		(*tif->tif_cleanup)(tif);

		/*
		* Reset directory-related state for subsequent
		* directories.
		*/
		TIFFCreateDirectory(tif);
	}
	_TIFFfree(data);
	return (1);
bad:
	_TIFFfree(data);
bad2:
	return (0);
}