#include "tiffiop.h"
#include <float.h>
#include <limits.h>
#define DATATYPE_VOID 0
#define DATATYPE_INT 1
#define DATATYPE_UINT 2
#define DATATYPE_IEEEFP 3
static void setByteArray(TIFF *tif, void **vpp, const void *vp, size_t nmemb,
size_t elem_size)
{
if (*vpp)
{
_TIFFfreeExt(tif, *vpp);
*vpp = 0;
}
if (vp)
{
tmsize_t bytes = _TIFFMultiplySSize(NULL, nmemb, elem_size, NULL);
if (bytes)
*vpp = (void *)_TIFFmallocExt(tif, bytes);
if (*vpp)
_TIFFmemcpy(*vpp, vp, bytes);
}
}
void _TIFFsetByteArray(void **vpp, const void *vp, uint32_t n)
{
setByteArray(NULL, vpp, vp, n, 1);
}
void _TIFFsetByteArrayExt(TIFF *tif, void **vpp, const void *vp, uint32_t n)
{
setByteArray(tif, vpp, vp, n, 1);
}
static void _TIFFsetNString(TIFF *tif, char **cpp, const char *cp, uint32_t n)
{
setByteArray(tif, (void **)cpp, cp, n, 1);
}
void _TIFFsetShortArray(uint16_t **wpp, const uint16_t *wp, uint32_t n)
{
setByteArray(NULL, (void **)wpp, wp, n, sizeof(uint16_t));
}
void _TIFFsetShortArrayExt(TIFF *tif, uint16_t **wpp, const uint16_t *wp,
uint32_t n)
{
setByteArray(tif, (void **)wpp, wp, n, sizeof(uint16_t));
}
void _TIFFsetLongArray(uint32_t **lpp, const uint32_t *lp, uint32_t n)
{
setByteArray(NULL, (void **)lpp, lp, n, sizeof(uint32_t));
}
void _TIFFsetLongArrayExt(TIFF *tif, uint32_t **lpp, const uint32_t *lp,
uint32_t n)
{
setByteArray(tif, (void **)lpp, lp, n, sizeof(uint32_t));
}
static void _TIFFsetLong8Array(TIFF *tif, uint64_t **lpp, const uint64_t *lp,
uint32_t n)
{
setByteArray(tif, (void **)lpp, lp, n, sizeof(uint64_t));
}
void _TIFFsetFloatArray(float **fpp, const float *fp, uint32_t n)
{
setByteArray(NULL, (void **)fpp, fp, n, sizeof(float));
}
void _TIFFsetFloatArrayExt(TIFF *tif, float **fpp, const float *fp, uint32_t n)
{
setByteArray(tif, (void **)fpp, fp, n, sizeof(float));
}
void _TIFFsetDoubleArray(double **dpp, const double *dp, uint32_t n)
{
setByteArray(NULL, (void **)dpp, dp, n, sizeof(double));
}
void _TIFFsetDoubleArrayExt(TIFF *tif, double **dpp, const double *dp,
uint32_t n)
{
setByteArray(tif, (void **)dpp, dp, n, sizeof(double));
}
static void setDoubleArrayOneValue(TIFF *tif, double **vpp, double value,
size_t nmemb)
{
if (*vpp)
_TIFFfreeExt(tif, *vpp);
*vpp = _TIFFmallocExt(tif, nmemb * sizeof(double));
if (*vpp)
{
while (nmemb--)
((double *)*vpp)[nmemb] = value;
}
}
static int setExtraSamples(TIFF *tif, va_list ap, uint32_t *v)
{
#define EXTRASAMPLE_COREL_UNASSALPHA 999
uint16_t *va;
uint32_t i;
TIFFDirectory *td = &tif->tif_dir;
static const char module[] = "setExtraSamples";
*v = (uint16_t)va_arg(ap, uint16_vap);
if ((uint16_t)*v > td->td_samplesperpixel)
return 0;
va = va_arg(ap, uint16_t *);
if (*v > 0 && va == NULL)
return 0;
for (i = 0; i < *v; i++)
{
if (va[i] > EXTRASAMPLE_UNASSALPHA)
{
if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA)
va[i] = EXTRASAMPLE_UNASSALPHA;
else
return 0;
}
}
if (td->td_transferfunction[0] != NULL &&
(td->td_samplesperpixel - *v > 1) &&
!(td->td_samplesperpixel - td->td_extrasamples > 1))
{
TIFFWarningExtR(tif, module,
"ExtraSamples tag value is changing, "
"but TransferFunction was read with a different value. "
"Canceling it");
TIFFClrFieldBit(tif, FIELD_TRANSFERFUNCTION);
_TIFFfreeExt(tif, td->td_transferfunction[0]);
td->td_transferfunction[0] = NULL;
}
td->td_extrasamples = (uint16_t)*v;
_TIFFsetShortArrayExt(tif, &td->td_sampleinfo, va, td->td_extrasamples);
return 1;
#undef EXTRASAMPLE_COREL_UNASSALPHA
}
static uint16_t countInkNamesString(TIFF *tif, uint32_t slen, const char *s)
{
uint16_t i = 0;
if (slen > 0)
{
const char *ep = s + slen;
const char *cp = s;
do
{
for (; cp < ep && *cp != '\0'; cp++)
{
}
if (cp >= ep)
goto bad;
cp++;
i++;
} while (cp < ep);
return (i);
}
bad:
TIFFErrorExtR(tif, "TIFFSetField",
"%s: Invalid InkNames value; no null at given buffer end "
"location %" PRIu32 ", after %" PRIu16 " ink",
tif->tif_name, slen, i);
return (0);
}
static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap)
{
static const char module[] = "_TIFFVSetField";
TIFFDirectory *td = &tif->tif_dir;
int status = 1;
uint32_t v32, v;
double dblval;
char *s;
const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
uint32_t standard_tag = tag;
if (fip == NULL)
return 0;
if (fip->field_bit == FIELD_CUSTOM)
{
standard_tag = 0;
}
switch (standard_tag)
{
case TIFFTAG_SUBFILETYPE:
td->td_subfiletype = (uint32_t)va_arg(ap, uint32_t);
break;
case TIFFTAG_IMAGEWIDTH:
td->td_imagewidth = (uint32_t)va_arg(ap, uint32_t);
break;
case TIFFTAG_IMAGELENGTH:
td->td_imagelength = (uint32_t)va_arg(ap, uint32_t);
break;
case TIFFTAG_BITSPERSAMPLE:
td->td_bitspersample = (uint16_t)va_arg(ap, uint16_vap);
if (tif->tif_flags & TIFF_SWAB)
{
if (td->td_bitspersample == 8)
tif->tif_postdecode = _TIFFNoPostDecode;
else if (td->td_bitspersample == 16)
tif->tif_postdecode = _TIFFSwab16BitData;
else if (td->td_bitspersample == 24)
tif->tif_postdecode = _TIFFSwab24BitData;
else if (td->td_bitspersample == 32)
tif->tif_postdecode = _TIFFSwab32BitData;
else if (td->td_bitspersample == 64)
tif->tif_postdecode = _TIFFSwab64BitData;
else if (td->td_bitspersample == 128)
tif->tif_postdecode = _TIFFSwab64BitData;
}
break;
case TIFFTAG_COMPRESSION:
v = (uint16_t)va_arg(ap, uint16_vap);
if (TIFFFieldSet(tif, FIELD_COMPRESSION))
{
if ((uint32_t)td->td_compression == v)
break;
(*tif->tif_cleanup)(tif);
tif->tif_flags &= ~TIFF_CODERSETUP;
}
if ((status = TIFFSetCompressionScheme(tif, v)) != 0)
td->td_compression = (uint16_t)v;
else
status = 0;
break;
case TIFFTAG_PHOTOMETRIC:
td->td_photometric = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_THRESHHOLDING:
td->td_threshholding = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_FILLORDER:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB)
goto badvalue;
td->td_fillorder = (uint16_t)v;
break;
case TIFFTAG_ORIENTATION:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v)
goto badvalue;
else
td->td_orientation = (uint16_t)v;
break;
case TIFFTAG_SAMPLESPERPIXEL:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v == 0)
goto badvalue;
if (v != td->td_samplesperpixel)
{
if (td->td_sminsamplevalue != NULL)
{
TIFFWarningExtR(tif, module,
"SamplesPerPixel tag value is changing, "
"but SMinSampleValue tag was read with a "
"different value. Canceling it");
TIFFClrFieldBit(tif, FIELD_SMINSAMPLEVALUE);
_TIFFfreeExt(tif, td->td_sminsamplevalue);
td->td_sminsamplevalue = NULL;
}
if (td->td_smaxsamplevalue != NULL)
{
TIFFWarningExtR(tif, module,
"SamplesPerPixel tag value is changing, "
"but SMaxSampleValue tag was read with a "
"different value. Canceling it");
TIFFClrFieldBit(tif, FIELD_SMAXSAMPLEVALUE);
_TIFFfreeExt(tif, td->td_smaxsamplevalue);
td->td_smaxsamplevalue = NULL;
}
if (td->td_transferfunction[0] != NULL &&
(v - td->td_extrasamples > 1) &&
!(td->td_samplesperpixel - td->td_extrasamples > 1))
{
TIFFWarningExtR(tif, module,
"SamplesPerPixel tag value is changing, "
"but TransferFunction was read with a "
"different value. Canceling it");
TIFFClrFieldBit(tif, FIELD_TRANSFERFUNCTION);
_TIFFfreeExt(tif, td->td_transferfunction[0]);
td->td_transferfunction[0] = NULL;
}
}
td->td_samplesperpixel = (uint16_t)v;
break;
case TIFFTAG_ROWSPERSTRIP:
v32 = (uint32_t)va_arg(ap, uint32_t);
if (v32 == 0)
goto badvalue32;
td->td_rowsperstrip = v32;
if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS))
{
td->td_tilelength = v32;
td->td_tilewidth = td->td_imagewidth;
}
break;
case TIFFTAG_MINSAMPLEVALUE:
td->td_minsamplevalue = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_MAXSAMPLEVALUE:
td->td_maxsamplevalue = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_SMINSAMPLEVALUE:
if (tif->tif_flags & TIFF_PERSAMPLE)
_TIFFsetDoubleArrayExt(tif, &td->td_sminsamplevalue,
va_arg(ap, double *),
td->td_samplesperpixel);
else
setDoubleArrayOneValue(tif, &td->td_sminsamplevalue,
va_arg(ap, double),
td->td_samplesperpixel);
break;
case TIFFTAG_SMAXSAMPLEVALUE:
if (tif->tif_flags & TIFF_PERSAMPLE)
_TIFFsetDoubleArrayExt(tif, &td->td_smaxsamplevalue,
va_arg(ap, double *),
td->td_samplesperpixel);
else
setDoubleArrayOneValue(tif, &td->td_smaxsamplevalue,
va_arg(ap, double),
td->td_samplesperpixel);
break;
case TIFFTAG_XRESOLUTION:
dblval = va_arg(ap, double);
if (dblval != dblval || dblval < 0)
goto badvaluedouble;
td->td_xresolution = _TIFFClampDoubleToFloat(dblval);
break;
case TIFFTAG_YRESOLUTION:
dblval = va_arg(ap, double);
if (dblval != dblval || dblval < 0)
goto badvaluedouble;
td->td_yresolution = _TIFFClampDoubleToFloat(dblval);
break;
case TIFFTAG_PLANARCONFIG:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE)
goto badvalue;
td->td_planarconfig = (uint16_t)v;
break;
case TIFFTAG_XPOSITION:
td->td_xposition = _TIFFClampDoubleToFloat(va_arg(ap, double));
break;
case TIFFTAG_YPOSITION:
td->td_yposition = _TIFFClampDoubleToFloat(va_arg(ap, double));
break;
case TIFFTAG_RESOLUTIONUNIT:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v)
goto badvalue;
td->td_resolutionunit = (uint16_t)v;
break;
case TIFFTAG_PAGENUMBER:
td->td_pagenumber[0] = (uint16_t)va_arg(ap, uint16_vap);
td->td_pagenumber[1] = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_HALFTONEHINTS:
td->td_halftonehints[0] = (uint16_t)va_arg(ap, uint16_vap);
td->td_halftonehints[1] = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_COLORMAP:
v32 = (uint32_t)(1L << td->td_bitspersample);
_TIFFsetShortArrayExt(tif, &td->td_colormap[0],
va_arg(ap, uint16_t *), v32);
_TIFFsetShortArrayExt(tif, &td->td_colormap[1],
va_arg(ap, uint16_t *), v32);
_TIFFsetShortArrayExt(tif, &td->td_colormap[2],
va_arg(ap, uint16_t *), v32);
break;
case TIFFTAG_EXTRASAMPLES:
if (!setExtraSamples(tif, ap, &v))
goto badvalue;
break;
case TIFFTAG_MATTEING:
td->td_extrasamples = (((uint16_t)va_arg(ap, uint16_vap)) != 0);
if (td->td_extrasamples)
{
uint16_t sv = EXTRASAMPLE_ASSOCALPHA;
_TIFFsetShortArrayExt(tif, &td->td_sampleinfo, &sv, 1);
}
break;
case TIFFTAG_TILEWIDTH:
v32 = (uint32_t)va_arg(ap, uint32_t);
if (v32 % 16)
{
if (tif->tif_mode != O_RDONLY)
goto badvalue32;
TIFFWarningExtR(
tif, tif->tif_name,
"Nonstandard tile width %" PRIu32 ", convert file", v32);
}
td->td_tilewidth = v32;
tif->tif_flags |= TIFF_ISTILED;
break;
case TIFFTAG_TILELENGTH:
v32 = (uint32_t)va_arg(ap, uint32_t);
if (v32 % 16)
{
if (tif->tif_mode != O_RDONLY)
goto badvalue32;
TIFFWarningExtR(
tif, tif->tif_name,
"Nonstandard tile length %" PRIu32 ", convert file", v32);
}
td->td_tilelength = v32;
tif->tif_flags |= TIFF_ISTILED;
break;
case TIFFTAG_TILEDEPTH:
v32 = (uint32_t)va_arg(ap, uint32_t);
if (v32 == 0)
goto badvalue32;
td->td_tiledepth = v32;
break;
case TIFFTAG_DATATYPE:
v = (uint16_t)va_arg(ap, uint16_vap);
switch (v)
{
case DATATYPE_VOID:
v = SAMPLEFORMAT_VOID;
break;
case DATATYPE_INT:
v = SAMPLEFORMAT_INT;
break;
case DATATYPE_UINT:
v = SAMPLEFORMAT_UINT;
break;
case DATATYPE_IEEEFP:
v = SAMPLEFORMAT_IEEEFP;
break;
default:
goto badvalue;
}
td->td_sampleformat = (uint16_t)v;
break;
case TIFFTAG_SAMPLEFORMAT:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v)
goto badvalue;
td->td_sampleformat = (uint16_t)v;
if (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT &&
td->td_bitspersample == 32 &&
tif->tif_postdecode == _TIFFSwab32BitData)
tif->tif_postdecode = _TIFFSwab16BitData;
else if ((td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT ||
td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP) &&
td->td_bitspersample == 64 &&
tif->tif_postdecode == _TIFFSwab64BitData)
tif->tif_postdecode = _TIFFSwab32BitData;
break;
case TIFFTAG_IMAGEDEPTH:
td->td_imagedepth = (uint32_t)va_arg(ap, uint32_t);
break;
case TIFFTAG_SUBIFD:
if ((tif->tif_flags & TIFF_INSUBIFD) == 0)
{
td->td_nsubifd = (uint16_t)va_arg(ap, uint16_vap);
_TIFFsetLong8Array(tif, &td->td_subifd,
(uint64_t *)va_arg(ap, uint64_t *),
(uint32_t)td->td_nsubifd);
}
else
{
TIFFErrorExtR(tif, module, "%s: Sorry, cannot nest SubIFDs",
tif->tif_name);
status = 0;
}
break;
case TIFFTAG_YCBCRPOSITIONING:
td->td_ycbcrpositioning = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_YCBCRSUBSAMPLING:
td->td_ycbcrsubsampling[0] = (uint16_t)va_arg(ap, uint16_vap);
td->td_ycbcrsubsampling[1] = (uint16_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_TRANSFERFUNCTION:
{
uint32_t i;
v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1;
for (i = 0; i < v; i++)
_TIFFsetShortArrayExt(tif, &td->td_transferfunction[i],
va_arg(ap, uint16_t *),
1U << td->td_bitspersample);
break;
}
case TIFFTAG_REFERENCEBLACKWHITE:
_TIFFsetFloatArrayExt(tif, &td->td_refblackwhite,
va_arg(ap, float *), 6);
break;
case TIFFTAG_INKNAMES:
{
v = (uint16_t)va_arg(ap, uint16_vap);
s = va_arg(ap, char *);
uint16_t ninksinstring;
ninksinstring = countInkNamesString(tif, v, s);
status = ninksinstring > 0;
if (ninksinstring > 0)
{
_TIFFsetNString(tif, &td->td_inknames, s, v);
td->td_inknameslen = v;
if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS))
{
if (td->td_numberofinks != ninksinstring)
{
TIFFErrorExtR(
tif, module,
"Warning %s; Tag %s:\n Value %" PRIu16
" of NumberOfInks is different from the number of "
"inks %" PRIu16
".\n -> NumberOfInks value adapted to %" PRIu16 "",
tif->tif_name, fip->field_name, td->td_numberofinks,
ninksinstring, ninksinstring);
td->td_numberofinks = ninksinstring;
}
}
else
{
td->td_numberofinks = ninksinstring;
TIFFSetFieldBit(tif, FIELD_NUMBEROFINKS);
}
if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
{
if (td->td_numberofinks != td->td_samplesperpixel)
{
TIFFErrorExtR(tif, module,
"Warning %s; Tag %s:\n Value %" PRIu16
" of NumberOfInks is different from the "
"SamplesPerPixel value %" PRIu16 "",
tif->tif_name, fip->field_name,
td->td_numberofinks,
td->td_samplesperpixel);
}
}
}
}
break;
case TIFFTAG_NUMBEROFINKS:
v = (uint16_t)va_arg(ap, uint16_vap);
if (TIFFFieldSet(tif, FIELD_INKNAMES))
{
if (v != td->td_numberofinks)
{
TIFFErrorExtR(
tif, module,
"Error %s; Tag %s:\n It is not possible to set the "
"value %" PRIu32
" for NumberOfInks\n which is different from the "
"number of inks in the InkNames tag (%" PRIu16 ")",
tif->tif_name, fip->field_name, v, td->td_numberofinks);
status = 0;
}
}
else
{
td->td_numberofinks = (uint16_t)v;
if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
{
if (td->td_numberofinks != td->td_samplesperpixel)
{
TIFFErrorExtR(tif, module,
"Warning %s; Tag %s:\n Value %" PRIu32
" of NumberOfInks is different from the "
"SamplesPerPixel value %" PRIu16 "",
tif->tif_name, fip->field_name, v,
td->td_samplesperpixel);
}
}
}
break;
case TIFFTAG_PERSAMPLE:
v = (uint16_t)va_arg(ap, uint16_vap);
if (v == PERSAMPLE_MULTI)
tif->tif_flags |= TIFF_PERSAMPLE;
else
tif->tif_flags &= ~TIFF_PERSAMPLE;
break;
default:
{
TIFFTagValue *tv;
int tv_size, iCustom;
if (fip->field_bit == FIELD_IGNORE)
{
TIFFErrorExtR(
tif, module,
"%s: Ignored %stag \"%s\" (not supported by libtiff)",
tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
fip->field_name);
status = 0;
break;
}
if (fip->field_bit != FIELD_CUSTOM)
{
TIFFErrorExtR(
tif, module,
"%s: Invalid %stag \"%s\" (not supported by codec)",
tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
fip->field_name);
status = 0;
break;
}
tv = NULL;
for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++)
{
if (td->td_customValues[iCustom].info->field_tag == tag)
{
tv = td->td_customValues + iCustom;
if (tv->value != NULL)
{
_TIFFfreeExt(tif, tv->value);
tv->value = NULL;
}
break;
}
}
if (tv == NULL)
{
TIFFTagValue *new_customValues;
td->td_customValueCount++;
new_customValues = (TIFFTagValue *)_TIFFreallocExt(
tif, td->td_customValues,
sizeof(TIFFTagValue) * td->td_customValueCount);
if (!new_customValues)
{
TIFFErrorExtR(tif, module,
"%s: Failed to allocate space for list of "
"custom values",
tif->tif_name);
status = 0;
goto end;
}
td->td_customValues = new_customValues;
tv = td->td_customValues + (td->td_customValueCount - 1);
tv->info = fip;
tv->value = NULL;
tv->count = 0;
}
tv_size = TIFFFieldSetGetSize(fip);
if (tv_size == 0)
{
status = 0;
TIFFErrorExtR(tif, module, "%s: Bad field type %d for \"%s\"",
tif->tif_name, fip->field_type, fip->field_name);
goto end;
}
if (fip->field_type == TIFF_ASCII)
{
uint32_t ma;
const char *mb;
if (fip->field_passcount)
{
assert(fip->field_writecount == TIFF_VARIABLE2);
ma = (uint32_t)va_arg(ap, uint32_t);
mb = (const char *)va_arg(ap, const char *);
}
else
{
mb = (const char *)va_arg(ap, const char *);
size_t len = strlen(mb) + 1;
if (len >= 0x80000000U)
{
status = 0;
TIFFErrorExtR(tif, module,
"%s: Too long string value for \"%s\". "
"Maximum supported is 2147483647 bytes",
tif->tif_name, fip->field_name);
goto end;
}
ma = (uint32_t)len;
}
tv->count = ma;
setByteArray(tif, &tv->value, mb, ma, 1);
}
else
{
if (fip->field_passcount)
{
if (fip->field_writecount == TIFF_VARIABLE2)
tv->count = (uint32_t)va_arg(ap, uint32_t);
else
tv->count = (int)va_arg(ap, int);
}
else if (fip->field_writecount == TIFF_VARIABLE ||
fip->field_writecount == TIFF_VARIABLE2)
tv->count = 1;
else if (fip->field_writecount == TIFF_SPP)
tv->count = td->td_samplesperpixel;
else
tv->count = fip->field_writecount;
if (tv->count == 0)
{
status = 0;
TIFFErrorExtR(tif, module,
"%s: Null count for \"%s\" (type "
"%d, writecount %d, passcount %d)",
tif->tif_name, fip->field_name,
fip->field_type, fip->field_writecount,
fip->field_passcount);
goto end;
}
tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size,
"custom tag binary object");
if (!tv->value)
{
status = 0;
goto end;
}
if (fip->field_tag == TIFFTAG_DOTRANGE &&
strcmp(fip->field_name, "DotRange") == 0)
{
uint16_t v2[2];
v2[0] = (uint16_t)va_arg(ap, int);
v2[1] = (uint16_t)va_arg(ap, int);
_TIFFmemcpy(tv->value, &v2, 4);
}
else if (fip->field_passcount ||
fip->field_writecount == TIFF_VARIABLE ||
fip->field_writecount == TIFF_VARIABLE2 ||
fip->field_writecount == TIFF_SPP || tv->count > 1)
{
_TIFFmemcpy(tv->value, va_arg(ap, void *),
tv->count * tv_size);
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
if (tv->info->field_type == TIFF_LONG8)
{
uint64_t *pui64 = (uint64_t *)tv->value;
for (int i = 0; i < tv->count; i++)
{
if (pui64[i] > 0xffffffffu)
{
TIFFErrorExtR(
tif, module,
"%s: Bad LONG8 value %" PRIu64
" at %d. array position for \"%s\" tag "
"%d in ClassicTIFF. Tag won't be "
"written to file",
tif->tif_name, pui64[i], i,
fip->field_name, tag);
goto badvalueifd8long8;
}
}
}
else if (tv->info->field_type == TIFF_SLONG8)
{
int64_t *pi64 = (int64_t *)tv->value;
for (int i = 0; i < tv->count; i++)
{
if (pi64[i] > 2147483647 ||
pi64[i] < (-2147483647 - 1))
{
TIFFErrorExtR(
tif, module,
"%s: Bad SLONG8 value %" PRIi64
" at %d. array position for \"%s\" tag "
"%d in ClassicTIFF. Tag won't be "
"written to file",
tif->tif_name, pi64[i], i,
fip->field_name, tag);
goto badvalueifd8long8;
}
}
}
}
}
else
{
char *val = (char *)tv->value;
assert(tv->count == 1);
switch (fip->field_type)
{
case TIFF_BYTE:
case TIFF_UNDEFINED:
{
uint8_t v2 = (uint8_t)va_arg(ap, int);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_SBYTE:
{
int8_t v2 = (int8_t)va_arg(ap, int);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_SHORT:
{
uint16_t v2 = (uint16_t)va_arg(ap, int);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_SSHORT:
{
int16_t v2 = (int16_t)va_arg(ap, int);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_LONG:
case TIFF_IFD:
{
uint32_t v2 = va_arg(ap, uint32_t);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_SLONG:
{
int32_t v2 = va_arg(ap, int32_t);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_LONG8:
case TIFF_IFD8:
{
uint64_t v2 = va_arg(ap, uint64_t);
_TIFFmemcpy(val, &v2, tv_size);
if (!(tif->tif_flags & TIFF_BIGTIFF) &&
(v2 > 0xffffffffu))
{
TIFFErrorExtR(
tif, module,
"%s: Bad LONG8 or IFD8 value %" PRIu64
" for \"%s\" tag %d in ClassicTIFF. Tag "
"won't be written to file",
tif->tif_name, v2, fip->field_name, tag);
goto badvalueifd8long8;
}
}
break;
case TIFF_SLONG8:
{
int64_t v2 = va_arg(ap, int64_t);
_TIFFmemcpy(val, &v2, tv_size);
if (!(tif->tif_flags & TIFF_BIGTIFF) &&
((v2 > 2147483647) || (v2 < (-2147483647 - 1))))
{
TIFFErrorExtR(
tif, module,
"%s: Bad SLONG8 value %" PRIi64
" for \"%s\" tag %d in ClassicTIFF. Tag "
"won't be written to file",
tif->tif_name, v2, fip->field_name, tag);
goto badvalueifd8long8;
}
}
break;
case TIFF_RATIONAL:
case TIFF_SRATIONAL:
{
if (tv_size == 8)
{
double v2 = va_arg(ap, double);
_TIFFmemcpy(val, &v2, tv_size);
}
else
{
float v3 = (float)va_arg(ap, double);
_TIFFmemcpy(val, &v3, tv_size);
if (tv_size != 4)
{
TIFFErrorExtR(
tif, module,
"Rational2Double: .set_field_type "
"in not 4 but %d",
tv_size);
}
}
}
break;
case TIFF_FLOAT:
{
float v2 =
_TIFFClampDoubleToFloat(va_arg(ap, double));
_TIFFmemcpy(val, &v2, tv_size);
}
break;
case TIFF_DOUBLE:
{
double v2 = va_arg(ap, double);
_TIFFmemcpy(val, &v2, tv_size);
}
break;
default:
_TIFFmemset(val, 0, tv_size);
status = 0;
break;
}
}
}
}
}
if (status)
{
const TIFFField *fip2 = TIFFFieldWithTag(tif, tag);
if (fip2)
TIFFSetFieldBit(tif, fip2->field_bit);
tif->tif_flags |= TIFF_DIRTYDIRECT;
}
end:
va_end(ap);
return (status);
badvalue:
{
const TIFFField *fip2 = TIFFFieldWithTag(tif, tag);
TIFFErrorExtR(tif, module, "%s: Bad value %" PRIu32 " for \"%s\" tag",
tif->tif_name, v, fip2 ? fip2->field_name : "Unknown");
va_end(ap);
}
return (0);
badvalue32:
{
const TIFFField *fip2 = TIFFFieldWithTag(tif, tag);
TIFFErrorExtR(tif, module, "%s: Bad value %" PRIu32 " for \"%s\" tag",
tif->tif_name, v32, fip2 ? fip2->field_name : "Unknown");
va_end(ap);
}
return (0);
badvaluedouble:
{
const TIFFField *fip2 = TIFFFieldWithTag(tif, tag);
TIFFErrorExtR(tif, module, "%s: Bad value %f for \"%s\" tag", tif->tif_name,
dblval, fip2 ? fip2->field_name : "Unknown");
va_end(ap);
}
return (0);
badvalueifd8long8:
{
TIFFTagValue *tv2 = NULL;
int iCustom2, iC2;
for (iCustom2 = 0; iCustom2 < td->td_customValueCount; iCustom2++)
{
if (td->td_customValues[iCustom2].info->field_tag == tag)
{
tv2 = td->td_customValues + (iCustom2);
break;
}
}
if (tv2 != NULL)
{
if (tv2->value != NULL)
{
_TIFFfreeExt(tif, tv2->value);
tv2->value = NULL;
}
td->td_customValueCount--;
for (iC2 = iCustom2; iC2 < td->td_customValueCount; iC2++)
{
td->td_customValues[iC2] = td->td_customValues[iC2 + 1];
}
}
else
{
assert(0);
}
va_end(ap);
}
return (0);
}
static int OkToChangeTag(TIFF *tif, uint32_t tag)
{
const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
if (!fip)
{
TIFFErrorExtR(tif, "TIFFSetField", "%s: Unknown %stag %" PRIu32,
tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag);
return (0);
}
if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) &&
!fip->field_oktochange)
{
TIFFErrorExtR(tif, "TIFFSetField",
"%s: Cannot modify tag \"%s\" while writing",
tif->tif_name, fip->field_name);
return (0);
}
return (1);
}
int TIFFSetField(TIFF *tif, uint32_t tag, ...)
{
va_list ap;
int status;
va_start(ap, tag);
status = TIFFVSetField(tif, tag, ap);
va_end(ap);
return (status);
}
int TIFFUnsetField(TIFF *tif, uint32_t tag)
{
const TIFFField *fip = TIFFFieldWithTag(tif, tag);
TIFFDirectory *td = &tif->tif_dir;
if (!fip)
return 0;
if (fip->field_bit != FIELD_CUSTOM)
TIFFClrFieldBit(tif, fip->field_bit);
else
{
TIFFTagValue *tv = NULL;
int i;
for (i = 0; i < td->td_customValueCount; i++)
{
tv = td->td_customValues + i;
if (tv->info->field_tag == tag)
break;
}
if (i < td->td_customValueCount)
{
_TIFFfreeExt(tif, tv->value);
for (; i < td->td_customValueCount - 1; i++)
{
td->td_customValues[i] = td->td_customValues[i + 1];
}
td->td_customValueCount--;
}
}
tif->tif_flags |= TIFF_DIRTYDIRECT;
return (1);
}
int TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap)
{
return OkToChangeTag(tif, tag)
? (*tif->tif_tagmethods.vsetfield)(tif, tag, ap)
: 0;
}
static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap)
{
TIFFDirectory *td = &tif->tif_dir;
int ret_val = 1;
uint32_t standard_tag = tag;
const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
if (fip == NULL)
return 0;
if (fip->field_bit == FIELD_CUSTOM)
{
standard_tag = 0;
}
switch (standard_tag)
{
case TIFFTAG_SUBFILETYPE:
*va_arg(ap, uint32_t *) = td->td_subfiletype;
break;
case TIFFTAG_IMAGEWIDTH:
*va_arg(ap, uint32_t *) = td->td_imagewidth;
break;
case TIFFTAG_IMAGELENGTH:
*va_arg(ap, uint32_t *) = td->td_imagelength;
break;
case TIFFTAG_BITSPERSAMPLE:
*va_arg(ap, uint16_t *) = td->td_bitspersample;
break;
case TIFFTAG_COMPRESSION:
*va_arg(ap, uint16_t *) = td->td_compression;
break;
case TIFFTAG_PHOTOMETRIC:
*va_arg(ap, uint16_t *) = td->td_photometric;
break;
case TIFFTAG_THRESHHOLDING:
*va_arg(ap, uint16_t *) = td->td_threshholding;
break;
case TIFFTAG_FILLORDER:
*va_arg(ap, uint16_t *) = td->td_fillorder;
break;
case TIFFTAG_ORIENTATION:
*va_arg(ap, uint16_t *) = td->td_orientation;
break;
case TIFFTAG_SAMPLESPERPIXEL:
*va_arg(ap, uint16_t *) = td->td_samplesperpixel;
break;
case TIFFTAG_ROWSPERSTRIP:
*va_arg(ap, uint32_t *) = td->td_rowsperstrip;
break;
case TIFFTAG_MINSAMPLEVALUE:
*va_arg(ap, uint16_t *) = td->td_minsamplevalue;
break;
case TIFFTAG_MAXSAMPLEVALUE:
*va_arg(ap, uint16_t *) = td->td_maxsamplevalue;
break;
case TIFFTAG_SMINSAMPLEVALUE:
if (tif->tif_flags & TIFF_PERSAMPLE)
*va_arg(ap, double **) = td->td_sminsamplevalue;
else
{
uint16_t i;
double v = td->td_sminsamplevalue[0];
for (i = 1; i < td->td_samplesperpixel; ++i)
if (td->td_sminsamplevalue[i] < v)
v = td->td_sminsamplevalue[i];
*va_arg(ap, double *) = v;
}
break;
case TIFFTAG_SMAXSAMPLEVALUE:
if (tif->tif_flags & TIFF_PERSAMPLE)
*va_arg(ap, double **) = td->td_smaxsamplevalue;
else
{
uint16_t i;
double v = td->td_smaxsamplevalue[0];
for (i = 1; i < td->td_samplesperpixel; ++i)
if (td->td_smaxsamplevalue[i] > v)
v = td->td_smaxsamplevalue[i];
*va_arg(ap, double *) = v;
}
break;
case TIFFTAG_XRESOLUTION:
*va_arg(ap, float *) = td->td_xresolution;
break;
case TIFFTAG_YRESOLUTION:
*va_arg(ap, float *) = td->td_yresolution;
break;
case TIFFTAG_PLANARCONFIG:
*va_arg(ap, uint16_t *) = td->td_planarconfig;
break;
case TIFFTAG_XPOSITION:
*va_arg(ap, float *) = td->td_xposition;
break;
case TIFFTAG_YPOSITION:
*va_arg(ap, float *) = td->td_yposition;
break;
case TIFFTAG_RESOLUTIONUNIT:
*va_arg(ap, uint16_t *) = td->td_resolutionunit;
break;
case TIFFTAG_PAGENUMBER:
*va_arg(ap, uint16_t *) = td->td_pagenumber[0];
*va_arg(ap, uint16_t *) = td->td_pagenumber[1];
break;
case TIFFTAG_HALFTONEHINTS:
*va_arg(ap, uint16_t *) = td->td_halftonehints[0];
*va_arg(ap, uint16_t *) = td->td_halftonehints[1];
break;
case TIFFTAG_COLORMAP:
*va_arg(ap, const uint16_t **) = td->td_colormap[0];
*va_arg(ap, const uint16_t **) = td->td_colormap[1];
*va_arg(ap, const uint16_t **) = td->td_colormap[2];
break;
case TIFFTAG_STRIPOFFSETS:
case TIFFTAG_TILEOFFSETS:
_TIFFFillStriles(tif);
*va_arg(ap, const uint64_t **) = td->td_stripoffset_p;
if (td->td_stripoffset_p == NULL)
ret_val = 0;
break;
case TIFFTAG_STRIPBYTECOUNTS:
case TIFFTAG_TILEBYTECOUNTS:
_TIFFFillStriles(tif);
*va_arg(ap, const uint64_t **) = td->td_stripbytecount_p;
if (td->td_stripbytecount_p == NULL)
ret_val = 0;
break;
case TIFFTAG_MATTEING:
*va_arg(ap, uint16_t *) =
(td->td_extrasamples == 1 &&
td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
break;
case TIFFTAG_EXTRASAMPLES:
*va_arg(ap, uint16_t *) = td->td_extrasamples;
*va_arg(ap, const uint16_t **) = td->td_sampleinfo;
break;
case TIFFTAG_TILEWIDTH:
*va_arg(ap, uint32_t *) = td->td_tilewidth;
break;
case TIFFTAG_TILELENGTH:
*va_arg(ap, uint32_t *) = td->td_tilelength;
break;
case TIFFTAG_TILEDEPTH:
*va_arg(ap, uint32_t *) = td->td_tiledepth;
break;
case TIFFTAG_DATATYPE:
switch (td->td_sampleformat)
{
case SAMPLEFORMAT_UINT:
*va_arg(ap, uint16_t *) = DATATYPE_UINT;
break;
case SAMPLEFORMAT_INT:
*va_arg(ap, uint16_t *) = DATATYPE_INT;
break;
case SAMPLEFORMAT_IEEEFP:
*va_arg(ap, uint16_t *) = DATATYPE_IEEEFP;
break;
case SAMPLEFORMAT_VOID:
*va_arg(ap, uint16_t *) = DATATYPE_VOID;
break;
}
break;
case TIFFTAG_SAMPLEFORMAT:
*va_arg(ap, uint16_t *) = td->td_sampleformat;
break;
case TIFFTAG_IMAGEDEPTH:
*va_arg(ap, uint32_t *) = td->td_imagedepth;
break;
case TIFFTAG_SUBIFD:
*va_arg(ap, uint16_t *) = td->td_nsubifd;
*va_arg(ap, const uint64_t **) = td->td_subifd;
break;
case TIFFTAG_YCBCRPOSITIONING:
*va_arg(ap, uint16_t *) = td->td_ycbcrpositioning;
break;
case TIFFTAG_YCBCRSUBSAMPLING:
*va_arg(ap, uint16_t *) = td->td_ycbcrsubsampling[0];
*va_arg(ap, uint16_t *) = td->td_ycbcrsubsampling[1];
break;
case TIFFTAG_TRANSFERFUNCTION:
*va_arg(ap, const uint16_t **) = td->td_transferfunction[0];
if (td->td_samplesperpixel - td->td_extrasamples > 1)
{
*va_arg(ap, const uint16_t **) = td->td_transferfunction[1];
*va_arg(ap, const uint16_t **) = td->td_transferfunction[2];
}
else
{
*va_arg(ap, const uint16_t **) = NULL;
*va_arg(ap, const uint16_t **) = NULL;
}
break;
case TIFFTAG_REFERENCEBLACKWHITE:
*va_arg(ap, const float **) = td->td_refblackwhite;
break;
case TIFFTAG_INKNAMES:
*va_arg(ap, const char **) = td->td_inknames;
break;
case TIFFTAG_NUMBEROFINKS:
*va_arg(ap, uint16_t *) = td->td_numberofinks;
break;
default:
{
int i;
if (fip->field_bit != FIELD_CUSTOM)
{
TIFFErrorExtR(tif, "_TIFFVGetField",
"%s: Invalid %stag \"%s\" "
"(not supported by codec)",
tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
fip->field_name);
ret_val = 0;
break;
}
ret_val = 0;
for (i = 0; i < td->td_customValueCount; i++)
{
TIFFTagValue *tv = td->td_customValues + i;
if (tv->info->field_tag != tag)
continue;
if (fip->field_passcount)
{
if (fip->field_readcount == TIFF_VARIABLE2)
*va_arg(ap, uint32_t *) = (uint32_t)tv->count;
else
*va_arg(ap, uint16_t *) = (uint16_t)tv->count;
*va_arg(ap, const void **) = tv->value;
ret_val = 1;
}
else if (fip->field_tag == TIFFTAG_DOTRANGE &&
strcmp(fip->field_name, "DotRange") == 0)
{
*va_arg(ap, uint16_t *) = ((uint16_t *)tv->value)[0];
*va_arg(ap, uint16_t *) = ((uint16_t *)tv->value)[1];
ret_val = 1;
}
else
{
if (fip->field_type == TIFF_ASCII ||
fip->field_readcount == TIFF_VARIABLE ||
fip->field_readcount == TIFF_VARIABLE2 ||
fip->field_readcount == TIFF_SPP || tv->count > 1)
{
*va_arg(ap, void **) = tv->value;
ret_val = 1;
}
else
{
char *val = (char *)tv->value;
assert(tv->count == 1);
switch (fip->field_type)
{
case TIFF_BYTE:
case TIFF_UNDEFINED:
*va_arg(ap, uint8_t *) = *(uint8_t *)val;
ret_val = 1;
break;
case TIFF_SBYTE:
*va_arg(ap, int8_t *) = *(int8_t *)val;
ret_val = 1;
break;
case TIFF_SHORT:
*va_arg(ap, uint16_t *) = *(uint16_t *)val;
ret_val = 1;
break;
case TIFF_SSHORT:
*va_arg(ap, int16_t *) = *(int16_t *)val;
ret_val = 1;
break;
case TIFF_LONG:
case TIFF_IFD:
*va_arg(ap, uint32_t *) = *(uint32_t *)val;
ret_val = 1;
break;
case TIFF_SLONG:
*va_arg(ap, int32_t *) = *(int32_t *)val;
ret_val = 1;
break;
case TIFF_LONG8:
case TIFF_IFD8:
*va_arg(ap, uint64_t *) = *(uint64_t *)val;
ret_val = 1;
break;
case TIFF_SLONG8:
*va_arg(ap, int64_t *) = *(int64_t *)val;
ret_val = 1;
break;
case TIFF_RATIONAL:
case TIFF_SRATIONAL:
{
int tv_size = TIFFFieldSetGetSize(fip);
if (tv_size == 8)
{
*va_arg(ap, double *) = *(double *)val;
ret_val = 1;
}
else
{
*va_arg(ap, float *) = *(float *)val;
ret_val = 1;
if (tv_size != 4)
{
TIFFErrorExtR(
tif, "_TIFFVGetField",
"Rational2Double: .set_field_type "
"in not 4 but %d",
tv_size);
}
}
}
break;
case TIFF_FLOAT:
*va_arg(ap, float *) = *(float *)val;
ret_val = 1;
break;
case TIFF_DOUBLE:
*va_arg(ap, double *) = *(double *)val;
ret_val = 1;
break;
default:
ret_val = 0;
break;
}
}
}
break;
}
}
}
return (ret_val);
}
int TIFFGetField(TIFF *tif, uint32_t tag, ...)
{
int status;
va_list ap;
va_start(ap, tag);
status = TIFFVGetField(tif, tag, ap);
va_end(ap);
return (status);
}
int TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap)
{
const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit))
? (*tif->tif_tagmethods.vgetfield)(tif, tag, ap)
: 0);
}
#define CleanupField(member) \
{ \
if (td->member) \
{ \
_TIFFfreeExt(tif, td->member); \
td->member = 0; \
} \
}
void TIFFFreeDirectory(TIFF *tif)
{
TIFFDirectory *td = &tif->tif_dir;
int i;
_TIFFmemset(td->td_fieldsset, 0, sizeof(td->td_fieldsset));
CleanupField(td_sminsamplevalue);
CleanupField(td_smaxsamplevalue);
CleanupField(td_colormap[0]);
CleanupField(td_colormap[1]);
CleanupField(td_colormap[2]);
CleanupField(td_sampleinfo);
CleanupField(td_subifd);
CleanupField(td_inknames);
CleanupField(td_refblackwhite);
CleanupField(td_transferfunction[0]);
CleanupField(td_transferfunction[1]);
CleanupField(td_transferfunction[2]);
CleanupField(td_stripoffset_p);
CleanupField(td_stripbytecount_p);
td->td_stripoffsetbyteallocsize = 0;
TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING);
TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING);
for (i = 0; i < td->td_customValueCount; i++)
{
if (td->td_customValues[i].value)
_TIFFfreeExt(tif, td->td_customValues[i].value);
}
td->td_customValueCount = 0;
CleanupField(td_customValues);
_TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
_TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
tif->tif_dir.td_dirdatasize_read = 0;
tif->tif_dir.td_dirdatasize_write = 0;
if (tif->tif_dir.td_dirdatasize_offsets != NULL)
{
_TIFFfreeExt(tif, tif->tif_dir.td_dirdatasize_offsets);
tif->tif_dir.td_dirdatasize_offsets = NULL;
tif->tif_dir.td_dirdatasize_Noffsets = 0;
}
tif->tif_dir.td_iswrittentofile = FALSE;
}
#undef CleanupField
static TIFFExtendProc _TIFFextender = (TIFFExtendProc)NULL;
TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc extender)
{
TIFFExtendProc prev = _TIFFextender;
_TIFFextender = extender;
return (prev);
}
int TIFFCreateDirectory(TIFF *tif)
{
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif);
tif->tif_diroff = 0;
tif->tif_nextdiroff = 0;
tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
tif->tif_dir.td_iswrittentofile = FALSE;
return 0;
}
int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray)
{
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif);
_TIFFSetupFields(tif, infoarray);
tif->tif_diroff = 0;
tif->tif_nextdiroff = 0;
tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
_TIFFCleanupIFDOffsetAndNumberMaps(tif);
tif->tif_setdirectory_force_absolute = TRUE;
return 0;
}
int TIFFCreateEXIFDirectory(TIFF *tif)
{
const TIFFFieldArray *exifFieldArray;
exifFieldArray = _TIFFGetExifFields();
return TIFFCreateCustomDirectory(tif, exifFieldArray);
}
int TIFFCreateGPSDirectory(TIFF *tif)
{
const TIFFFieldArray *gpsFieldArray;
gpsFieldArray = _TIFFGetGpsFields();
return TIFFCreateCustomDirectory(tif, gpsFieldArray);
}
int TIFFDefaultDirectory(TIFF *tif)
{
register TIFFDirectory *td = &tif->tif_dir;
const TIFFFieldArray *tiffFieldArray;
tiffFieldArray = _TIFFGetFields();
_TIFFSetupFields(tif, tiffFieldArray);
_TIFFmemset(td, 0, sizeof(*td));
td->td_fillorder = FILLORDER_MSB2LSB;
td->td_bitspersample = 1;
td->td_threshholding = THRESHHOLD_BILEVEL;
td->td_orientation = ORIENTATION_TOPLEFT;
td->td_samplesperpixel = 1;
td->td_rowsperstrip = (uint32_t)-1;
td->td_tilewidth = 0;
td->td_tilelength = 0;
td->td_tiledepth = 1;
#ifdef STRIPBYTECOUNTSORTED_UNUSED
td->td_stripbytecountsorted = 1;
#endif
td->td_resolutionunit = RESUNIT_INCH;
td->td_sampleformat = SAMPLEFORMAT_UINT;
td->td_imagedepth = 1;
td->td_ycbcrsubsampling[0] = 2;
td->td_ycbcrsubsampling[1] = 2;
td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED;
tif->tif_postdecode = _TIFFNoPostDecode;
tif->tif_foundfield = NULL;
tif->tif_tagmethods.vsetfield = _TIFFVSetField;
tif->tif_tagmethods.vgetfield = _TIFFVGetField;
tif->tif_tagmethods.printdir = NULL;
td->td_planarconfig = PLANARCONFIG_CONTIG;
td->td_compression = COMPRESSION_NONE;
td->td_subfiletype = 0;
td->td_minsamplevalue = 0;
td->td_maxsamplevalue = 1;
td->td_extrasamples = 0;
td->td_sampleinfo = NULL;
if (tif->tif_nfieldscompat > 0)
{
uint32_t i;
for (i = 0; i < tif->tif_nfieldscompat; i++)
{
if (tif->tif_fieldscompat[i].allocated_size)
_TIFFfreeExt(tif, tif->tif_fieldscompat[i].fields);
}
_TIFFfreeExt(tif, tif->tif_fieldscompat);
tif->tif_nfieldscompat = 0;
tif->tif_fieldscompat = NULL;
}
if (_TIFFextender)
(*_TIFFextender)(tif);
(void)TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
tif->tif_flags &= ~TIFF_DIRTYDIRECT;
tif->tif_flags &= ~TIFF_ISTILED;
return (1);
}
static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
tdir_t *nextdirnum)
{
static const char module[] = "TIFFAdvanceDirectory";
if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff))
{
TIFFErrorExtR(tif, module,
"Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64
") might cause an IFD loop",
*nextdirnum, *nextdiroff, *nextdiroff);
*nextdiroff = 0;
*nextdirnum = 0;
return (0);
}
if (isMapped(tif))
{
uint64_t poff = *nextdiroff;
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
tmsize_t poffa, poffb, poffc, poffd;
uint16_t dircount;
uint32_t nextdir32;
poffa = (tmsize_t)poff;
poffb = poffa + sizeof(uint16_t);
if (((uint64_t)poffa != poff) || (poffb < poffa) ||
(poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size))
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
*nextdiroff = 0;
return (0);
}
_TIFFmemcpy(&dircount, tif->tif_base + poffa, sizeof(uint16_t));
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&dircount);
poffc = poffb + dircount * 12;
poffd = poffc + sizeof(uint32_t);
if ((poffc < poffb) || (poffc < dircount * 12) || (poffd < poffc) ||
(poffd < (tmsize_t)sizeof(uint32_t)) || (poffd > tif->tif_size))
{
TIFFErrorExtR(tif, module, "Error fetching directory link");
return (0);
}
if (off != NULL)
*off = (uint64_t)poffc;
_TIFFmemcpy(&nextdir32, tif->tif_base + poffc, sizeof(uint32_t));
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong(&nextdir32);
*nextdiroff = nextdir32;
}
else
{
tmsize_t poffa, poffb, poffc, poffd;
uint64_t dircount64;
uint16_t dircount16;
if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t))
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0);
}
poffa = (tmsize_t)poff;
poffb = poffa + sizeof(uint64_t);
if (poffb > tif->tif_size)
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0);
}
_TIFFmemcpy(&dircount64, tif->tif_base + poffa, sizeof(uint64_t));
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&dircount64);
if (dircount64 > 0xFFFF)
{
TIFFErrorExtR(tif, module,
"Sanity check on directory count failed");
return (0);
}
dircount16 = (uint16_t)dircount64;
if (poffb > TIFF_TMSIZE_T_MAX - (tmsize_t)(dircount16 * 20) -
(tmsize_t)sizeof(uint64_t))
{
TIFFErrorExtR(tif, module, "Error fetching directory link");
return (0);
}
poffc = poffb + dircount16 * 20;
poffd = poffc + sizeof(uint64_t);
if (poffd > tif->tif_size)
{
TIFFErrorExtR(tif, module, "Error fetching directory link");
return (0);
}
if (off != NULL)
*off = (uint64_t)poffc;
_TIFFmemcpy(nextdiroff, tif->tif_base + poffc, sizeof(uint64_t));
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(nextdiroff);
}
}
else
{
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
uint16_t dircount;
uint32_t nextdir32;
if (!SeekOK(tif, *nextdiroff) ||
!ReadOK(tif, &dircount, sizeof(uint16_t)))
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0);
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&dircount);
if (off != NULL)
*off = TIFFSeekFile(tif, dircount * 12, SEEK_CUR);
else
(void)TIFFSeekFile(tif, dircount * 12, SEEK_CUR);
if (!ReadOK(tif, &nextdir32, sizeof(uint32_t)))
{
TIFFErrorExtR(tif, module, "%s: Error fetching directory link",
tif->tif_name);
return (0);
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong(&nextdir32);
*nextdiroff = nextdir32;
}
else
{
uint64_t dircount64;
uint16_t dircount16;
if (!SeekOK(tif, *nextdiroff) ||
!ReadOK(tif, &dircount64, sizeof(uint64_t)))
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0);
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&dircount64);
if (dircount64 > 0xFFFF)
{
TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0);
}
dircount16 = (uint16_t)dircount64;
if (off != NULL)
*off = TIFFSeekFile(tif, dircount16 * 20, SEEK_CUR);
else
(void)TIFFSeekFile(tif, dircount16 * 20, SEEK_CUR);
if (!ReadOK(tif, nextdiroff, sizeof(uint64_t)))
{
TIFFErrorExtR(tif, module, "%s: Error fetching directory link",
tif->tif_name);
return (0);
}
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(nextdiroff);
}
}
if (*nextdiroff != 0)
{
(*nextdirnum)++;
if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff))
{
TIFFWarningExtR(
tif, module,
"the next directory %u at offset 0x%" PRIx64 " (%" PRIu64
") might be an IFD loop. Treating directory %d as "
"last directory",
*nextdirnum, *nextdiroff, *nextdiroff, (int)(*nextdirnum) - 1);
*nextdiroff = 0;
(*nextdirnum)--;
}
}
return (1);
}
tdir_t TIFFNumberOfDirectories(TIFF *tif)
{
uint64_t nextdiroff;
tdir_t nextdirnum;
tdir_t n;
if (!(tif->tif_flags & TIFF_BIGTIFF))
nextdiroff = tif->tif_header.classic.tiff_diroff;
else
nextdiroff = tif->tif_header.big.tiff_diroff;
nextdirnum = 0;
n = 0;
while (nextdiroff != 0 &&
TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
{
++n;
}
tif->tif_curdircount = n;
return (n);
}
int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
{
uint64_t nextdiroff;
tdir_t nextdirnum = 0;
tdir_t n;
if (tif->tif_setdirectory_force_absolute)
{
_TIFFCleanupIFDOffsetAndNumberMaps(tif);
}
if (!tif->tif_setdirectory_force_absolute &&
_TIFFGetOffsetFromDirNumber(tif, dirn, &nextdiroff))
{
tif->tif_nextdiroff = nextdiroff;
tif->tif_curdir = dirn;
tif->tif_setdirectory_force_absolute = FALSE;
}
else
{
const int relative = (dirn >= tif->tif_curdir) &&
(tif->tif_diroff != 0) &&
!tif->tif_setdirectory_force_absolute;
if (relative)
{
nextdiroff = tif->tif_diroff;
dirn -= tif->tif_curdir;
nextdirnum = tif->tif_curdir;
}
else if (!(tif->tif_flags & TIFF_BIGTIFF))
nextdiroff = tif->tif_header.classic.tiff_diroff;
else
nextdiroff = tif->tif_header.big.tiff_diroff;
tif->tif_setdirectory_force_absolute = FALSE;
for (n = dirn; n > 0 && nextdiroff != 0; n--)
if (!TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
return (0);
if (nextdiroff == 0 || n > 0)
return (0);
tif->tif_nextdiroff = nextdiroff;
if (relative)
tif->tif_curdir += dirn - n;
else
tif->tif_curdir = dirn - n;
}
if (tif->tif_curdir == 0)
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
else
tif->tif_curdir--;
tdir_t curdir = tif->tif_curdir;
int retval = TIFFReadDirectory(tif);
if (!retval && tif->tif_curdir == curdir)
{
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
return (retval);
}
int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
{
int retval;
uint32_t curdir = 0;
int8_t probablySubIFD = 0;
if (diroff == 0)
{
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
tif->tif_dir.td_iswrittentofile = FALSE;
}
else
{
if (!_TIFFGetDirNumberFromOffset(tif, diroff, &curdir))
{
probablySubIFD = 1;
}
if (curdir >= 1)
tif->tif_curdir = curdir - 1;
else
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
curdir = tif->tif_curdir;
tif->tif_nextdiroff = diroff;
retval = TIFFReadDirectory(tif);
if (!retval && diroff != 0 && tif->tif_curdir == curdir)
{
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
if (probablySubIFD)
{
if (retval)
{
_TIFFCleanupIFDOffsetAndNumberMaps(tif);
tif->tif_curdir = 0;
_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
}
tif->tif_setdirectory_force_absolute = TRUE;
}
return (retval);
}
uint64_t TIFFCurrentDirOffset(TIFF *tif) { return (tif->tif_diroff); }
int TIFFLastDirectory(TIFF *tif) { return (tif->tif_nextdiroff == 0); }
int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn)
{
static const char module[] = "TIFFUnlinkDirectory";
uint64_t nextdir;
tdir_t nextdirnum;
uint64_t off;
tdir_t n;
if (tif->tif_mode == O_RDONLY)
{
TIFFErrorExtR(tif, module,
"Can not unlink directory in read-only file");
return (0);
}
if (dirn == 0)
{
TIFFErrorExtR(tif, module,
"For TIFFUnlinkDirectory() first directory starts with "
"number 1 and not 0");
return (0);
}
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
nextdir = tif->tif_header.classic.tiff_diroff;
off = 4;
}
else
{
nextdir = tif->tif_header.big.tiff_diroff;
off = 8;
}
nextdirnum = 0;
for (n = dirn - 1; n > 0; n--)
{
if (nextdir == 0)
{
TIFFErrorExtR(tif, module, "Directory %u does not exist", dirn);
return (0);
}
if (!TIFFAdvanceDirectory(tif, &nextdir, &off, &nextdirnum))
return (0);
}
if (!TIFFAdvanceDirectory(tif, &nextdir, NULL, &nextdirnum))
return (0);
(void)TIFFSeekFile(tif, off, SEEK_SET);
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
uint32_t nextdir32;
nextdir32 = (uint32_t)nextdir;
assert((uint64_t)nextdir32 == nextdir);
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong(&nextdir32);
if (!WriteOK(tif, &nextdir32, sizeof(uint32_t)))
{
TIFFErrorExtR(tif, module, "Error writing directory link");
return (0);
}
}
else
{
uint64_t nextdir64 = nextdir;
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&nextdir64);
if (!WriteOK(tif, &nextdir64, sizeof(uint64_t)))
{
TIFFErrorExtR(tif, module, "Error writing directory link");
return (0);
}
}
if (dirn == 1)
{
if (!(tif->tif_flags & TIFF_BIGTIFF))
tif->tif_header.classic.tiff_diroff = (uint32_t)nextdir;
else
tif->tif_header.big.tiff_diroff = nextdir;
}
(*tif->tif_cleanup)(tif);
if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
{
_TIFFfreeExt(tif, tif->tif_rawdata);
tif->tif_rawdata = NULL;
tif->tif_rawcc = 0;
tif->tif_rawdataoff = 0;
tif->tif_rawdataloaded = 0;
}
tif->tif_flags &= ~(TIFF_BEENWRITING | TIFF_BUFFERSETUP | TIFF_POSTENCODE |
TIFF_BUF4WRITE);
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif);
tif->tif_diroff = 0;
tif->tif_nextdiroff = 0;
tif->tif_lastdiroff = 0;
tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
if (tif->tif_curdircount > 0)
tif->tif_curdircount--;
else
tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
_TIFFCleanupIFDOffsetAndNumberMaps(tif);
return (1);
}