Update to 2.0.0 tree from current Fremantle build
[opencv] / 3rdparty / libtiff / tif_dirwrite.c
diff --git a/3rdparty/libtiff/tif_dirwrite.c b/3rdparty/libtiff/tif_dirwrite.c
new file mode 100644 (file)
index 0000000..3870bb8
--- /dev/null
@@ -0,0 +1,1238 @@
+/* $Id: tif_dirwrite.c,v 1.1 2005-06-17 13:54:52 vp153 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"
+
+#if HAVE_IEEEFP
+#define        TIFFCvtNativeToIEEEFloat(tif, n, fp)
+#define        TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*);
+extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*);
+#endif
+
+static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*);
+static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32);
+static void TIFFSetupShort(TIFF*, ttag_t, TIFFDirEntry*, uint16);
+static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*);
+static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**);
+static int TIFFWriteShortArray(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFWriteLongArray(TIFF *, TIFFDirEntry*, uint32*);
+static int TIFFWriteRationalArray(TIFF *, TIFFDirEntry*, float*);
+static int TIFFWriteFloatArray(TIFF *, TIFFDirEntry*, float*);
+static int TIFFWriteDoubleArray(TIFF *, TIFFDirEntry*, double*);
+static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*);
+static int TIFFWriteAnyArray(TIFF*,
+           TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*);
+static int TIFFWriteInkNames(TIFF*, TIFFDirEntry*);
+static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*);
+static int TIFFLinkDirectory(TIFF*);
+
+#define        WriteRationalPair(type, tag1, v1, tag2, v2) {           \
+       TIFFWriteRational((tif), (type), (tag1), (dir), (v1))   \
+       TIFFWriteRational((tif), (type), (tag2), (dir)+1, (v2)) \
+       (dir)++;                                                \
+}
+#define        TIFFWriteRational(tif, type, tag, dir, v)               \
+       (dir)->tdir_tag = (tag);                                \
+       (dir)->tdir_type = (type);                              \
+       (dir)->tdir_count = 1;                                  \
+       if (!TIFFWriteRationalArray((tif), (dir), &(v)))        \
+               goto bad;
+
+/*
+ * 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;
+       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)) {
+                           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;
+                       
+                       dir->tdir_tag = (uint16) tag;
+                       dir->tdir_type = (uint16) TIFF_LONG;
+                       dir->tdir_count = (uint32) td->td_nstrips;
+                       if (!TIFFWriteLongArray(tif, dir, 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;
+                       
+                       dir->tdir_tag = (uint16) tag;
+                       dir->tdir_type = (uint16) TIFF_LONG;
+                       dir->tdir_count = (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);
+                       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:
+               case FIELD_YCBCRSUBSAMPLING:
+               case FIELD_DOTRANGE:
+                       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:
+                       /*
+                        * XXX: Always write this field using LONG type
+                        * for backward compatibility.
+                        */
+                       dir->tdir_tag = (uint16) fip->field_tag;
+                       dir->tdir_type = (uint16) TIFF_LONG;
+                       dir->tdir_count = (uint32) td->td_nsubifd;
+                       if (!TIFFWriteLongArray(tif, dir, td->td_subifd))
+                               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;
+               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);
+}
+#undef WriteRationalPair
+
+int
+TIFFWriteDirectory(TIFF* tif)
+{
+       return _TIFFWriteDirectory(tif, TRUE);
+}
+
+/*
+ * 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 = _TIFFWriteDirectory(tif, FALSE);
+       (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
+       return rc;
+}
+
+/*
+ * Process tags that are not special cased.
+ */
+static int
+TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
+{
+       uint16 wc = (uint16) fip->field_writecount;
+       uint32 wc2;
+
+       dir->tdir_tag = (uint16) fip->field_tag;
+       dir->tdir_type = (uint16) fip->field_type;
+       dir->tdir_count = wc;
+       
+       switch (fip->field_type) {
+       case TIFF_SHORT:
+       case TIFF_SSHORT:
+               if (fip->field_passcount) {
+                       uint16* wp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &wp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &wp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteShortArray(tif, dir, wp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               uint16 sv;
+                               TIFFGetField(tif, fip->field_tag, &sv);
+                               dir->tdir_offset =
+                                       TIFFInsertData(tif, dir->tdir_type, sv);
+                       } else {
+                               uint16* wp;
+                               TIFFGetField(tif, fip->field_tag, &wp);
+                               if (!TIFFWriteShortArray(tif, dir, wp))
+                                       return 0;
+                       }
+               }
+               break;
+       case TIFF_LONG:
+       case TIFF_SLONG:
+       case TIFF_IFD:
+               if (fip->field_passcount) {
+                       uint32* lp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &lp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &lp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteLongArray(tif, dir, lp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               /* XXX handle LONG->SHORT conversion */
+                               TIFFGetField(tif, fip->field_tag,
+                                            &dir->tdir_offset);
+                       } else {
+                               uint32* lp;
+                               TIFFGetField(tif, fip->field_tag, &lp);
+                               if (!TIFFWriteLongArray(tif, dir, lp))
+                                       return 0;
+                       }
+               }
+               break;
+       case TIFF_RATIONAL:
+       case TIFF_SRATIONAL:
+               if (fip->field_passcount) {
+                       float* fp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &fp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &fp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteRationalArray(tif, dir, fp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               float fv;
+                               TIFFGetField(tif, fip->field_tag, &fv);
+                               if (!TIFFWriteRationalArray(tif, dir, &fv))
+                                       return 0;
+                       } else {
+                               float* fp;
+                               TIFFGetField(tif, fip->field_tag, &fp);
+                               if (!TIFFWriteRationalArray(tif, dir, fp))
+                                       return 0;
+                       }
+               }
+               break;
+       case TIFF_FLOAT:
+               if (fip->field_passcount) {
+                       float* fp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &fp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &fp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteFloatArray(tif, dir, fp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               float fv;
+                               TIFFGetField(tif, fip->field_tag, &fv);
+                               if (!TIFFWriteFloatArray(tif, dir, &fv))
+                                       return 0;
+                       } else {
+                               float* fp;
+                               TIFFGetField(tif, fip->field_tag, &fp);
+                               if (!TIFFWriteFloatArray(tif, dir, fp))
+                                       return 0;
+                       }
+               }
+               break;
+       case TIFF_DOUBLE:
+               if (fip->field_passcount) {
+                       double* dp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &dp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &dp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteDoubleArray(tif, dir, dp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               double dv;
+                               TIFFGetField(tif, fip->field_tag, &dv);
+                               if (!TIFFWriteDoubleArray(tif, dir, &dv))
+                                       return 0;
+                       } else {
+                               double* dp;
+                               TIFFGetField(tif, fip->field_tag, &dp);
+                               if (!TIFFWriteDoubleArray(tif, dir, dp))
+                                       return 0;
+                       }
+               }
+               break;
+       case TIFF_ASCII:
+               { 
+                    char* cp;
+                    if (fip->field_passcount)
+                        TIFFGetField(tif, fip->field_tag, &wc, &cp);
+                    else
+                        TIFFGetField(tif, fip->field_tag, &cp);
+
+                    dir->tdir_count = (uint32) (strlen(cp) + 1);
+                    if (!TIFFWriteByteArray(tif, dir, cp))
+                        return (0);
+               }
+               break;
+
+        case TIFF_BYTE:
+        case TIFF_SBYTE:          
+               if (fip->field_passcount) {
+                       char* cp;
+                       if (wc == (uint16) TIFF_VARIABLE2) {
+                               TIFFGetField(tif, fip->field_tag, &wc2, &cp);
+                               dir->tdir_count = wc2;
+                       } else {        /* Assume TIFF_VARIABLE */
+                               TIFFGetField(tif, fip->field_tag, &wc, &cp);
+                               dir->tdir_count = wc;
+                       }
+                       if (!TIFFWriteByteArray(tif, dir, cp))
+                               return 0;
+               } else {
+                       if (wc == 1) {
+                               char cv;
+                               TIFFGetField(tif, fip->field_tag, &cv);
+                               if (!TIFFWriteByteArray(tif, dir, &cv))
+                                       return 0;
+                       } else {
+                               char* cp;
+                               TIFFGetField(tif, fip->field_tag, &cp);
+                               if (!TIFFWriteByteArray(tif, dir, cp))
+                                       return 0;
+                       }
+               }
+                break;
+
+       case TIFF_UNDEFINED:
+               { char* cp;
+                 if (wc == (unsigned short) TIFF_VARIABLE) {
+                       TIFFGetField(tif, fip->field_tag, &wc, &cp);
+                       dir->tdir_count = wc;
+                 } else if (wc == (unsigned short) TIFF_VARIABLE2) {
+                       TIFFGetField(tif, fip->field_tag, &wc2, &cp);
+                       dir->tdir_count = wc2;
+                 } else 
+                       TIFFGetField(tif, fip->field_tag, &cp);
+                 if (!TIFFWriteByteArray(tif, dir, cp))
+                       return (0);
+               }
+               break;
+
+        case TIFF_NOTYPE:
+                break;
+       }
+       return (1);
+}
+
+/*
+ * Setup a directory entry with either a SHORT
+ * or LONG type according to the value.
+ */
+static void
+TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
+{
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_count = 1;
+       if (v > 0xffffL) {
+               dir->tdir_type = (short) TIFF_LONG;
+               dir->tdir_offset = v;
+       } else {
+               dir->tdir_type = (short) TIFF_SHORT;
+               dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+       }
+}
+
+/*
+ * Setup a SHORT directory entry
+ */
+static void
+TIFFSetupShort(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint16 v)
+{
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_count = 1;
+       dir->tdir_type = (short) TIFF_SHORT;
+       dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+}
+#undef MakeShortDirent
+
+#define        NITEMS(x)       (sizeof (x) / sizeof (x[0]))
+/*
+ * Setup a directory entry that references a
+ * samples/pixel array of SHORT values and
+ * (potentially) write the associated indirect
+ * values.
+ */
+static int
+TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+       uint16 buf[10], v;
+       uint16* w = buf;
+       int i, status, samples = tif->tif_dir.td_samplesperpixel;
+
+       if (samples > NITEMS(buf)) {
+               w = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+               if (w == NULL) {
+                       TIFFError(tif->tif_name,
+                           "No space to write per-sample shorts");
+                       return (0);
+               }
+       }
+       TIFFGetField(tif, tag, &v);
+       for (i = 0; i < samples; i++)
+               w[i] = v;
+       
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_type = (uint16) TIFF_SHORT;
+       dir->tdir_count = samples;
+       status = TIFFWriteShortArray(tif, dir, w);
+       if (w != buf)
+               _TIFFfree((char*) w);
+       return (status);
+}
+
+/*
+ * Setup a directory entry that references a samples/pixel array of ``type''
+ * values and (potentially) write the associated indirect values.  The source
+ * data from TIFFGetField() for the specified tag must be returned as double.
+ */
+static int
+TIFFWritePerSampleAnys(TIFF* tif,
+    TIFFDataType type, ttag_t tag, TIFFDirEntry* dir)
+{
+       double buf[10], v;
+       double* w = buf;
+       int i, status;
+       int samples = (int) tif->tif_dir.td_samplesperpixel;
+
+       if (samples > NITEMS(buf)) {
+               w = (double*) _TIFFmalloc(samples * sizeof (double));
+               if (w == NULL) {
+                       TIFFError(tif->tif_name,
+                           "No space to write per-sample values");
+                       return (0);
+               }
+       }
+       TIFFGetField(tif, tag, &v);
+       for (i = 0; i < samples; i++)
+               w[i] = v;
+       status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w);
+       if (w != buf)
+               _TIFFfree(w);
+       return (status);
+}
+#undef NITEMS
+
+/*
+ * Setup a pair of shorts that are returned by
+ * value, rather than as a reference to an array.
+ */
+static int
+TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+       uint16 v[2];
+
+       TIFFGetField(tif, tag, &v[0], &v[1]);
+
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_type = (uint16) TIFF_SHORT;
+       dir->tdir_count = 2;
+       return (TIFFWriteShortArray(tif, dir, v));
+}
+
+/*
+ * Setup a directory entry for an NxM table of shorts,
+ * where M is known to be 2**bitspersample, and write
+ * the associated indirect data.
+ */
+static int
+TIFFWriteShortTable(TIFF* tif,
+    ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table)
+{
+       uint32 i, off;
+
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_type = (short) TIFF_SHORT;
+       /* XXX -- yech, fool TIFFWriteData */
+       dir->tdir_count = (uint32) (1L<<tif->tif_dir.td_bitspersample);
+       off = tif->tif_dataoff;
+       for (i = 0; i < n; i++)
+               if (!TIFFWriteData(tif, dir, (char *)table[i]))
+                       return (0);
+       dir->tdir_count *= n;
+       dir->tdir_offset = off;
+       return (1);
+}
+
+/*
+ * Write/copy data associated with an ASCII or opaque tag value.
+ */
+static int
+TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+       if (dir->tdir_count > 4) {
+               if (!TIFFWriteData(tif, dir, cp))
+                       return (0);
+       } else
+               _TIFFmemcpy(&dir->tdir_offset, cp, dir->tdir_count);
+       return (1);
+}
+
+/*
+ * Setup a directory entry of an array of SHORT
+ * or SSHORT and write the associated indirect values.
+ */
+static int
+TIFFWriteShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+       if (dir->tdir_count <= 2) {
+               if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+                       dir->tdir_offset = (uint32) ((long) v[0] << 16);
+                       if (dir->tdir_count == 2)
+                               dir->tdir_offset |= v[1] & 0xffff;
+               } else {
+                       dir->tdir_offset = v[0] & 0xffff;
+                       if (dir->tdir_count == 2)
+                               dir->tdir_offset |= (long) v[1] << 16;
+               }
+               return (1);
+       } else
+               return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of LONG
+ * or SLONG and write the associated indirect values.
+ */
+static int
+TIFFWriteLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v)
+{
+       if (dir->tdir_count == 1) {
+               dir->tdir_offset = v[0];
+               return (1);
+       } else
+               return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of RATIONAL
+ * or SRATIONAL and write the associated indirect values.
+ */
+static int
+TIFFWriteRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+       uint32 i;
+       uint32* t;
+       int status;
+
+       t = (uint32*) _TIFFmalloc(2 * dir->tdir_count * sizeof (uint32));
+       if (t == NULL) {
+               TIFFError(tif->tif_name,
+                   "No space to write RATIONAL array");
+               return (0);
+       }
+       for (i = 0; i < dir->tdir_count; i++) {
+               float fv = v[i];
+               int sign = 1;
+               uint32 den;
+
+               if (fv < 0) {
+                       if (dir->tdir_type == TIFF_RATIONAL) {
+                               TIFFWarning(tif->tif_name,
+       "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL",
+                               _TIFFFieldWithTag(tif,dir->tdir_tag)->field_name,
+                               fv);
+                               fv = 0;
+                       } else
+                               fv = -fv, sign = -1;
+               }
+               den = 1L;
+               if (fv > 0) {
+                       while (fv < 1L<<(31-3) && den < 1L<<(31-3))
+                               fv *= 1<<3, den *= 1L<<3;
+               }
+               t[2*i+0] = (uint32) (sign * (fv + 0.5));
+               t[2*i+1] = den;
+       }
+       status = TIFFWriteData(tif, dir, (char *)t);
+       _TIFFfree((char*) t);
+       return (status);
+}
+
+static int
+TIFFWriteFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+       TIFFCvtNativeToIEEEFloat(tif, dir->tdir_count, v);
+       if (dir->tdir_count == 1) {
+               dir->tdir_offset = *(uint32*) &v[0];
+               return (1);
+       } else
+               return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+static int
+TIFFWriteDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+       TIFFCvtNativeToIEEEDouble(tif, n, v);
+       return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Write an array of ``type'' values for a specified tag (i.e. this is a tag
+ * which is allowed to have different types, e.g. SMaxSampleType).
+ * Internally the data values are represented as double since a double can
+ * hold any of the TIFF tag types (yes, this should really be an abstract
+ * type tany_t for portability).  The data is converted into the specified
+ * type in a temporary buffer and then handed off to the appropriate array
+ * writer.
+ */
+static int
+TIFFWriteAnyArray(TIFF* tif,
+    TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+       char buf[10 * sizeof(double)];
+       char* w = buf;
+       int i, status = 0;
+
+       if (n * TIFFDataWidth(type) > sizeof buf) {
+               w = (char*) _TIFFmalloc(n * TIFFDataWidth(type));
+               if (w == NULL) {
+                       TIFFError(tif->tif_name,
+                           "No space to write array");
+                       return (0);
+               }
+       }
+
+       dir->tdir_tag = (uint16) tag;
+       dir->tdir_type = (uint16) type;
+       dir->tdir_count = n;
+
+       switch (type) {
+       case TIFF_BYTE:
+               { 
+                       uint8* bp = (uint8*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (uint8) v[i];
+                       if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+                               goto out;
+               }
+               break;
+       case TIFF_SBYTE:
+               { 
+                       int8* bp = (int8*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (int8) v[i];
+                       if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+                               goto out;
+               }
+               break;
+       case TIFF_SHORT:
+               {
+                       uint16* bp = (uint16*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (uint16) v[i];
+                       if (!TIFFWriteShortArray(tif, dir, (uint16*)bp))
+                               goto out;
+               }
+               break;
+       case TIFF_SSHORT:
+               { 
+                       int16* bp = (int16*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (int16) v[i];
+                       if (!TIFFWriteShortArray(tif, dir, (uint16*)bp))
+                               goto out;
+               }
+               break;
+       case TIFF_LONG:
+               {
+                       uint32* bp = (uint32*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (uint32) v[i];
+                       if (!TIFFWriteLongArray(tif, dir, bp))
+                               goto out;
+               }
+               break;
+       case TIFF_SLONG:
+               {
+                       int32* bp = (int32*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (int32) v[i];
+                       if (!TIFFWriteLongArray(tif, dir, (uint32*) bp))
+                               goto out;
+               }
+               break;
+       case TIFF_FLOAT:
+               { 
+                       float* bp = (float*) w;
+                       for (i = 0; i < (int) n; i++)
+                               bp[i] = (float) v[i];
+                       if (!TIFFWriteFloatArray(tif, dir, bp))
+                               goto out;
+               }
+               break;
+       case TIFF_DOUBLE:
+               return (TIFFWriteDoubleArray(tif, dir, v));
+       default:
+               /* TIFF_NOTYPE */
+               /* TIFF_ASCII */
+               /* TIFF_UNDEFINED */
+               /* TIFF_RATIONAL */
+               /* TIFF_SRATIONAL */
+               goto out;
+       }
+       status = 1;
+ out:
+       if (w != buf)
+               _TIFFfree(w);
+       return (status);
+}
+
+static int
+TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir)
+{
+       TIFFDirectory* td = &tif->tif_dir;
+       tsize_t n = (1L<<td->td_bitspersample) * sizeof (uint16);
+       uint16** tf = td->td_transferfunction;
+       int ncols;
+
+       /*
+        * 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.
+        */
+       switch (td->td_samplesperpixel - td->td_extrasamples) {
+       default:        if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; }
+       case 2:         if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; }
+       case 1: case 0: ncols = 1;
+       }
+       return (TIFFWriteShortTable(tif,
+           TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf));
+}
+
+static int
+TIFFWriteInkNames(TIFF* tif, TIFFDirEntry* dir)
+{
+       TIFFDirectory* td = &tif->tif_dir;
+
+       dir->tdir_tag = TIFFTAG_INKNAMES;
+       dir->tdir_type = (short) TIFF_ASCII;
+       dir->tdir_count = td->td_inknameslen;
+       return (TIFFWriteByteArray(tif, dir, td->td_inknames));
+}
+
+/*
+ * Write a contiguous directory item.
+ */
+static int
+TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+       tsize_t cc;
+
+       if (tif->tif_flags & TIFF_SWAB) {
+               switch (dir->tdir_type) {
+               case TIFF_SHORT:
+               case TIFF_SSHORT:
+                       TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+                       break;
+               case TIFF_LONG:
+               case TIFF_SLONG:
+               case TIFF_FLOAT:
+                       TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+                       break;
+               case TIFF_RATIONAL:
+               case TIFF_SRATIONAL:
+                       TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+                       break;
+               case TIFF_DOUBLE:
+                       TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+                       break;
+               }
+       }
+       dir->tdir_offset = tif->tif_dataoff;
+       cc = dir->tdir_count * TIFFDataWidth((TIFFDataType) dir->tdir_type);
+       if (SeekOK(tif, dir->tdir_offset) &&
+           WriteOK(tif, cp, cc)) {
+               tif->tif_dataoff += (cc + 1) & ~1;
+               return (1);
+       }
+       TIFFError(tif->tif_name, "Error writing data for field \"%s\"",
+           _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+       return (0);
+}
+
+/*
+ * 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.
+    */
+    
+    /* Is it the first directory in the file? */
+    if (tif->tif_header.tiff_diroff == tif->tif_diroff) 
+    {
+        tif->tif_header.tiff_diroff = 0;
+        tif->tif_diroff = 0;
+
+        TIFFSeekFile(tif, (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE),
+                    SEEK_SET);
+        if (!WriteOK(tif, &(tif->tif_header.tiff_diroff), 
+                     sizeof (tif->tif_diroff))) 
+        {
+            TIFFError(tif->tif_name, "Error updating TIFF header");
+            return (0);
+        }
+    }
+    else
+    {
+        toff_t  nextdir, off;
+
+       nextdir = tif->tif_header.tiff_diroff;
+       do {
+               uint16 dircount;
+
+               if (!SeekOK(tif, nextdir) ||
+                   !ReadOK(tif, &dircount, sizeof (dircount))) {
+                       TIFFError(module, "Error fetching directory count");
+                       return (0);
+               }
+               if (tif->tif_flags & TIFF_SWAB)
+                       TIFFSwabShort(&dircount);
+               (void) TIFFSeekFile(tif,
+                   dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+               if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+                       TIFFError(module, "Error fetching directory link");
+                       return (0);
+               }
+               if (tif->tif_flags & TIFF_SWAB)
+                       TIFFSwabLong(&nextdir);
+       } while (nextdir != tif->tif_diroff && nextdir != 0);
+        off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */
+        (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET);
+        tif->tif_diroff = 0;
+       if (!WriteOK(tif, &(tif->tif_diroff), sizeof (nextdir))) {
+               TIFFError(module, "Error writing directory link");
+               return (0);
+       }
+    }
+
+    /*
+    ** Now use TIFFWriteDirectory() normally.
+    */
+
+    return TIFFWriteDirectory( tif );
+}
+
+
+/*
+ * Link the current directory into the
+ * directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+       static const char module[] = "TIFFLinkDirectory";
+       toff_t nextdir;
+       toff_t diroff, off;
+
+       tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+       diroff = tif->tif_diroff;
+       if (tif->tif_flags & TIFF_SWAB)
+               TIFFSwabLong(&diroff);
+
+       /*
+        * Handle SubIFDs
+        */
+        if (tif->tif_flags & TIFF_INSUBIFD) {
+               (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+               if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+                       TIFFError(module,
+                           "%s: Error writing SubIFD directory link",
+                           tif->tif_name);
+                       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 += sizeof (diroff);
+               else
+                       tif->tif_flags &= ~TIFF_INSUBIFD;
+               return (1);
+       }
+
+       if (tif->tif_header.tiff_diroff == 0) {
+               /*
+                * First directory, overwrite offset in header.
+                */
+               tif->tif_header.tiff_diroff = tif->tif_diroff;
+               (void) TIFFSeekFile(tif,
+                                   (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE),
+                                    SEEK_SET);
+               if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+                       TIFFError(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.tiff_diroff;
+       do {
+               uint16 dircount;
+
+               if (!SeekOK(tif, nextdir) ||
+                   !ReadOK(tif, &dircount, sizeof (dircount))) {
+                       TIFFError(module, "Error fetching directory count");
+                       return (0);
+               }
+               if (tif->tif_flags & TIFF_SWAB)
+                       TIFFSwabShort(&dircount);
+               (void) TIFFSeekFile(tif,
+                   dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+               if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+                       TIFFError(module, "Error fetching directory link");
+                       return (0);
+               }
+               if (tif->tif_flags & TIFF_SWAB)
+                       TIFFSwabLong(&nextdir);
+       } while (nextdir != 0);
+        off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */
+        (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET);
+       if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+               TIFFError(module, "Error writing directory link");
+               return (0);
+       }
+       return (1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */