]> git.saurik.com Git - wxWidgets.git/blobdiff - src/tiff/tif_dirwrite.c
upgraded libtiff to 3.6.1 + security fixes (patch from Tim Kosse)
[wxWidgets.git] / src / tiff / tif_dirwrite.c
index ed4b0118c020dd7b5b7c4af4b911489fd467d221..df120153f20a4b426a630c49e20c62107bfb52cf 100644 (file)
@@ -41,6 +41,7 @@ extern        void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*);
 
 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*);
@@ -87,11 +88,11 @@ static      int TIFFWriteRational(TIFF*,
  * handle overwriting a directory with auxiliary
  * storage that's been changed.
  */
-int
-TIFFWriteDirectory(TIFF* tif)
+static int
+_TIFFWriteDirectory(TIFF* tif, int done)
 {
        uint16 dircount;
-       uint32 diroff;
+       toff_t diroff;
        ttag_t tag;
        uint32 nfields;
        tsize_t dirsize;
@@ -108,30 +109,34 @@ TIFFWriteDirectory(TIFF* tif)
         * different characteristics get the right buffers
         * setup for them.
         */
-       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);
-               }
+       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);
        }
-       (*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_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
 
        td = &tif->tif_dir;
        /*
@@ -141,8 +146,9 @@ TIFFWriteDirectory(TIFF* tif)
         */
        nfields = 0;
        for (b = 0; b <= FIELD_LAST; b++)
-               if (TIFFFieldSet(tif, 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) {
@@ -180,12 +186,35 @@ TIFFWriteDirectory(TIFF* tif)
        }                                                               /*XXX*/
        for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
                const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];
-               if (!FieldSet(fields, fip->field_bit))
-                       continue;
-               switch (fip->field_bit) {
+
+                /*
+                ** 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).
@@ -234,6 +263,14 @@ TIFFWriteDirectory(TIFF* tif)
                        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,
@@ -294,7 +331,7 @@ TIFFWriteDirectory(TIFF* tif)
                         */
                        if (dir->tdir_count > 0) {
                                tif->tif_flags |= TIFF_INSUBIFD;
-                               tif->tif_nsubifd = dir->tdir_count;
+                               tif->tif_nsubifd = (uint16) dir->tdir_count;
                                if (dir->tdir_count > 1)
                                        tif->tif_subifdoff = dir->tdir_offset;
                                else
@@ -311,8 +348,11 @@ TIFFWriteDirectory(TIFF* tif)
                        break;
                }
                dir++;
-               ResetFieldBit(fields, fip->field_bit);
+                
+                if( fip->field_bit != FIELD_CUSTOM )
+                    ResetFieldBit(fields, fip->field_bit);
        }
+
        /*
         * Write directory.
         */
@@ -350,20 +390,18 @@ TIFFWriteDirectory(TIFF* tif)
                TIFFError(tif->tif_name, "Error writing directory link");
                goto bad;
        }
-       TIFFFreeDirectory(tif);
-       _TIFFfree(data);
-       tif->tif_flags &= ~TIFF_DIRTYDIRECT;
-       (*tif->tif_cleanup)(tif);
+       if (done) {
+               TIFFFreeDirectory(tif);
+               tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+               (*tif->tif_cleanup)(tif);
 
-       /*
-        * Reset directory-related state for subsequent
-        * directories.
-        */
-       TIFFDefaultDirectory(tif);
-       tif->tif_diroff = 0;
-       tif->tif_curoff = 0;
-       tif->tif_row = (uint32) -1;
-       tif->tif_curstrip = (tstrip_t) -1;
+               /*
+               * Reset directory-related state for subsequent
+               * directories.
+               */
+               TIFFCreateDirectory(tif);
+       }
+       _TIFFfree(data);
        return (1);
 bad:
        _TIFFfree(data);
@@ -371,6 +409,30 @@ bad:
 }
 #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.
  */
@@ -380,7 +442,7 @@ TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
        u_short wc = (u_short) fip->field_writecount;
        uint32 wc2;
 
-       dir->tdir_tag = fip->field_tag;
+       dir->tdir_tag = (uint16) fip->field_tag;
        dir->tdir_type = (u_short) fip->field_type;
        dir->tdir_count = wc;
 #define        WRITEF(x,y)     x(tif, fip->field_type, fip->field_tag, dir, wc, y)
@@ -389,81 +451,123 @@ TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
        case TIFF_SSHORT:
                if (wc > 1) {
                        uint16* wp;
-                       if (wc == (u_short) TIFF_VARIABLE)
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount)
                                TIFFGetField(tif, fip->field_tag, &wc, &wp);
                        else
                                TIFFGetField(tif, fip->field_tag, &wp);
                        if (!WRITEF(TIFFWriteShortArray, wp))
                                return (0);
                } else {
-                       uint16 sv;
-                       TIFFGetField(tif, fip->field_tag, &sv);
-                       dir->tdir_offset =
-                           TIFFInsertData(tif, dir->tdir_type, sv);
+                       if (fip->field_passcount) {
+                               uint16* wp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &wp);
+                               if (!WRITEF(TIFFWriteShortArray, wp))
+                                       return 0;
+                       } else {
+                               uint16 sv;
+                               TIFFGetField(tif, fip->field_tag, &sv);
+                               dir->tdir_offset =
+                                       TIFFInsertData(tif, dir->tdir_type, sv);
+                       }
                }
                break;
        case TIFF_LONG:
        case TIFF_SLONG:
+       case TIFF_IFD:
                if (wc > 1) {
                        uint32* lp;
-                       if (wc == (u_short) TIFF_VARIABLE)
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount)
                                TIFFGetField(tif, fip->field_tag, &wc, &lp);
                        else
                                TIFFGetField(tif, fip->field_tag, &lp);
                        if (!WRITEF(TIFFWriteLongArray, lp))
                                return (0);
                } else {
-                       /* XXX handle LONG->SHORT conversion */
-                       TIFFGetField(tif, fip->field_tag, &dir->tdir_offset);
+                       if (fip->field_passcount) {
+                               uint32* lp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &lp);
+                               if (!WRITEF(TIFFWriteLongArray, lp))
+                                       return 0;
+                       } else {
+                               /* XXX handle LONG->SHORT conversion */
+                               TIFFGetField(tif, fip->field_tag,
+                                            &dir->tdir_offset);
+                       }
                }
                break;
        case TIFF_RATIONAL:
        case TIFF_SRATIONAL:
                if (wc > 1) {
                        float* fp;
-                       if (wc == (u_short) TIFF_VARIABLE)
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount)
                                TIFFGetField(tif, fip->field_tag, &wc, &fp);
                        else
                                TIFFGetField(tif, fip->field_tag, &fp);
                        if (!WRITEF(TIFFWriteRationalArray, fp))
                                return (0);
                } else {
-                       float fv;
-                       TIFFGetField(tif, fip->field_tag, &fv);
-                       if (!WRITEF(TIFFWriteRationalArray, &fv))
-                               return (0);
+                       if (fip->field_passcount) {
+                               float* fp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &fp);
+                               if (!WRITEF(TIFFWriteRationalArray, fp))
+                                       return 0;
+                       } else {
+                               float fv;
+                               TIFFGetField(tif, fip->field_tag, &fv);
+                               if (!WRITEF(TIFFWriteRationalArray, &fv))
+                                       return (0);
+                       }
                }
                break;
        case TIFF_FLOAT:
                if (wc > 1) {
                        float* fp;
-                       if (wc == (u_short) TIFF_VARIABLE)
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount)
                                TIFFGetField(tif, fip->field_tag, &wc, &fp);
                        else
                                TIFFGetField(tif, fip->field_tag, &fp);
                        if (!WRITEF(TIFFWriteFloatArray, fp))
                                return (0);
                } else {
-                       float fv;
-                       TIFFGetField(tif, fip->field_tag, &fv);
-                       if (!WRITEF(TIFFWriteFloatArray, &fv))
-                               return (0);
+                       if (fip->field_passcount) {
+                               float* fp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &fp);
+                               if (!WRITEF(TIFFWriteFloatArray, fp))
+                                       return 0;
+                       } else {
+                               float fv;
+                               TIFFGetField(tif, fip->field_tag, &fv);
+                               if (!WRITEF(TIFFWriteFloatArray, &fv))
+                                       return (0);
+                       }
                }
                break;
        case TIFF_DOUBLE:
                if (wc > 1) {
                        double* dp;
-                       if (wc == (u_short) TIFF_VARIABLE)
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount)
                                TIFFGetField(tif, fip->field_tag, &wc, &dp);
                        else
                                TIFFGetField(tif, fip->field_tag, &dp);
                        if (!WRITEF(TIFFWriteDoubleArray, dp))
                                return (0);
                } else {
-                       double dv;
-                       TIFFGetField(tif, fip->field_tag, &dv);
-                       if (!WRITEF(TIFFWriteDoubleArray, &dv))
-                               return (0);
+                       if (fip->field_passcount) {
+                               double* dp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &dp);
+                               if (!WRITEF(TIFFWriteDoubleArray, dp))
+                                       return 0;
+                       } else {
+                               double dv;
+                               TIFFGetField(tif, fip->field_tag, &dv);
+                               if (!WRITEF(TIFFWriteDoubleArray, &dv))
+                                       return (0);
+                       }
                }
                break;
        case TIFF_ASCII:
@@ -479,20 +583,32 @@ TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
            correctness not verified (FW, 99/08) */
         case TIFF_BYTE:
         case TIFF_SBYTE:          
-                if (wc > 1) {
-                    char* cp;
-                    if (wc == (u_short) TIFF_VARIABLE) {
-                        TIFFGetField(tif, fip->field_tag, &wc, &cp);
-                        dir->tdir_count = wc;
-                    } else
-                        TIFFGetField(tif, fip->field_tag, &cp);
-                    if (!TIFFWriteByteArray(tif, dir, cp))
-                        return (0);
+               if (wc > 1) {
+                       char* cp;
+                       if (wc == (u_short) TIFF_VARIABLE
+                           || fip->field_passcount) {
+                               TIFFGetField(tif, fip->field_tag, &wc, &cp);
+                               dir->tdir_count = wc;
+                       } else if (wc == (u_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);
                 } else {
-                    char cv;
-                    TIFFGetField(tif, fip->field_tag, &cv);
-                    if (!TIFFWriteByteArray(tif, dir, &cv))
-                        return (0);
+                       if (fip->field_passcount) {
+                               char* cp;
+                               TIFFGetField(tif, fip->field_tag, &wc, &cp);
+                               dir->tdir_count = wc;
+                               if (!TIFFWriteByteArray(tif, dir, cp))
+                                       return 0;
+                       } else {
+                               char cv;
+                               TIFFGetField(tif, fip->field_tag, &cv);
+                               if (!TIFFWriteByteArray(tif, dir, &cv))
+                                       return (0);
+                       }
                 }
                 break;
 
@@ -525,7 +641,7 @@ TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
 static void
 TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
 {
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_count = 1;
        if (v > 0xffffL) {
                dir->tdir_type = (short) TIFF_LONG;
@@ -535,6 +651,18 @@ TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
                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
 
 #ifndef TIFFWriteRational
@@ -564,8 +692,14 @@ TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
        uint16* w = buf;
        int i, status, samples = tif->tif_dir.td_samplesperpixel;
 
-       if (samples > NITEMS(buf))
+       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;
@@ -589,8 +723,14 @@ TIFFWritePerSampleAnys(TIFF* tif,
        int i, status;
        int samples = (int) tif->tif_dir.td_samplesperpixel;
 
-       if (samples > NITEMS(buf))
+       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;
@@ -625,7 +765,7 @@ TIFFWriteShortTable(TIFF* tif,
 {
        uint32 i, off;
 
-       dir->tdir_tag = tag;
+       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);
@@ -660,7 +800,7 @@ static int
 TIFFWriteShortArray(TIFF* tif,
     TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16* v)
 {
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_type = (short) type;
        dir->tdir_count = n;
        if (n <= 2) {
@@ -686,7 +826,7 @@ static int
 TIFFWriteLongArray(TIFF* tif,
     TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint32* v)
 {
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_type = (short) type;
        dir->tdir_count = n;
        if (n == 1) {
@@ -708,10 +848,15 @@ TIFFWriteRationalArray(TIFF* tif,
        uint32* t;
        int status;
 
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_type = (short) type;
        dir->tdir_count = n;
        t = (uint32*) _TIFFmalloc(2*n * sizeof (uint32));
+       if (t == NULL) {
+               TIFFError(tif->tif_name,
+                   "No space to write RATIONAL array");
+               return (0);
+       }
        for (i = 0; i < n; i++) {
                float fv = v[i];
                int sign = 1;
@@ -731,7 +876,7 @@ TIFFWriteRationalArray(TIFF* tif,
                        while (fv < 1L<<(31-3) && den < 1L<<(31-3))
                                fv *= 1<<3, den *= 1L<<3;
                }
-               t[2*i+0] = sign * (fv + 0.5);
+               t[2*i+0] = (uint32) (sign * (fv + 0.5));
                t[2*i+1] = den;
        }
        status = TIFFWriteData(tif, dir, (char *)t);
@@ -743,7 +888,7 @@ static int
 TIFFWriteFloatArray(TIFF* tif,
     TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v)
 {
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_type = (short) type;
        dir->tdir_count = n;
        TIFFCvtNativeToIEEEFloat(tif, n, v);
@@ -758,7 +903,7 @@ static int
 TIFFWriteDoubleArray(TIFF* tif,
     TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
 {
-       dir->tdir_tag = tag;
+       dir->tdir_tag = (uint16) tag;
        dir->tdir_type = (short) type;
        dir->tdir_count = n;
        TIFFCvtNativeToIEEEDouble(tif, n, v);
@@ -782,14 +927,20 @@ TIFFWriteAnyArray(TIFF* tif,
        char* w = buf;
        int i, status = 0;
 
-       if (n * tiffDataWidth[type] > sizeof buf)
-               w = (char*) _TIFFmalloc(n * tiffDataWidth[type]);
+       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);
+               }
+       }
        switch (type) {
        case TIFF_BYTE:
                { uint8* bp = (uint8*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (uint8) v[i];
-                 dir->tdir_tag = tag;
+                 dir->tdir_tag = (uint16) tag;
                  dir->tdir_type = (short) type;
                  dir->tdir_count = n;
                  if (!TIFFWriteByteArray(tif, dir, (char*) bp))
@@ -798,9 +949,9 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_SBYTE:
                { int8* bp = (int8*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (int8) v[i];
-                 dir->tdir_tag = tag;
+                 dir->tdir_tag = (uint16) tag;
                  dir->tdir_type = (short) type;
                  dir->tdir_count = n;
                  if (!TIFFWriteByteArray(tif, dir, (char*) bp))
@@ -809,7 +960,7 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_SHORT:
                { uint16* bp = (uint16*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (uint16) v[i];
                  if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
                                goto out;
@@ -817,7 +968,7 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_SSHORT:
                { int16* bp = (int16*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (int16) v[i];
                  if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
                        goto out;
@@ -825,7 +976,7 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_LONG:
                { uint32* bp = (uint32*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (uint32) v[i];
                  if (!TIFFWriteLongArray(tif, type, tag, dir, n, bp))
                        goto out;
@@ -833,7 +984,7 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_SLONG:
                { int32* bp = (int32*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (int32) v[i];
                  if (!TIFFWriteLongArray(tif, type, tag, dir, n, (uint32*) bp))
                        goto out;
@@ -841,7 +992,7 @@ TIFFWriteAnyArray(TIFF* tif,
                break;
        case TIFF_FLOAT:
                { float* bp = (float*) w;
-                 for (i = 0; i < n; i++)
+                 for (i = 0; i < (int) n; i++)
                        bp[i] = (float) v[i];
                  if (!TIFFWriteFloatArray(tif, type, tag, dir, n, bp))
                        goto out;
@@ -931,7 +1082,7 @@ TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
                }
        }
        dir->tdir_offset = tif->tif_dataoff;
-       cc = dir->tdir_count * tiffDataWidth[dir->tdir_type];
+       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;
@@ -942,6 +1093,87 @@ TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
        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;
+
+#if defined(__hpux) && defined(__LP64__)
+#define HDROFF(f) ((toff_t)(unsigned long) &(((TIFFHeader*) 0)->f))
+#else
+#define        HDROFF(f)       ((toff_t) &(((TIFFHeader*) 0)->f))
+#endif
+        TIFFSeekFile(tif, HDROFF(tiff_diroff), 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.
@@ -950,11 +1182,11 @@ static int
 TIFFLinkDirectory(TIFF* tif)
 {
        static const char module[] = "TIFFLinkDirectory";
-       uint32 nextdir;
-       uint32 diroff;
+       toff_t nextdir;
+       toff_t diroff, off;
 
        tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
-       diroff = (uint32) tif->tif_diroff;
+       diroff = tif->tif_diroff;
        if (tif->tif_flags & TIFF_SWAB)
                TIFFSwabLong(&diroff);
 #if SUBIFD_SUPPORT
@@ -982,7 +1214,7 @@ TIFFLinkDirectory(TIFF* tif)
                /*
                 * First directory, overwrite offset in header.
                 */
-               tif->tif_header.tiff_diroff = (uint32) tif->tif_diroff;
+               tif->tif_header.tiff_diroff = tif->tif_diroff;
 #define        HDROFF(f)       ((toff_t) &(((TIFFHeader*) 0)->f))
                (void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
                if (!WriteOK(tif, &diroff, sizeof (diroff))) {
@@ -1014,7 +1246,8 @@ TIFFLinkDirectory(TIFF* tif)
                if (tif->tif_flags & TIFF_SWAB)
                        TIFFSwabLong(&nextdir);
        } while (nextdir != 0);
-       (void) TIFFSeekFile(tif, -(toff_t) sizeof (nextdir), SEEK_CUR);
+        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);