From e8874d75f5d281641e65a446ddc659ee08ae838a Mon Sep 17 00:00:00 2001
From: Su_Laus <[EMAIL REDACTED]>
Date: Mon, 15 May 2023 21:03:12 +0200
Subject: [PATCH] Fix #559 DNG 1.6 passcount assertion
Amend DNG tags definition introduced with MR 482:
- DNG 1.6 tags specified as UTF-8 strings are defined as variable TIFF_BYTE with passcount=TRUE.
- For all tags with TIFF_SETGET_C32_UINT8 the readcount and writecount were corrected to -3 (TIFF_VARIABLE2).
Testprogram to write and read all tags defined within LibTIFF is introduced.
It also checks for valid passcount flag setting for the defined tags but some special tags are excluded from that check.
Closes #559.
---
libtiff/tif_dirinfo.c | 44 +-
test/CMakeLists.txt | 5 +
test/test_write_read_tags.c | 1852 +++++++++++++++++++++++++++++++++++
3 files changed, 1879 insertions(+), 22 deletions(-)
create mode 100644 test/test_write_read_tags.c
diff --git a/libtiff/tif_dirinfo.c b/libtiff/tif_dirinfo.c
index 54785b06..9ab0b2f4 100644
--- a/libtiff/tif_dirinfo.c
+++ b/libtiff/tif_dirinfo.c
@@ -166,7 +166,7 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DNGVersion", NULL},
{TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DNGBackwardVersion", NULL},
{TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL},
- {TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LocalizedCameraModel", NULL},
+ {TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL},
{TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPlaneColor", NULL},
{TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CFALayout", NULL},
{TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LinearizationTable", NULL},
@@ -203,7 +203,7 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant1", NULL},
{TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant2", NULL},
{TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawDataUniqueID", NULL},
- {TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalRawFileName", NULL},
+ {TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL},
{TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileData", NULL},
{TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ActiveArea", NULL},
{TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MaskedAreas", NULL},
@@ -214,23 +214,23 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL},
/* begin DNG 1.2.0.0 tags */
{TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL},
- {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraCalibrationSignature", NULL},
- {TIFFTAG_PROFILECALIBRATIONSIGNATURE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileCalibrationSignature", NULL},
+ {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL},
+ {TIFFTAG_PROFILECALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCalibrationSignature", NULL},
{TIFFTAG_EXTRACAMERAPROFILES, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ExtraCameraProfiles", NULL},
- {TIFFTAG_ASSHOTPROFILENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AsShotProfileName", NULL},
+ {TIFFTAG_ASSHOTPROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotProfileName", NULL},
{TIFFTAG_NOISEREDUCTIONAPPLIED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NoiseReductionApplied", NULL},
- {TIFFTAG_PROFILENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileName", NULL},
+ {TIFFTAG_PROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileName", NULL},
{TIFFTAG_PROFILEHUESATMAPDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapDims", NULL},
{TIFFTAG_PROFILEHUESATMAPDATA1, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData1", NULL},
{TIFFTAG_PROFILEHUESATMAPDATA2, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData2", NULL},
{TIFFTAG_PROFILETONECURVE, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileToneCurve", NULL},
{TIFFTAG_PROFILEEMBEDPOLICY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileEmbedPolicy", NULL},
- {TIFFTAG_PROFILECOPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileCopyright", NULL},
+ {TIFFTAG_PROFILECOPYRIGHT, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCopyright", NULL},
{TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix1", NULL},
{TIFFTAG_FORWARDMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix2", NULL},
- {TIFFTAG_PREVIEWAPPLICATIONNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewApplicationName", NULL},
- {TIFFTAG_PREVIEWAPPLICATIONVERSION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewApplicationVersion", NULL},
- {TIFFTAG_PREVIEWSETTINGSNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewSettingsName", NULL},
+ {TIFFTAG_PREVIEWAPPLICATIONNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationName", NULL},
+ {TIFFTAG_PREVIEWAPPLICATIONVERSION, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationVersion", NULL},
+ {TIFFTAG_PREVIEWSETTINGSNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewSettingsName", NULL},
{TIFFTAG_PREVIEWSETTINGSDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewSettingsDigest", NULL},
{TIFFTAG_PREVIEWCOLORSPACE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewColorSpace", NULL},
{TIFFTAG_PREVIEWDATETIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewDateTime", NULL},
@@ -241,9 +241,9 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_PROFILELOOKTABLEDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileLookTableDims", NULL},
{TIFFTAG_PROFILELOOKTABLEDATA, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileLookTableData", NULL},
/* begin DNG 1.3.0.0 tags */
- {TIFFTAG_OPCODELIST1, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList1", NULL},
- {TIFFTAG_OPCODELIST2, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList2", NULL},
- {TIFFTAG_OPCODELIST3, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList3", NULL},
+ {TIFFTAG_OPCODELIST1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList1", NULL},
+ {TIFFTAG_OPCODELIST2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList2", NULL},
+ {TIFFTAG_OPCODELIST3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList3", NULL},
{TIFFTAG_NOISEPROFILE, -1, -1, TIFF_DOUBLE, 0, TIFF_SETGET_C16_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "NoiseProfile", NULL},
/* begin DNG 1.4.0.0 tags */
{TIFFTAG_DEFAULTUSERCROP, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultUserCrop", NULL},
@@ -264,20 +264,20 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_DEPTHMEASURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthMeasureType", NULL},
{TIFFTAG_ENHANCEPARAMS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EnhanceParams", NULL},
/* begin DNG 1.6.0.0 tags */
- {TIFFTAG_PROFILEGAINTABLEMAP, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileGainTableMap", NULL},
+ {TIFFTAG_PROFILEGAINTABLEMAP, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileGainTableMap", NULL},
{TIFFTAG_SEMANTICNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticName", NULL},
{TIFFTAG_SEMANTICINSTANCEID, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticInstanceID", NULL},
{TIFFTAG_MASKSUBAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaskSubArea", NULL},
- {TIFFTAG_RGBTABLES, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "RGBTables", NULL},
+ {TIFFTAG_RGBTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "RGBTables", NULL},
{TIFFTAG_CALIBRATIONILLUMINANT3, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant3", NULL},
{TIFFTAG_COLORMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix3", NULL},
{TIFFTAG_CAMERACALIBRATION3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration3", NULL},
{TIFFTAG_REDUCTIONMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix3", NULL},
{TIFFTAG_PROFILEHUESATMAPDATA3, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData3", NULL},
{TIFFTAG_FORWARDMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix3", NULL},
- {TIFFTAG_ILLUMINANTDATA1, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData1", NULL},
- {TIFFTAG_ILLUMINANTDATA2, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL},
- {TIFFTAG_ILLUMINANTDATA3, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL},
+ {TIFFTAG_ILLUMINANTDATA1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData1", NULL},
+ {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL},
+ {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL},
/* end DNG tags */
/* begin TIFF/EP tags */
{TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL},
@@ -291,13 +291,13 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_EP_TIMEZONEOFFSET, -1, -1, TIFF_SSHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP TimeZoneOffset", NULL},
{TIFFTAG_EP_SELFTIMERMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SelfTimerMode", NULL},
{TIFFTAG_EP_FLASHENERGY, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FlashEnergy", NULL},
- {TIFFTAG_EP_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SpatialFrequencyResponse", NULL},
- {TIFFTAG_EP_NOISE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP Noise", NULL},
+ {TIFFTAG_EP_SPATIALFREQUENCYRESPONSE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SpatialFrequencyResponse", NULL},
+ {TIFFTAG_EP_NOISE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP Noise", NULL},
{TIFFTAG_EP_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneXResolution", NULL},
{TIFFTAG_EP_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneYResolution", NULL},
{TIFFTAG_EP_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneResolutionUnit", NULL},
{TIFFTAG_EP_IMAGENUMBER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageNumber", NULL}, /* or SHORT */
- {TIFFTAG_EP_SECURITYCLASSIFICATION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SecurityClassification", NULL},
+ {TIFFTAG_EP_SECURITYCLASSIFICATION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SecurityClassification", NULL},
{TIFFTAG_EP_IMAGEHISTORY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageHistory", NULL},
{TIFFTAG_EP_EXPOSUREINDEX, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureIndex", NULL},
{TIFFTAG_EP_STANDARDID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP StandardId", NULL},
@@ -308,7 +308,7 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_EP_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ExposureProgram", NULL},
{TIFFTAG_EP_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SpectralSensitivity", NULL},
{TIFFTAG_EP_ISOSPEEDRATINGS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ISOSpeedRatings", NULL},
- {TIFFTAG_EP_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP OptoelectricConversionFactor", NULL},
+ {TIFFTAG_EP_OECF, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP OptoelectricConversionFactor", NULL},
{TIFFTAG_EP_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP DateTimeOriginal", NULL},
{TIFFTAG_EP_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CompressedBitsPerPixel", NULL},
{TIFFTAG_EP_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ShutterSpeedValue", NULL},
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 779c6e7e..878a9748 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -150,6 +150,11 @@ if(NOT BUILD_SHARED_LIBS)
target_sources(rational_precision2double PRIVATE rational_precision2double.c)
target_link_libraries(rational_precision2double PRIVATE tiff tiff_port)
list(APPEND simple_tests rational_precision2double)
+
+ add_executable(test_write_read_tags ../placeholder.h)
+ target_sources(test_write_read_tags PRIVATE test_write_read_tags.c)
+ target_link_libraries(test_write_read_tags PRIVATE tiff)
+ list(APPEND simple_tests test_write_read_tags)
endif()
add_executable(custom_dir_EXIF_231 ../placeholder.h)
diff --git a/test/test_write_read_tags.c b/test/test_write_read_tags.c
new file mode 100644
index 00000000..950005dd
--- /dev/null
+++ b/test/test_write_read_tags.c
@@ -0,0 +1,1852 @@
+/*
+ * Copyright (c) 2023, LibTIFF Contributors
+ *
+ * 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.
+ */
+
+/*
+ *=========== Purpose ========================================================
+ * TIFF Library Testing:
+ * - Write- and read- test of most tags defined within tif_dirinfo.c
+ * - Write- and read- test of custom directories for EXIF and GPS.
+ *
+ * Attention:
+ * This test program uses private functions from static LibTIFF library.
+ * Therefore, it does not work when compiled for shared library.
+ */
+
+#define FOR_AUTO_TESTING
+#ifdef FOR_AUTO_TESTING
+/* Only for automake and CMake infrastructure the test should:
+ a.) delete any written testfiles when test passed (otherwise autotest
+ will fail)
+ b.) goto failure, if any failure is detected, which is not
+ necessary when test is initiated manually for debugging
+*/
+#define GOTOFAILURE goto failure;
+#else
+#define GOTOFAILURE
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4101)
+#endif
+
+#include "tif_config.h" //necessary for linux compiler
+
+#include <errno.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "tiffio.h"
+#include "tiffiop.h"
+
+static const char filename[] = "test_write_read_tags.tif";
+static const char filenameBigTiff[] = "test_write_read_tags_Big.tif";
+
+/* Settings for basic TIFF image to be written */
+#define SPP 3 /* Samples per pixel */
+const uint16_t width = 1;
+const uint16_t length = 1;
+const uint16_t bps = 8;
+const uint16_t photometric = PHOTOMETRIC_RGB;
+const uint16_t rows_per_strip = 1;
+const uint16_t planarconfig = PLANARCONFIG_CONTIG;
+
+/* -- Test data for writing -- */
+#define STRSIZE 1000
+#define N_SIZE 400
+#define VARIABLE_ARRAY_SIZE 6
+
+char auxCharArrayW[N_SIZE];
+short auxShortArrayW[N_SIZE];
+long auxLongArrayW[N_SIZE];
+float auxFloatArrayW[N_SIZE];
+double auxDoubleArrayW[N_SIZE];
+char auxTextArrayW[N_SIZE][STRSIZE];
+
+/*-- Additional variables --*/
+char exifVersion[4] = {
+ '0', '2', '3', '1'}; /* EXIF 2.31 version is 4 characters of a string! */
+char gpsVersion[4] = {2, 2, 0, 1}; /* GPS Version is 4 numbers! */
+
+/* Inkname string is separated but not closed at the very end with a NULL.
+ * Otherwise NumberOfInks would be counted to four by countInkNamesString()
+ * at TIFFSetField() for the inkname string.
+ */
+#define NINKS 3
+char inkNamesW[] = {"Ink1\0Ink2\0Ink3"};
+
+#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
+
+/* -- List of tags, which must not be written with arbitrary values because they
+ * are written explicitely by the test program (like the basic TIFF tags),
+ * are automatically written by LibTIFF (e.g.TIFFTAG_NUMBEROFINKS),
+ * have some special characteristics, or write procedure is not supported
+ * yet.
+ * - For TileOffsets and TileBytecounts the same variable is used as for
+ * StripOffsets and StripBytecounts, respectively.
+ */
+uint32_t listTagsNotToWrite[] = {TIFFTAG_OSUBFILETYPE,
+ TIFFTAG_STRIPOFFSETS,
+ TIFFTAG_COMPRESSION,
+ TIFFTAG_STRIPBYTECOUNTS,
+ TIFFTAG_IMAGEWIDTH,
+ TIFFTAG_IMAGELENGTH,
+ TIFFTAG_BITSPERSAMPLE,
+ TIFFTAG_SAMPLESPERPIXEL,
+ TIFFTAG_ROWSPERSTRIP,
+ TIFFTAG_PLANARCONFIG,
+ TIFFTAG_PHOTOMETRIC,
+ TIFFTAG_FREEOFFSETS,
+ TIFFTAG_FREEBYTECOUNTS,
+ TIFFTAG_GRAYRESPONSEUNIT,
+ TIFFTAG_GRAYRESPONSECURVE,
+ TIFFTAG_TRANSFERFUNCTION,
+ TIFFTAG_COLORMAP,
+ TIFFTAG_COLORRESPONSEUNIT,
+ TIFFTAG_TILEWIDTH,
+ TIFFTAG_TILELENGTH,
+ TIFFTAG_TILEOFFSETS,
+ TIFFTAG_TILEBYTECOUNTS,
+ TIFFTAG_SUBIFD,
+ TIFFTAG_NUMBEROFINKS,
+ TIFFTAG_GPSIFD,
+ TIFFTAG_EXIFIFD,
+ TIFFTAG_DATATYPE,
+ TIFFTAG_MATTEING};
+
+/* Some tag definitions do not follow the rules for
+ * readcount/writecount/set_field_type/passcount-flag.
+ * Most of them are handled by LibTIFF in special cases anyway, so the tag
+ * definition is irrelevant.
+ */
+uint32_t listTagsNotFollowPasscountRules[] = {
+ TIFFTAG_STRIPOFFSETS, TIFFTAG_STRIPBYTECOUNTS,
+ TIFFTAG_MINSAMPLEVALUE, TIFFTAG_MAXSAMPLEVALUE,
+ TIFFTAG_FREEOFFSETS, TIFFTAG_FREEBYTECOUNTS,
+ TIFFTAG_GRAYRESPONSECURVE, TIFFTAG_TRANSFERFUNCTION,
+ TIFFTAG_COLORMAP, TIFFTAG_SAMPLEFORMAT,
+ TIFFTAG_SMINSAMPLEVALUE, TIFFTAG_SMAXSAMPLEVALUE,
+ TIFFTAG_DATATYPE, TIFFTAG_TILEOFFSETS,
+ TIFFTAG_TILEBYTECOUNTS, TIFFTAG_PERSAMPLE};
+
+/* Function definition */
+int check_tag_definitions(void);
+int write_test_tiff(TIFF *tif, const char *filenameRead);
+int write_all_tags(TIFF *tif, const TIFFFieldArray *tFieldArray,
+ uint32_t *listTagsNotToWrite, uint32_t nTagsInList,
+ uint32_t *iCnt);
+int tagIsInList(uint32_t tTag, uint32_t *list, uint32_t nTagsInList);
+int testPasscountFlag(const char *szMsg, const TIFFFieldArray *tFieldArray,
+ uint32_t *listTagsNotFollowPasscountRules,
+ uint32_t nTagsInList);
+int read_all_tags(TIFF *tif, const TIFFFieldArray *tFieldArray,
+ uint32_t *listTagsNotToWrite, uint32_t nTagsNotToWrite,
+ uint32_t *iCnt);
+
+/* ==== main() ========================================================
+ * Main program checks for correct tags definition.
+ * Then, writing/reading is tested for ClassicTIFF and BigTIFF.
+ * Testprograms shall return 0 for success.
+ */
+int main()
+{
+ int ret, ret1, ret2;
+
+ fprintf(stderr, "==== Test automatically if all tags are "
+ "written/read correctly. ====\n");
+ /* --- Test with Classic-TIFF ---*/
+ /* Delete file, if exists and open it freshly. */
+ ret = unlink(filename);
+ if (ret != 0 && errno != ENOENT)
+ {
+ fprintf(stderr, "Can't delete test TIFF file %s.\n", filename);
+ }
+ TIFF *tif = TIFFOpen(filename, "w+");
+ if (!tif)
+ {
+ fprintf(stderr, "Can't create test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ /* Firstly, check for correct definition of tags. */
+ fprintf(stderr, "-------- Check tag definition -------------------\n");
+ ret1 = check_tag_definitions();
+
+ if (ret1 > 0)
+ return (ret1);
+
+ /* Write a simple image with all tags and check if correctly written
+ * by reading all tags. */
+ fprintf(stderr, "-------- Test with ClassicTIFF started ----------\n");
+ ret1 = write_test_tiff(tif, filename);
+
+ if (ret1 > 0)
+ return (ret1);
+
+ /*--- Test with BIG-TIFF ---*/
+ ret = unlink(filenameBigTiff);
+ if (ret != 0 && errno != ENOENT)
+ {
+ fprintf(stderr, "Can't delete test TIFF file %s.\n", filenameBigTiff);
+ }
+ tif = TIFFOpen(filenameBigTiff, "w8");
+ if (!tif)
+ {
+ fprintf(stderr, "Can't create test TIFF file %s.\n", filenameBigTiff);
+ return 1;
+ }
+ fprintf(stderr, "\n\n-------- Test with BigTIFF started ----------\n");
+ ret2 = write_test_tiff(tif, filenameBigTiff);
+
+ if (ret2 > 0)
+ return (ret2 + 10);
+ else
+ return (ret2);
+} /* main() */
+
+/* ==== check_tag_definitions() =======================================
+ * Check for correct definition of tags within tags FieldArray wrt passcount
+ * flag and set_field_type.
+ */
+int check_tag_definitions(void)
+{
+ const TIFFFieldArray *tFieldArray;
+ int ret = 0;
+
+ tFieldArray = _TIFFGetFields();
+ ret = testPasscountFlag("---- TIFF tags:", tFieldArray,
+ listTagsNotFollowPasscountRules,
+ NUM_ELEMENTS(listTagsNotFollowPasscountRules));
+
+ tFieldArray = _TIFFGetGpsFields();
+ ret += testPasscountFlag("---- GPS tags:", tFieldArray, NULL, 0);
+
+ tFieldArray = _TIFFGetExifFields();
+ ret += testPasscountFlag("---- EXIF tags:", tFieldArray, NULL, 0);
+
+ return ret;
+} /*-- check_tag_definitions() --*/
+
+/* ==== write_test_tiff() =============================================
+ * Performs write and read test of all tags defined within LibTiff
+ * to the opened file passed through "tif".
+ * All TIFF, GPS and EXIF tags are written with arbitrary values.
+ * Finally, the file is closed, re-opened and all tags are read
+ * and compared to their written value.
+ */
+
+int write_test_tiff(TIFF *tif, const char *filenameRead)
+{
+ unsigned char buf[SPP] = {0, 127, 255};
+ uint16_t auxUint16 = 0;
+ uint32_t auxUint32 = 0;
+ int i;
+
+ /*-- Fill test data arrays for writing and later comparison when written
+ * tags are checked. */
+ for (i = 0; i < N_SIZE; i++)
+ {
+ sprintf(auxTextArrayW[i],
+ "N%d-String-%d_tttttttttttttttttttttttttttttx", i, i);
+ }
+ for (i = 0; i < N_SIZE; i++)
+ {
+ auxCharArrayW[i] = (char)(i + 1);
+ }
+ for (i = 0; i < N_SIZE; i++)
+ {
+ auxShortArrayW[i] = (short)(i + 1) * 7;
+ }
+ for (i = 0; i < N_SIZE; i++)
+ {
+ auxLongArrayW[i] = (i + 1) * 133;
+ }
+ for (i = 0; i < N_SIZE; i++)
+ {
+ auxFloatArrayW[i] = (float)((i + 1) * 133) / 3.3f;
+ }
+ for (i = 0; i < N_SIZE; i++)
+ {
+ auxDoubleArrayW[i] = (double)((i + 1) * 3689) / 4.5697;
+ }
+
+ /*-- Setup standard tags of a simple tiff file --*/
+ fprintf(stderr, "----Write TIFF tags ...\n");
+ if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width))
+ {
+ fprintf(stderr, "Can't set ImageWidth tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length))
+ {
+ fprintf(stderr, "Can't set ImageLength tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps))
+ {
+ fprintf(stderr, "Can't set BitsPerSample tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SPP))
+ {
+ fprintf(stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip))
+ {
+ fprintf(stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig))
+ {
+ fprintf(stderr, "Can't set PlanarConfiguration tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric))
+ {
+ fprintf(stderr, "Can't set PhotometricInterpretation tag.\n");
+ goto failure;
+ }
+
+ /*============ Write GPS and EXIF Dummy tags =====================*/
+ /*-- Set dummy EXIF/GPS tag in original tif-structure in order to reserve
+ * space for final dir_offset value,
+ * which is properly written at the end.
+ */
+ uint64_t dir_offset = 0; /* Zero, in case no Custom-IFD is written */
+
+ if (!TIFFSetField(tif, TIFFTAG_GPSIFD, dir_offset))
+ {
+ fprintf(stderr, "Can't write TIFFTAG_GPSIFD\n");
+ }
+
+ if (!TIFFSetField(tif, TIFFTAG_EXIFIFD, dir_offset))
+ {
+ fprintf(stderr, "Can't write TIFFTAG_EXIFIFD\n");
+ }
+
+ /*============ Write mostly all other TIFF tags ==================*/
+ /* Get array, where tag fields are defined. */
+ const TIFFFieldArray *tFieldArray = _TIFFGetFields();
+
+ /*-- write_all_tags() writes all tags automatically with the defined
+ * precision according to its set_field_type definition. --*/
+ uint32_t iDataCnt = 0;
+ if (write_all_tags(tif, tFieldArray, listTagsNotToWrite,
+ NUM_ELEMENTS(listTagsNotToWrite), &iDataCnt))
+ {
+ fprintf(stderr, "Error during TIFF tag writing.\n");
+ goto failure;
+ }
+
+#ifndef WRITEPIXELLAST
+ /*-- Write dummy pixel data. --*/
+ if (TIFFWriteScanline(tif, buf, 0, 0) < 0)
+ {
+ fprintf(stderr, "Can't write image data.\n");
+ goto failure;
+ }
+#endif
+
+ /*================== Save TIFF Directory =====================*/
+ /*-- Save current TIFF-directory to file before directory
(Patch may be truncated, please check the link at the top of this post.)