libtiff: Merge branch 'fix_#40_ReadSignedTags' into 'master'

From f536b00b649779200ff42a240199a1887dec377b Mon Sep 17 00:00:00 2001
From: Su Laus <[EMAIL REDACTED]>
Date: Sun, 8 May 2022 19:55:53 +0000
Subject: [PATCH] Reading of signed tags added (fixes #40)

---
 libtiff/tif_dirread.c   | 645 ++++++++++++++++++++++++++++++++++++++--
 test/CMakeLists.txt     |   5 +
 test/Makefile.am        |   4 +-
 test/test_signed_tags.c | 349 ++++++++++++++++++++++
 4 files changed, 985 insertions(+), 18 deletions(-)
 create mode 100644 test/test_signed_tags.c

diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index 32972d93..32653f04 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -62,9 +62,13 @@ enum TIFFReadDirEntryErr {
 };
 
 static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyte(TIFF * tif, TIFFDirEntry * direntry, int8_t * value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshort(TIFF * tif, TIFFDirEntry * direntry, int16_t * value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong(TIFF * tif, TIFFDirEntry * direntry, int32_t * value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8(TIFF * tif, TIFFDirEntry * direntry, int64_t * value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
 static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value);
@@ -286,6 +290,98 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* di
 	}
 }
 
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyte(TIFF *tif, TIFFDirEntry *direntry, int8_t *value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count != 1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_UNDEFINED:	/* Support to read TIFF_UNDEFINED with field_readcount==1 */
+			{
+				uint8_t m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeSbyteByte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(int8_t)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+		{
+			TIFFReadDirEntryCheckedSbyte(tif, direntry, value);
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SHORT:
+		{
+			uint16_t m;
+			TIFFReadDirEntryCheckedShort(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSbyteShort(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SSHORT:
+		{
+			int16_t m;
+			TIFFReadDirEntryCheckedSshort(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSbyteSshort(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG:
+		{
+			uint32_t m;
+			TIFFReadDirEntryCheckedLong(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSbyteLong(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG:
+		{
+			int32_t m;
+			TIFFReadDirEntryCheckedSlong(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSbyteSlong(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG8:
+		{
+			uint64_t m;
+			err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSbyteLong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG8:
+		{
+			int64_t m;
+			err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSbyteSlong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int8_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}  /*-- TIFFReadDirEntrySbyte() --*/
+
 static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value)
 {
 	enum TIFFReadDirEntryErr err;
@@ -370,7 +466,91 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* d
 		default:
 			return(TIFFReadDirEntryErrType);
 	}
-}
+}  /*-- TIFFReadDirEntryShort() --*/
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshort(TIFF *tif, TIFFDirEntry *direntry, int16_t *value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count != 1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		{
+			uint8_t m;
+			TIFFReadDirEntryCheckedByte(tif, direntry, &m);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SBYTE:
+		{
+			int8_t m;
+			TIFFReadDirEntryCheckedSbyte(tif, direntry, &m);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SHORT:
+		{
+			uint16_t m;
+			TIFFReadDirEntryCheckedShort(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSshortShort(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (uint16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SSHORT:
+			TIFFReadDirEntryCheckedSshort(tif, direntry, value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_LONG:
+		{
+			uint32_t m;
+			TIFFReadDirEntryCheckedLong(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSshortLong(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG:
+		{
+			int32_t m;
+			TIFFReadDirEntryCheckedSlong(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSshortSlong(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG8:
+		{
+			uint64_t m;
+			err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSshortLong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG8:
+		{
+			int64_t m;
+			err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSshortSlong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int16_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}  /*-- TIFFReadDirEntrySshort() --*/
+
 
 static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value)
 {
@@ -453,7 +633,84 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* di
 		default:
 			return(TIFFReadDirEntryErrType);
 	}
-}
+}  /*-- TIFFReadDirEntryLong() --*/
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong(TIFF *tif, TIFFDirEntry *direntry, int32_t *value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count != 1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		{
+			uint8_t m;
+			TIFFReadDirEntryCheckedByte(tif, direntry, &m);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SBYTE:
+		{
+			int8_t m;
+			TIFFReadDirEntryCheckedSbyte(tif, direntry, &m);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SHORT:
+		{
+			uint16_t m;
+			TIFFReadDirEntryCheckedShort(tif, direntry, &m);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SSHORT:
+		{
+			int16_t m;
+			TIFFReadDirEntryCheckedSshort(tif, direntry, &m);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG:
+		{
+			uint32_t m;
+			TIFFReadDirEntryCheckedLong(tif, direntry, &m);
+			err = TIFFReadDirEntryCheckRangeSlongLong(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG:
+			TIFFReadDirEntryCheckedSlong(tif, direntry, value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_LONG8:
+		{
+			uint64_t m;
+			err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSlongLong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG8:
+		{
+			int64_t m;
+			err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSlongSlong8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int32_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}  /*-- TIFFReadDirEntrySlong() --*/
 
 static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value)
 {
@@ -531,7 +788,77 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* d
 		default:
 			return(TIFFReadDirEntryErrType);
 	}
-}
+}  /*-- TIFFReadDirEntryLong8() --*/
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8(TIFF *tif, TIFFDirEntry *direntry, int64_t *value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count != 1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		{
+			uint8_t m;
+			TIFFReadDirEntryCheckedByte(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SBYTE:
+		{
+			int8_t m;
+			TIFFReadDirEntryCheckedSbyte(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SHORT:
+		{
+			uint16_t m;
+			TIFFReadDirEntryCheckedShort(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SSHORT:
+		{
+			int16_t m;
+			TIFFReadDirEntryCheckedSshort(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG:
+		{
+			uint32_t m;
+			TIFFReadDirEntryCheckedLong(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG:
+		{
+			int32_t m;
+			TIFFReadDirEntryCheckedSlong(tif, direntry, &m);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_LONG8:
+		{
+			uint64_t m;
+			err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			err = TIFFReadDirEntryCheckRangeSlong8Long8(m);
+			if (err != TIFFReadDirEntryErrOk)
+				return(err);
+			*value = (int64_t)m;
+			return(TIFFReadDirEntryErrOk);
+		}
+		case TIFF_SLONG8:
+			err = TIFFReadDirEntryCheckedSlong8(tif, direntry, value);
+			return(err);
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}  /*-- TIFFReadDirEntrySlong8() --*/
+
 
 static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
 {
@@ -5135,6 +5462,19 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_SINT8:
+		{
+			int8_t data = 0;
+			assert(fip->field_readcount == 1);
+			assert(fip->field_passcount == 0);
+			err = TIFFReadDirEntrySbyte(tif, dp, &data);
+			if (err == TIFFReadDirEntryErrOk)
+			{
+				if (!TIFFSetField(tif, dp->tdir_tag, data))
+					return(0);
+			}
+		}
+		break;
 		case TIFF_SETGET_UINT16:
 			{
 				uint16_t data;
@@ -5148,6 +5488,19 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_SINT16:
+			{
+				int16_t data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntrySshort(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
 		case TIFF_SETGET_UINT32:
 			{
 				uint32_t data;
@@ -5161,6 +5514,19 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_SINT32:
+			{
+				int32_t data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntrySlong(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
 		case TIFF_SETGET_UINT64:
 			{
 				uint64_t data;
@@ -5174,6 +5540,19 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_SINT64:
+			{
+				int64_t data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntrySlong8(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
 		case TIFF_SETGET_FLOAT:
 			{
 				float data;
@@ -5228,7 +5607,7 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				if (err==TIFFReadDirEntryErrOk)
 				{
 					int m;
-                                        assert(data); /* avoid CLang static Analyzer false positive */
+					assert(data); /* avoid CLang static Analyzer false positive */
 					m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]);
 					_TIFFfree(data);
 					if (!m)
@@ -5243,9 +5622,9 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				assert(fip->field_passcount==0);
 				if (dp->tdir_count!=(uint64_t)fip->field_readcount) {
 					TIFFWarningExt(tif->tif_clientdata,module,
-						       "incorrect count for field \"%s\", expected %d, got %"PRIu64,
-						       fip->field_name,(int) fip->field_readcount, dp->tdir_count);
-					return 0;
+							"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+							fip->field_name,(int) fip->field_readcount, dp->tdir_count);
+					return(0); 
 				}
 				else
 				{
@@ -5262,13 +5641,43 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C0_SINT8:
+			{
+				int8_t * data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				}
+				else
+				{
+					err=TIFFReadDirEntrySbyteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C0_UINT16:
 			{
 				uint16_t* data;
 				assert(fip->field_readcount>=1);
 				assert(fip->field_passcount==0);
-				if (dp->tdir_count!=(uint64_t)fip->field_readcount)
-                                    /* corrupt file */;
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				}
 				else
 				{
 					err=TIFFReadDirEntryShortArray(tif,dp,&data);
@@ -5284,13 +5693,43 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C0_SINT16:
+			{
+				int16_t* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				} 
+				else
+				{
+					err=TIFFReadDirEntrySshortArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C0_UINT32:
 			{
 				uint32_t* data;
 				assert(fip->field_readcount>=1);
 				assert(fip->field_passcount==0);
-				if (dp->tdir_count!=(uint64_t)fip->field_readcount)
-                                    /* corrupt file */;
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				} 
 				else
 				{
 					err=TIFFReadDirEntryLongArray(tif,dp,&data);
@@ -5306,13 +5745,93 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C0_SINT32:
+			{
+				int32_t* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				} 
+				else
+				{
+					err=TIFFReadDirEntrySlongArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT64:
+		{
+			uint64_t *data;
+			assert(fip->field_readcount >= 1);
+			assert(fip->field_passcount == 0);
+			if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+				TIFFWarningExt(tif->tif_clientdata, module,
+					"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+					fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+				return(0);
+			} else
+			{
+				err = TIFFReadDirEntryLong8Array(tif, dp, &data);
+				if (err == TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m = TIFFSetField(tif, dp->tdir_tag, data);
+					if (data != 0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+		}
+		break;
+		case TIFF_SETGET_C0_SINT64:
+		{
+			int64_t *data;
+			assert(fip->field_readcount >= 1);
+			assert(fip->field_passcount == 0);
+			if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+				TIFFWarningExt(tif->tif_clientdata, module,
+					"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+					fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+				return(0);
+			} else
+			{
+				err = TIFFReadDirEntrySlong8Array(tif, dp, &data);
+				if (err == TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m = TIFFSetField(tif, dp->tdir_tag, data);
+					if (data != 0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+		}
+		break;
 		case TIFF_SETGET_C0_FLOAT:
 			{
 				float* data;
 				assert(fip->field_readcount>=1);
 				assert(fip->field_passcount==0);
-				if (dp->tdir_count!=(uint64_t)fip->field_readcount)
-					/* corrupt file */;
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				} 
 				else
 				{
 					err=TIFFReadDirEntryFloatArray(tif,dp,&data);
@@ -5334,8 +5853,12 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				double* data;
 				assert(fip->field_readcount>=1);
 				assert(fip->field_passcount==0);
-				if (dp->tdir_count!=(uint64_t)fip->field_readcount)
-					/* corrupt file */;
+				if (dp->tdir_count != (uint64_t)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata, module,
+						"incorrect count for field \"%s\", expected %d, got %"PRIu64,
+						fip->field_name, (int)fip->field_readcount, dp->tdir_count);
+					return(0);
+				} 
 				else
 				{
 					err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
@@ -5400,6 +5923,28 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C16_SINT8:
+			{
+				int8_t* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntrySbyteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16_t)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C16_UINT16:
 			{
 				uint16_t* data;
@@ -5422,6 +5967,28 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C16_SINT16:
+			{
+				int16_t* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntrySshortArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16_t)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C16_UINT32:
 			{
 				uint32_t* data;
@@ -5444,6 +6011,28 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C16_SINT32:
+			{
+				int32_t* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntrySlongArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16_t)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C16_UINT64:
 			{
 				uint64_t* data;
@@ -5466,6 +6055,28 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 				}
 			}
 			break;
+		case TIFF_SETGET_C16_SINT64:
+			{
+				int64_t* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntrySlong8Array(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16_t)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
 		case TIFF_SETGET_C16_FLOAT:
 			{
 				float* data;
@@ -5543,8 +6154,8 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
 					int m;
 					if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )
 					{
-					    TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
-                                            data[dp->tdir_count-1] = '\0';
+						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);
+											data[dp->tdir_count-1] = '\0';
 					}
 					m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data);
 					if (data!=0)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 093d2edc..47e21d40 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -100,6 +100,11 @@ set(noinst_HEADERS tifftest.h)
 
 set(simple_tests)
 
+add_executable(test_signed_tags ../placeholder.h)
+target_sources(test_signed_tags PRIVATE test_signed_tags.c)
+target_link_libraries(test_signed_tags PRIVATE tiff port)
+list(APPEND simple_tests test_signed_tags)
+
 add_executable(ascii_tag ../placeholder.h)
 target_sources(ascii_tag PRIVATE ascii_tag.c)
 target_link_libraries(ascii_tag PRIVATE tiff port)
diff --git a/test/Makefile.am b/test/Makefile.am
index 6c1bae62..b5823198 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -69,7 +69,7 @@ endif
 check_PROGRAMS = \
 	ascii_tag long_tag short_tag strip_rw rewrite custom_dir custom_dir_EXIF_231 \
 	rational_precision2double defer_strile_loading defer_strile_writing test_directory \
-	testtypes $(JPEG_DEPENDENT_CHECK_PROG)
+	testtypes test_signed_tags $(JPEG_DEPENDENT_CHECK_PROG)
 
 # Test scripts to execute
 TESTSCRIPTS = \
@@ -206,6 +206,8 @@ IMAGES_EXTRA_DIST = \
 
 noinst_HEADERS = tifftest.h
 
+test_signed_tags_SOURCES = test_signed_tags.c
+test_signed_tags_LDADD = $(LIBTIFF)
 ascii_tag_SOURCES = ascii_tag.c
 ascii_tag_LDADD = $(LIBTIFF)
 long_tag_SOURCES = long_tag.c check_tag.c
diff --git a/test/test_signed_tags.c b/test/test_signed_tags.c
new file mode 100644
index 00000000..582ba3aa
--- /dev/null
+++ b/test/test_signed_tags.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2022, Su Laus  @Su_Laus
+ *
+ * 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.
+ */
+
+
+#include <stdio.h>
+
+#include "tif_config.h"		/* necessary for linux compiler to get HAVE_UNISTD_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>	/* for unlink() on linux */
+#endif
+
+#include <tiffio.h>
+
+#define FAULT_RETURN  1
+#define OK_RETURN     0
+#define GOTOFAILURE	goto failure;
+
+#define	N(a)	(sizeof (a) / sizeof (a[0]))
+
+
+enum {
+	SINT8 = 65100,
+	SINT16,
+	SINT32,
+	SINT64,
+	C0_SINT8,
+	C0_SINT16,
+	C0_SINT32,
+	C0_SINT64,
+	C16_SINT8,
+	C16_SINT16,
+	C16_SINT32,
+	C16_SINT64,
+	C32_SINT8,
+	C32_SINT16,
+	C32_SINT32,
+	C32_SINT64,
+};
+
+static const TIFFFieldInfo tiff_field_info[] = {
+	{ SINT8, 1, 1, TIFF_SBYTE,  FIELD_CUSTOM, 0, 0, "SINT8" },
+	{ SINT16, 1, 1, TIFF_SSHORT, FIELD_CUSTOM, 0, 0, "SINT16" },
+	{ SINT32, 1, 1, TIFF_SLONG,  FIELD_CUSTOM, 0, 0, "SINT32" },
+	{ SINT64, 1, 1, TIFF_SLONG8, FIELD_CUSTOM, 0, 0, "SINT64" },
+	{ C0_SINT8, 6, 6, TIFF_SBYTE,  FIELD_CUSTOM, 0, 0, "C0_SINT8" },
+	{ C0_SINT16, 6, 6, TIFF_SSHORT, FIELD_CUSTOM, 0, 0, "C0_SINT16" },
+	{ C0_SINT32, 6, 6, TIFF_SLONG,  FIELD_CUSTOM, 0, 0, "C0_SINT32" },
+	{ C0_SINT64, 6, 6, TIFF_SLONG8, FIELD_CUSTOM, 0, 0, "C0_SINT64" },
+	{ C16_SINT8, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SBYTE,  FIELD_CUSTOM, 0, 1, "C16_SINT8" },
+	{ C16_SINT16, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SSHORT, FIELD_CUSTOM, 0, 1, "C16_SINT16" },
+	{ C16_SINT32, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SLONG,  FIELD_CUSTOM, 0, 1, "C16_SINT32" },
+	{ C16_SINT64, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SLONG8, FIELD_CUSTOM, 0, 1, "C16_SINT64" },
+	{ C32_SINT8, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_SBYTE,  FIELD_CUSTOM, 0, 1, "C32_SINT8" },
+	{ C32_SINT16, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_SSHORT, FIELD_CUSTOM, 0, 1, "C32_SINT16" },
+	{ C32_SINT32, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_SLONG,  FIELD_CUSTOM, 0, 1, "C32_SINT32" },
+	{ C32_SINT64, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_SLONG8, FIELD_CUSTOM, 0, 1, "C32_SINT64" },
+};
+
+static TIFFExtendProc parent = NULL;
+
+static void extender(TIFF *tif)
+{
+	TIFFMergeFieldInfo(tif, tiff_field_info, sizeof(tiff_field_info) / sizeof(tiff_field_info[0]));
+	if (parent) {
+		(*parent)(tif);
+	}
+}
+
+/*-- Global test fields --*/
+int8_t s8[] = { -8, -9, -10, -11, INT8_MAX, INT8_MIN };
+int16_t s16[] = { -16, -17, -18, -19, INT16_MAX, INT16_MIN };
+int32_t s32[] = { -32, -33, -34, -35, INT32_MAX, INT32_MIN };
+int64_t s64[] = { -64, -65, -66, -67, INT64_MAX, INT64_MIN };
+
+const uint32_t idxSingle = 0;
+
+
+static int writeTestTiff(const char *szFileName, int isBigTiff)
+{
+	int ret;
+	TIFF *tif;
+	int retcode = FAULT_RETURN;
+
+	if (isBigTiff) {
+		fprintf(stdout, "\n-- Writing signed values to BigTIFF...\n");
+		ret = unlink(szFileName);
+		tif = TIFFOpen(szFileName, "w8");
+	} else {
+		fprintf(stdout, "\n-- Writing signed values to ClassicTIFF...\n");
+		unlink(szFileName);
+		tif = TIFFOpen(szFileName, "w");
+	}
+	if (!tif) {
+		fprintf(stdout, "Can't create test TIFF file %s.\n", szFileName);
+		return (FAULT_RETURN);
+	}
+
+	ret = TIFFSetField(tif, SINT8, s8[idxSingle]);
+	if (ret != 1) { fprintf(stdout, "Error writing SINT8: ret=%d\n", ret); GOTOFAILURE; }
+	ret = TIFFSetField(tif, SINT16, s16[idxSingle]);
+	if (ret != 1) { fprintf(stdout, "Error writing SINT16: ret=%d\n", ret); GOTOFAILURE; }
+	ret = TIFFSetField(tif, SINT32, s32[idxSingle]);
+	if (ret != 1) { fprintf(stdout, "Error writing SINT32: ret=%d\n", ret); GOTOFAILURE; }
+
+	TIFFSetField(tif, C0_SINT8, &s8);
+	TIFFSetField(tif, C0_SINT16, &s16);
+	TIFFSetField(tif, C0_SINT32, &s32);
+
+	TIFFSetField(tif, C16_SINT8, 6, &s8);
+	TIFFSetField(tif, C16_SINT16, 6, &s16);
+	TIFFSetField(tif, C16_SINT32, 6, &s32);
+
+	TIFFSetField(tif, C16_SINT8, 6, &s8);
+	TIFFSetField(tif, C16_SINT16, 6, &s16);
+	TIFFSetField(tif, C16_SINT32, 6, &s32);
+
+	TIFFSetField(tif, C32_SINT8, 6, &s8);
+	TIFFSetField(tif, C32_SINT16, 6, &s16);
+	TIFFSetField(tif, C32_SINT32, 6, &s32);
+
+	if (isBigTiff) {
+		ret = TIFFSetField(tif, SINT64, s64[0]);
+		if (ret != 1) { fprintf(stdout, "Error writing SINT64: ret=%d\n", ret); GOTOFAILURE; }
+		ret = TIFFSetField(tif, C0_SINT64, &s64);
+		if (ret != 1) { fprintf(stdout, "Error writing C0_SINT64: ret=%d\n", ret); GOTOFAILURE; }
+		ret = TIFFSetField(tif, C16_SINT64, N(s64), &s64);
+		if (ret != 1) { fprintf(stdout, "Error writing C16_SINT64: ret=%d\n", ret); GOTOFAILURE;}
+		ret = TIFFSetField(tif, C32_SINT64, N(s64), &s64);
+		if (ret != 1) { fprintf(stdout, "Error writing C32_SINT64: ret=%d\n", ret); GOTOFAILURE;}
+	}
+
+	TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 1);
+	TIFFSetField(tif, TIFFTAG_IMAGELENGTH, 1);
+	TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+	TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+	TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+	TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+	TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
+	ret = (int)TIFFWriteEncodedStrip(tif, 0, "\0", 1);
+	if (ret != 1) { fprintf(stdout, "Error TIFFWriteEncodedStrip: ret=%d\n", ret); GOTOFAILURE; }
+
+	retcode = OK_RETURN;
+failure:
+	TIFFClose(tif);
+	return(retcode);
+}
+
+static int readTestTiff(const char* szFileName, in

(Patch may be truncated, please check the link at the top of this post.)