libtiff: Setting the TIFFFieldInfo field `set_field_type` should consider `field_writecount` not `field_readcount`

From cee5e991e5abafca2d14a27a1e316a2622b634a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20St=C3=BCber?= <[EMAIL REDACTED]>
Date: Tue, 30 Jan 2024 20:59:04 +0000
Subject: [PATCH] Setting the TIFFFieldInfo field `set_field_type` should
 consider `field_writecount` not `field_readcount`

In most of the cases the field_writecount and field_readcount of the TIFFFieldInfo are equal. But they do not have to be the same.

I encountered this issues when using an older release of Pillow. Since they use custom fields for decoding only, they set the readcount value to 0. As the result _TIFFSetGetType can not identify the type correctly and set TIFF_SETGET_UNDEFINED.

Error Message:

TIFFLib: _TIFFWriteDirectorySec(): Rational2Double: .set_field_type is not 4 but 1.


During the execution of TIFFMergeFieldInfo the fields get_field_type and set_field_type set. I guess the set_field_type should dependent on the field_writecount.
---
 libtiff/tif_dirinfo.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/libtiff/tif_dirinfo.c b/libtiff/tif_dirinfo.c
index bff7592a..22e6ad0d 100644
--- a/libtiff/tif_dirinfo.c
+++ b/libtiff/tif_dirinfo.c
@@ -374,7 +374,7 @@ static const TIFFField exifFields[] = {
     {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL},
     {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL},
     {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL},
-    /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! 
+    /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance!
      *    However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values,
      *    which are not treated within LibTiff!! */
     {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL},
@@ -1197,12 +1197,24 @@ int TIFFMergeFieldInfo(TIFF *tif, const TIFFFieldInfo info[], uint32_t n)
     for (i = 0; i < n; i++)
     {
         tp->field_tag = info[i].field_tag;
+        if (info[i].field_readcount < TIFF_VARIABLE2 ||
+            info[i].field_readcount == 0 ||
+            info[i].field_writecount < TIFF_VARIABLE2 ||
+            info[i].field_writecount == 0)
+        {
+            /* The fields (field_readcount) and (field_writecount) may use the
+             * values TIFF_VARIABLE (-1), TIFF_SPP (-2), TIFF_VARIABLE2 (-3). */
+            TIFFErrorExtR(tif, module,
+                          "The value of field_readcount and field_writecount "
+                          "must be greater than or equal to -3 and not zero.");
+            return -1;
+        }
         tp->field_readcount = info[i].field_readcount;
         tp->field_writecount = info[i].field_writecount;
         tp->field_type = info[i].field_type;
         tp->field_anonymous = 0;
         tp->set_field_type =
-            _TIFFSetGetType(info[i].field_type, info[i].field_readcount,
+            _TIFFSetGetType(info[i].field_type, info[i].field_writecount,
                             info[i].field_passcount);
         tp->get_field_type =
             _TIFFSetGetType(info[i].field_type, info[i].field_readcount,