mirror of
https://github.com/opencv/opencv.git
synced 2024-12-15 18:09:11 +08:00
52f3f5a3f6
* libtiff upgrade to version 4.6.0 * fix tiffvers.h cmake generation * temp: force build 3rd party deps from source * remove libport.h and spintf.c * cmake fixes * don't use tiff_dummy_namespace on windows * introduce numeric_types namespace alias * include cstdint * uint16_t is not a numeric_types type * fix uint16 and uint32 type defs * use standard c++ types * remove unused files * remove more unused files * revert build 3rd party code from source --------- Co-authored-by: Misha Klatis <misha.klatis@autodesk.com>
3621 lines
135 KiB
C
3621 lines
135 KiB
C
/*
|
|
* Copyright (c) 1988-1997 Sam Leffler
|
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* TIFF Library.
|
|
*
|
|
* Directory Write Support Routines.
|
|
*/
|
|
#include "tiffiop.h"
|
|
#include <float.h> /*--: for Rational2Double */
|
|
#include <math.h> /*--: for Rational2Double */
|
|
|
|
#ifdef HAVE_IEEEFP
|
|
#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
|
|
#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
|
|
#else
|
|
extern void TIFFCvtNativeToIEEEFloat(TIFF *tif, uint32_t n, float *fp);
|
|
extern void TIFFCvtNativeToIEEEDouble(TIFF *tif, uint32_t n, double *dp);
|
|
#endif
|
|
|
|
static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
|
|
uint64_t *pdiroff);
|
|
|
|
static int TIFFWriteDirectoryTagSampleformatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
double *value);
|
|
|
|
static int TIFFWriteDirectoryTagAscii(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, char *value);
|
|
static int TIFFWriteDirectoryTagUndefinedArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint8_t *value);
|
|
static int TIFFWriteDirectoryTagByteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint8_t *value);
|
|
static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int8_t *value);
|
|
static int TIFFWriteDirectoryTagShort(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value);
|
|
static int TIFFWriteDirectoryTagShortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint16_t *value);
|
|
static int TIFFWriteDirectoryTagShortPerSample(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value);
|
|
static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int16_t *value);
|
|
static int TIFFWriteDirectoryTagLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value);
|
|
static int TIFFWriteDirectoryTagLongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint32_t *value);
|
|
static int TIFFWriteDirectoryTagSlongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int32_t *value);
|
|
static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value);
|
|
static int TIFFWriteDirectoryTagSlong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int64_t *value);
|
|
static int TIFFWriteDirectoryTagRational(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
double value);
|
|
static int TIFFWriteDirectoryTagRationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value);
|
|
static int TIFFWriteDirectoryTagSrationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value);
|
|
static int TIFFWriteDirectoryTagFloatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value);
|
|
static int TIFFWriteDirectoryTagDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, double *value);
|
|
static int TIFFWriteDirectoryTagIfdArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint32_t *value);
|
|
static int TIFFWriteDirectoryTagShortLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value);
|
|
static int TIFFWriteDirectoryTagLongLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value);
|
|
static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value);
|
|
static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir);
|
|
static int TIFFWriteDirectoryTagTransferfunction(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir);
|
|
static int TIFFWriteDirectoryTagSubifd(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir);
|
|
|
|
static int TIFFWriteDirectoryTagCheckedAscii(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, char *value);
|
|
static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
uint8_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedByteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint8_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int8_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedShort(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value);
|
|
static int TIFFWriteDirectoryTagCheckedShortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint16_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int16_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value);
|
|
static int TIFFWriteDirectoryTagCheckedLongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint32_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int32_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint64_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int64_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedRational(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
double value);
|
|
static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
float *value);
|
|
static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
float *value);
|
|
|
|
/*--: Rational2Double: New functions to support true double-precision for custom
|
|
* rational tag types. */
|
|
static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
double *value);
|
|
static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
double *value);
|
|
static int
|
|
TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, double *value);
|
|
static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray(
|
|
TIFF *tif, uint32_t *ndir, TIFFDirEntry *dir, uint16_t tag, uint32_t count,
|
|
double *value);
|
|
static void DoubleToRational(double value, uint32_t *num, uint32_t *denom);
|
|
static void DoubleToSrational(double value, int32_t *num, int32_t *denom);
|
|
|
|
static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
float *value);
|
|
static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
double *value);
|
|
static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count,
|
|
uint32_t *value);
|
|
static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint64_t *value);
|
|
|
|
static int TIFFWriteDirectoryTagData(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t datatype, uint32_t count,
|
|
uint32_t datalength, void *data);
|
|
|
|
static int TIFFLinkDirectory(TIFF *);
|
|
|
|
/*
|
|
* Write the contents of the current directory
|
|
* to the specified file. This routine doesn't
|
|
* handle overwriting a directory with auxiliary
|
|
* storage that's been changed.
|
|
*/
|
|
int TIFFWriteDirectory(TIFF *tif)
|
|
{
|
|
return TIFFWriteDirectorySec(tif, TRUE, TRUE, NULL);
|
|
}
|
|
|
|
/*
|
|
* This is an advanced writing function that must be used in a particular
|
|
* sequence, and generally together with TIFFForceStrileArrayWriting(),
|
|
* to make its intended effect. Its aim is to modify the location
|
|
* where the [Strip/Tile][Offsets/ByteCounts] arrays are located in the file.
|
|
* More precisely, when TIFFWriteCheck() will be called, the tag entries for
|
|
* those arrays will be written with type = count = offset = 0 as a temporary
|
|
* value.
|
|
*
|
|
* Its effect is only valid for the current directory, and before
|
|
* TIFFWriteDirectory() is first called, and will be reset when
|
|
* changing directory.
|
|
*
|
|
* The typical sequence of calls is:
|
|
* TIFFOpen()
|
|
* [ TIFFCreateDirectory(tif) ]
|
|
* Set fields with calls to TIFFSetField(tif, ...)
|
|
* TIFFDeferStrileArrayWriting(tif)
|
|
* TIFFWriteCheck(tif, ...)
|
|
* TIFFWriteDirectory(tif)
|
|
* ... potentially create other directories and come back to the above directory
|
|
* TIFFForceStrileArrayWriting(tif): emit the arrays at the end of file
|
|
*
|
|
* Returns 1 in case of success, 0 otherwise.
|
|
*/
|
|
int TIFFDeferStrileArrayWriting(TIFF *tif)
|
|
{
|
|
static const char module[] = "TIFFDeferStrileArrayWriting";
|
|
if (tif->tif_mode == O_RDONLY)
|
|
{
|
|
TIFFErrorExtR(tif, tif->tif_name, "File opened in read-only mode");
|
|
return 0;
|
|
}
|
|
if (tif->tif_diroff != 0)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Directory has already been written");
|
|
return 0;
|
|
}
|
|
|
|
tif->tif_dir.td_deferstrilearraywriting = TRUE;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Similar to TIFFWriteDirectory(), writes the directory out
|
|
* but leaves all data structures in memory so that it can be
|
|
* written again. This will make a partially written TIFF file
|
|
* readable before it is successfully completed/closed.
|
|
*/
|
|
int TIFFCheckpointDirectory(TIFF *tif)
|
|
{
|
|
int rc;
|
|
/* Setup the strips arrays, if they haven't already been. */
|
|
if (tif->tif_dir.td_stripoffset_p == NULL)
|
|
(void)TIFFSetupStrips(tif);
|
|
rc = TIFFWriteDirectorySec(tif, TRUE, FALSE, NULL);
|
|
(void)TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
|
|
return rc;
|
|
}
|
|
|
|
int TIFFWriteCustomDirectory(TIFF *tif, uint64_t *pdiroff)
|
|
{
|
|
return TIFFWriteDirectorySec(tif, FALSE, FALSE, pdiroff);
|
|
}
|
|
|
|
/*
|
|
* Similar to TIFFWriteDirectory(), but if the directory has already
|
|
* been written once, it is relocated to the end of the file, in case it
|
|
* has changed in size. Note that this will result in the loss of the
|
|
* previously used directory space.
|
|
*/
|
|
int TIFFRewriteDirectory(TIFF *tif)
|
|
{
|
|
static const char module[] = "TIFFRewriteDirectory";
|
|
|
|
/* We don't need to do anything special if it hasn't been written. */
|
|
if (tif->tif_diroff == 0)
|
|
return TIFFWriteDirectory(tif);
|
|
|
|
/*
|
|
* Find and zero the pointer to this directory, so that TIFFLinkDirectory
|
|
* will cause it to be added after this directories current pre-link.
|
|
*/
|
|
uint64_t torewritediroff = tif->tif_diroff;
|
|
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff)
|
|
{
|
|
tif->tif_header.classic.tiff_diroff = 0;
|
|
tif->tif_diroff = 0;
|
|
|
|
TIFFSeekFile(tif, 4, SEEK_SET);
|
|
if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff), 4))
|
|
{
|
|
TIFFErrorExtR(tif, tif->tif_name, "Error updating TIFF header");
|
|
return (0);
|
|
}
|
|
}
|
|
else if (tif->tif_diroff > 0xFFFFFFFFU)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"tif->tif_diroff exceeds 32 bit range allowed for "
|
|
"Classic TIFF");
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
uint32_t nextdir;
|
|
nextdir = tif->tif_header.classic.tiff_diroff;
|
|
while (1)
|
|
{
|
|
uint16_t dircount;
|
|
uint32_t nextnextdir;
|
|
|
|
if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, 2))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error fetching directory count");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&dircount);
|
|
(void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12, SEEK_SET);
|
|
if (!ReadOK(tif, &nextnextdir, 4))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory link");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&nextnextdir);
|
|
if (nextnextdir == tif->tif_diroff)
|
|
{
|
|
uint32_t m;
|
|
m = 0;
|
|
(void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12,
|
|
SEEK_SET);
|
|
if (!WriteOK(tif, &m, 4))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error writing directory link");
|
|
return (0);
|
|
}
|
|
tif->tif_diroff = 0;
|
|
/* Force a full-traversal to reach the zeroed pointer */
|
|
tif->tif_lastdiroff = 0;
|
|
break;
|
|
}
|
|
nextdir = nextnextdir;
|
|
}
|
|
}
|
|
/* Remove skipped offset from IFD loop directory list. */
|
|
_TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff);
|
|
}
|
|
else
|
|
{
|
|
if (tif->tif_header.big.tiff_diroff == tif->tif_diroff)
|
|
{
|
|
tif->tif_header.big.tiff_diroff = 0;
|
|
tif->tif_diroff = 0;
|
|
|
|
TIFFSeekFile(tif, 8, SEEK_SET);
|
|
if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff), 8))
|
|
{
|
|
TIFFErrorExtR(tif, tif->tif_name, "Error updating TIFF header");
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint64_t nextdir;
|
|
nextdir = tif->tif_header.big.tiff_diroff;
|
|
while (1)
|
|
{
|
|
uint64_t dircount64;
|
|
uint16_t dircount;
|
|
uint64_t nextnextdir;
|
|
|
|
if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount64, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error fetching directory count");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&dircount64);
|
|
if (dircount64 > 0xFFFF)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Sanity check on tag count failed, likely "
|
|
"corrupt TIFF");
|
|
return (0);
|
|
}
|
|
dircount = (uint16_t)dircount64;
|
|
(void)TIFFSeekFile(tif, nextdir + 8 + dircount * 20, SEEK_SET);
|
|
if (!ReadOK(tif, &nextnextdir, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory link");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&nextnextdir);
|
|
if (nextnextdir == tif->tif_diroff)
|
|
{
|
|
uint64_t m;
|
|
m = 0;
|
|
(void)TIFFSeekFile(tif, nextdir + 8 + dircount * 20,
|
|
SEEK_SET);
|
|
if (!WriteOK(tif, &m, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error writing directory link");
|
|
return (0);
|
|
}
|
|
tif->tif_diroff = 0;
|
|
/* Force a full-traversal to reach the zeroed pointer */
|
|
tif->tif_lastdiroff = 0;
|
|
break;
|
|
}
|
|
nextdir = nextnextdir;
|
|
}
|
|
}
|
|
/* Remove skipped offset from IFD loop directory list. */
|
|
_TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff);
|
|
}
|
|
|
|
/*
|
|
* Now use TIFFWriteDirectory() normally.
|
|
*/
|
|
|
|
return TIFFWriteDirectory(tif);
|
|
}
|
|
|
|
static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
|
|
uint64_t *pdiroff)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectorySec";
|
|
uint32_t ndir;
|
|
TIFFDirEntry *dir;
|
|
uint32_t dirsize;
|
|
void *dirmem;
|
|
uint32_t m;
|
|
if (tif->tif_mode == O_RDONLY)
|
|
return (1);
|
|
|
|
_TIFFFillStriles(tif);
|
|
|
|
/*
|
|
* Clear write state so that subsequent images with
|
|
* different characteristics get the right buffers
|
|
* setup for them.
|
|
*/
|
|
if (imagedone)
|
|
{
|
|
if (tif->tif_flags & TIFF_POSTENCODE)
|
|
{
|
|
tif->tif_flags &= ~TIFF_POSTENCODE;
|
|
if (!(*tif->tif_postencode)(tif))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error post-encoding before directory write");
|
|
return (0);
|
|
}
|
|
}
|
|
(*tif->tif_close)(tif); /* shutdown encoder */
|
|
/*
|
|
* Flush any data that might have been written
|
|
* by the compression close+cleanup routines. But
|
|
* be careful not to write stuff if we didn't add data
|
|
* in the previous steps as the "rawcc" data may well be
|
|
* a previously read tile/strip in mixed read/write mode.
|
|
*/
|
|
if (tif->tif_rawcc > 0 && (tif->tif_flags & TIFF_BEENWRITING) != 0)
|
|
{
|
|
if (!TIFFFlushData1(tif))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error flushing data before directory write");
|
|
return (0);
|
|
}
|
|
}
|
|
if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
|
|
{
|
|
_TIFFfreeExt(tif, tif->tif_rawdata);
|
|
tif->tif_rawdata = NULL;
|
|
tif->tif_rawcc = 0;
|
|
tif->tif_rawdatasize = 0;
|
|
tif->tif_rawdataoff = 0;
|
|
tif->tif_rawdataloaded = 0;
|
|
}
|
|
tif->tif_flags &= ~(TIFF_BEENWRITING | TIFF_BUFFERSETUP);
|
|
}
|
|
|
|
if (TIFFFieldSet(tif, FIELD_COMPRESSION) &&
|
|
(tif->tif_dir.td_compression == COMPRESSION_DEFLATE))
|
|
{
|
|
TIFFWarningExtR(tif, module,
|
|
"Creating TIFF with legacy Deflate codec identifier, "
|
|
"COMPRESSION_ADOBE_DEFLATE is more widely supported");
|
|
}
|
|
dir = NULL;
|
|
dirmem = NULL;
|
|
dirsize = 0;
|
|
while (1)
|
|
{
|
|
ndir = 0;
|
|
if (isimage)
|
|
{
|
|
if (TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortLong(tif, &ndir, dir,
|
|
TIFFTAG_IMAGEWIDTH,
|
|
tif->tif_dir.td_imagewidth))
|
|
goto bad;
|
|
if (!TIFFWriteDirectoryTagShortLong(
|
|
tif, &ndir, dir, TIFFTAG_IMAGELENGTH,
|
|
tif->tif_dir.td_imagelength))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_TILEDIMENSIONS))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortLong(tif, &ndir, dir,
|
|
TIFFTAG_TILEWIDTH,
|
|
tif->tif_dir.td_tilewidth))
|
|
goto bad;
|
|
if (!TIFFWriteDirectoryTagShortLong(tif, &ndir, dir,
|
|
TIFFTAG_TILELENGTH,
|
|
tif->tif_dir.td_tilelength))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_RESOLUTION))
|
|
{
|
|
if (!TIFFWriteDirectoryTagRational(tif, &ndir, dir,
|
|
TIFFTAG_XRESOLUTION,
|
|
tif->tif_dir.td_xresolution))
|
|
goto bad;
|
|
if (!TIFFWriteDirectoryTagRational(tif, &ndir, dir,
|
|
TIFFTAG_YRESOLUTION,
|
|
tif->tif_dir.td_yresolution))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_POSITION))
|
|
{
|
|
if (!TIFFWriteDirectoryTagRational(tif, &ndir, dir,
|
|
TIFFTAG_XPOSITION,
|
|
tif->tif_dir.td_xposition))
|
|
goto bad;
|
|
if (!TIFFWriteDirectoryTagRational(tif, &ndir, dir,
|
|
TIFFTAG_YPOSITION,
|
|
tif->tif_dir.td_yposition))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SUBFILETYPE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir,
|
|
TIFFTAG_SUBFILETYPE,
|
|
tif->tif_dir.td_subfiletype))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_BITSPERSAMPLE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortPerSample(
|
|
tif, &ndir, dir, TIFFTAG_BITSPERSAMPLE,
|
|
tif->tif_dir.td_bitspersample))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_COMPRESSION))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_COMPRESSION,
|
|
tif->tif_dir.td_compression))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_PHOTOMETRIC))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_PHOTOMETRIC,
|
|
tif->tif_dir.td_photometric))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_THRESHHOLDING))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_THRESHHOLDING,
|
|
tif->tif_dir.td_threshholding))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_FILLORDER))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_FILLORDER,
|
|
tif->tif_dir.td_fillorder))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_ORIENTATION))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_ORIENTATION,
|
|
tif->tif_dir.td_orientation))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(
|
|
tif, &ndir, dir, TIFFTAG_SAMPLESPERPIXEL,
|
|
tif->tif_dir.td_samplesperpixel))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortLong(
|
|
tif, &ndir, dir, TIFFTAG_ROWSPERSTRIP,
|
|
tif->tif_dir.td_rowsperstrip))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_MINSAMPLEVALUE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortPerSample(
|
|
tif, &ndir, dir, TIFFTAG_MINSAMPLEVALUE,
|
|
tif->tif_dir.td_minsamplevalue))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortPerSample(
|
|
tif, &ndir, dir, TIFFTAG_MAXSAMPLEVALUE,
|
|
tif->tif_dir.td_maxsamplevalue))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_PLANARCONFIG))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_PLANARCONFIG,
|
|
tif->tif_dir.td_planarconfig))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_RESOLUTIONUNIT))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_RESOLUTIONUNIT,
|
|
tif->tif_dir.td_resolutionunit))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_PAGENUMBER))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortArray(
|
|
tif, &ndir, dir, TIFFTAG_PAGENUMBER, 2,
|
|
&tif->tif_dir.td_pagenumber[0]))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS))
|
|
{
|
|
if (!isTiled(tif))
|
|
{
|
|
if (!TIFFWriteDirectoryTagLongLong8Array(
|
|
tif, &ndir, dir, TIFFTAG_STRIPBYTECOUNTS,
|
|
tif->tif_dir.td_nstrips,
|
|
tif->tif_dir.td_stripbytecount_p))
|
|
goto bad;
|
|
}
|
|
else
|
|
{
|
|
if (!TIFFWriteDirectoryTagLongLong8Array(
|
|
tif, &ndir, dir, TIFFTAG_TILEBYTECOUNTS,
|
|
tif->tif_dir.td_nstrips,
|
|
tif->tif_dir.td_stripbytecount_p))
|
|
goto bad;
|
|
}
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_STRIPOFFSETS))
|
|
{
|
|
if (!isTiled(tif))
|
|
{
|
|
/* td_stripoffset_p might be NULL in an odd OJPEG case. See
|
|
* tif_dirread.c around line 3634.
|
|
* XXX: OJPEG hack.
|
|
* If a) compression is OJPEG, b) it's not a tiled TIFF,
|
|
* and c) the number of strips is 1,
|
|
* then we tolerate the absence of stripoffsets tag,
|
|
* because, presumably, all required data is in the
|
|
* JpegInterchangeFormat stream.
|
|
* We can get here when using tiffset on such a file.
|
|
* See http://bugzilla.maptools.org/show_bug.cgi?id=2500
|
|
*/
|
|
if (tif->tif_dir.td_stripoffset_p != NULL &&
|
|
!TIFFWriteDirectoryTagLongLong8Array(
|
|
tif, &ndir, dir, TIFFTAG_STRIPOFFSETS,
|
|
tif->tif_dir.td_nstrips,
|
|
tif->tif_dir.td_stripoffset_p))
|
|
goto bad;
|
|
}
|
|
else
|
|
{
|
|
if (!TIFFWriteDirectoryTagLongLong8Array(
|
|
tif, &ndir, dir, TIFFTAG_TILEOFFSETS,
|
|
tif->tif_dir.td_nstrips,
|
|
tif->tif_dir.td_stripoffset_p))
|
|
goto bad;
|
|
}
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_COLORMAP))
|
|
{
|
|
if (!TIFFWriteDirectoryTagColormap(tif, &ndir, dir))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_EXTRASAMPLES))
|
|
{
|
|
if (tif->tif_dir.td_extrasamples)
|
|
{
|
|
uint16_t na;
|
|
uint16_t *nb;
|
|
TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &na, &nb);
|
|
if (!TIFFWriteDirectoryTagShortArray(
|
|
tif, &ndir, dir, TIFFTAG_EXTRASAMPLES, na, nb))
|
|
goto bad;
|
|
}
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SAMPLEFORMAT))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortPerSample(
|
|
tif, &ndir, dir, TIFFTAG_SAMPLEFORMAT,
|
|
tif->tif_dir.td_sampleformat))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SMINSAMPLEVALUE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagSampleformatArray(
|
|
tif, &ndir, dir, TIFFTAG_SMINSAMPLEVALUE,
|
|
tif->tif_dir.td_samplesperpixel,
|
|
tif->tif_dir.td_sminsamplevalue))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SMAXSAMPLEVALUE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagSampleformatArray(
|
|
tif, &ndir, dir, TIFFTAG_SMAXSAMPLEVALUE,
|
|
tif->tif_dir.td_samplesperpixel,
|
|
tif->tif_dir.td_smaxsamplevalue))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_IMAGEDEPTH))
|
|
{
|
|
if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir,
|
|
TIFFTAG_IMAGEDEPTH,
|
|
tif->tif_dir.td_imagedepth))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_TILEDEPTH))
|
|
{
|
|
if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir,
|
|
TIFFTAG_TILEDEPTH,
|
|
tif->tif_dir.td_tiledepth))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_HALFTONEHINTS))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortArray(
|
|
tif, &ndir, dir, TIFFTAG_HALFTONEHINTS, 2,
|
|
&tif->tif_dir.td_halftonehints[0]))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_YCBCRSUBSAMPLING))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShortArray(
|
|
tif, &ndir, dir, TIFFTAG_YCBCRSUBSAMPLING, 2,
|
|
&tif->tif_dir.td_ycbcrsubsampling[0]))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_YCBCRPOSITIONING))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(
|
|
tif, &ndir, dir, TIFFTAG_YCBCRPOSITIONING,
|
|
tif->tif_dir.td_ycbcrpositioning))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_REFBLACKWHITE))
|
|
{
|
|
if (!TIFFWriteDirectoryTagRationalArray(
|
|
tif, &ndir, dir, TIFFTAG_REFERENCEBLACKWHITE, 6,
|
|
tif->tif_dir.td_refblackwhite))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_TRANSFERFUNCTION))
|
|
{
|
|
if (!TIFFWriteDirectoryTagTransferfunction(tif, &ndir, dir))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_INKNAMES))
|
|
{
|
|
if (!TIFFWriteDirectoryTagAscii(
|
|
tif, &ndir, dir, TIFFTAG_INKNAMES,
|
|
tif->tif_dir.td_inknameslen, tif->tif_dir.td_inknames))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS))
|
|
{
|
|
if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir,
|
|
TIFFTAG_NUMBEROFINKS,
|
|
tif->tif_dir.td_numberofinks))
|
|
goto bad;
|
|
}
|
|
if (TIFFFieldSet(tif, FIELD_SUBIFD))
|
|
{
|
|
if (!TIFFWriteDirectoryTagSubifd(tif, &ndir, dir))
|
|
goto bad;
|
|
}
|
|
{
|
|
uint32_t n;
|
|
for (n = 0; n < tif->tif_nfields; n++)
|
|
{
|
|
const TIFFField *o;
|
|
o = tif->tif_fields[n];
|
|
if ((o->field_bit >= FIELD_CODEC) &&
|
|
(TIFFFieldSet(tif, o->field_bit)))
|
|
{
|
|
switch (o->get_field_type)
|
|
{
|
|
case TIFF_SETGET_ASCII:
|
|
{
|
|
uint32_t pa;
|
|
char *pb;
|
|
assert(o->field_type == TIFF_ASCII);
|
|
assert(o->field_readcount == TIFF_VARIABLE);
|
|
assert(o->field_passcount == 0);
|
|
TIFFGetField(tif, o->field_tag, &pb);
|
|
pa = (uint32_t)(strlen(pb));
|
|
if (!TIFFWriteDirectoryTagAscii(
|
|
tif, &ndir, dir, (uint16_t)o->field_tag,
|
|
pa, pb))
|
|
goto bad;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_UINT16:
|
|
{
|
|
uint16_t p;
|
|
assert(o->field_type == TIFF_SHORT);
|
|
assert(o->field_readcount == 1);
|
|
assert(o->field_passcount == 0);
|
|
TIFFGetField(tif, o->field_tag, &p);
|
|
if (!TIFFWriteDirectoryTagShort(
|
|
tif, &ndir, dir, (uint16_t)o->field_tag,
|
|
p))
|
|
goto bad;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_UINT32:
|
|
{
|
|
uint32_t p;
|
|
assert(o->field_type == TIFF_LONG);
|
|
assert(o->field_readcount == 1);
|
|
assert(o->field_passcount == 0);
|
|
TIFFGetField(tif, o->field_tag, &p);
|
|
if (!TIFFWriteDirectoryTagLong(
|
|
tif, &ndir, dir, (uint16_t)o->field_tag,
|
|
p))
|
|
goto bad;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_C32_UINT8:
|
|
{
|
|
uint32_t pa;
|
|
void *pb;
|
|
assert(o->field_type == TIFF_UNDEFINED);
|
|
assert(o->field_readcount == TIFF_VARIABLE2);
|
|
assert(o->field_passcount == 1);
|
|
TIFFGetField(tif, o->field_tag, &pa, &pb);
|
|
if (!TIFFWriteDirectoryTagUndefinedArray(
|
|
tif, &ndir, dir, (uint16_t)o->field_tag,
|
|
pa, pb))
|
|
goto bad;
|
|
}
|
|
break;
|
|
default:
|
|
TIFFErrorExtR(
|
|
tif, module,
|
|
"Cannot write tag %" PRIu32 " (%s)",
|
|
TIFFFieldTag(o),
|
|
o->field_name ? o->field_name : "unknown");
|
|
goto bad;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (m = 0; m < (uint32_t)(tif->tif_dir.td_customValueCount); m++)
|
|
{
|
|
uint16_t tag =
|
|
(uint16_t)tif->tif_dir.td_customValues[m].info->field_tag;
|
|
uint32_t count = tif->tif_dir.td_customValues[m].count;
|
|
switch (tif->tif_dir.td_customValues[m].info->field_type)
|
|
{
|
|
case TIFF_ASCII:
|
|
if (!TIFFWriteDirectoryTagAscii(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_UNDEFINED:
|
|
if (!TIFFWriteDirectoryTagUndefinedArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_BYTE:
|
|
if (!TIFFWriteDirectoryTagByteArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_SBYTE:
|
|
if (!TIFFWriteDirectoryTagSbyteArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_SHORT:
|
|
if (!TIFFWriteDirectoryTagShortArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_SSHORT:
|
|
if (!TIFFWriteDirectoryTagSshortArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_LONG:
|
|
if (!TIFFWriteDirectoryTagLongArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_SLONG:
|
|
if (!TIFFWriteDirectoryTagSlongArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_LONG8:
|
|
if (!TIFFWriteDirectoryTagLong8Array(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_SLONG8:
|
|
if (!TIFFWriteDirectoryTagSlong8Array(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_RATIONAL:
|
|
{
|
|
/*-- Rational2Double: For Rationals evaluate
|
|
* "set_field_type" to determine internal storage size. */
|
|
int tv_size;
|
|
tv_size = TIFFFieldSetGetSize(
|
|
tif->tif_dir.td_customValues[m].info);
|
|
if (tv_size == 8)
|
|
{
|
|
if (!TIFFWriteDirectoryTagRationalDoubleArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
}
|
|
else
|
|
{
|
|
/*-- default should be tv_size == 4 */
|
|
if (!TIFFWriteDirectoryTagRationalArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
/*-- ToDo: After Testing, this should be removed and
|
|
* tv_size==4 should be set as default. */
|
|
if (tv_size != 4)
|
|
{
|
|
TIFFErrorExtR(tif,
|
|
"TIFFLib: _TIFFWriteDirectorySec()",
|
|
"Rational2Double: .set_field_type is "
|
|
"not 4 but %d",
|
|
tv_size);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case TIFF_SRATIONAL:
|
|
{
|
|
/*-- Rational2Double: For Rationals evaluate
|
|
* "set_field_type" to determine internal storage size. */
|
|
int tv_size;
|
|
tv_size = TIFFFieldSetGetSize(
|
|
tif->tif_dir.td_customValues[m].info);
|
|
if (tv_size == 8)
|
|
{
|
|
if (!TIFFWriteDirectoryTagSrationalDoubleArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
}
|
|
else
|
|
{
|
|
/*-- default should be tv_size == 4 */
|
|
if (!TIFFWriteDirectoryTagSrationalArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
/*-- ToDo: After Testing, this should be removed and
|
|
* tv_size==4 should be set as default. */
|
|
if (tv_size != 4)
|
|
{
|
|
TIFFErrorExtR(tif,
|
|
"TIFFLib: _TIFFWriteDirectorySec()",
|
|
"Rational2Double: .set_field_type is "
|
|
"not 4 but %d",
|
|
tv_size);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case TIFF_FLOAT:
|
|
if (!TIFFWriteDirectoryTagFloatArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_DOUBLE:
|
|
if (!TIFFWriteDirectoryTagDoubleArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_IFD:
|
|
if (!TIFFWriteDirectoryTagIfdArray(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
case TIFF_IFD8:
|
|
if (!TIFFWriteDirectoryTagIfdIfd8Array(
|
|
tif, &ndir, dir, tag, count,
|
|
tif->tif_dir.td_customValues[m].value))
|
|
goto bad;
|
|
break;
|
|
default:
|
|
assert(0); /* we should never get here */
|
|
break;
|
|
}
|
|
}
|
|
if (dir != NULL)
|
|
break;
|
|
dir = _TIFFmallocExt(tif, ndir * sizeof(TIFFDirEntry));
|
|
if (dir == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
goto bad;
|
|
}
|
|
if (isimage)
|
|
{
|
|
if ((tif->tif_diroff == 0) && (!TIFFLinkDirectory(tif)))
|
|
goto bad;
|
|
}
|
|
else
|
|
tif->tif_diroff =
|
|
(TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1));
|
|
if (pdiroff != NULL)
|
|
*pdiroff = tif->tif_diroff;
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
dirsize = 2 + ndir * 12 + 4;
|
|
else
|
|
dirsize = 8 + ndir * 20 + 8;
|
|
tif->tif_dataoff = tif->tif_diroff + dirsize;
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
tif->tif_dataoff = (uint32_t)tif->tif_dataoff;
|
|
if ((tif->tif_dataoff < tif->tif_diroff) ||
|
|
(tif->tif_dataoff < (uint64_t)dirsize))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded");
|
|
goto bad;
|
|
}
|
|
if (tif->tif_dataoff & 1)
|
|
tif->tif_dataoff++;
|
|
if (isimage)
|
|
{
|
|
if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER)
|
|
tif->tif_curdir = 0;
|
|
else
|
|
tif->tif_curdir++;
|
|
}
|
|
}
|
|
if (isimage)
|
|
{
|
|
if (TIFFFieldSet(tif, FIELD_SUBIFD) && (tif->tif_subifdoff == 0))
|
|
{
|
|
uint32_t na;
|
|
TIFFDirEntry *nb;
|
|
for (na = 0, nb = dir;; na++, nb++)
|
|
{
|
|
if (na == ndir)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Cannot find SubIFD tag");
|
|
goto bad;
|
|
}
|
|
if (nb->tdir_tag == TIFFTAG_SUBIFD)
|
|
break;
|
|
}
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
tif->tif_subifdoff = tif->tif_diroff + 2 + na * 12 + 8;
|
|
else
|
|
tif->tif_subifdoff = tif->tif_diroff + 8 + na * 20 + 12;
|
|
}
|
|
}
|
|
dirmem = _TIFFmallocExt(tif, dirsize);
|
|
if (dirmem == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
goto bad;
|
|
}
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint8_t *n;
|
|
uint32_t nTmp;
|
|
TIFFDirEntry *o;
|
|
n = dirmem;
|
|
*(uint16_t *)n = (uint16_t)ndir;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)n);
|
|
n += 2;
|
|
o = dir;
|
|
for (m = 0; m < ndir; m++)
|
|
{
|
|
*(uint16_t *)n = o->tdir_tag;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)n);
|
|
n += 2;
|
|
*(uint16_t *)n = o->tdir_type;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)n);
|
|
n += 2;
|
|
nTmp = (uint32_t)o->tdir_count;
|
|
_TIFFmemcpy(n, &nTmp, 4);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong((uint32_t *)n);
|
|
n += 4;
|
|
/* This is correct. The data has been */
|
|
/* swabbed previously in TIFFWriteDirectoryTagData */
|
|
_TIFFmemcpy(n, &o->tdir_offset, 4);
|
|
n += 4;
|
|
o++;
|
|
}
|
|
nTmp = (uint32_t)tif->tif_nextdiroff;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&nTmp);
|
|
_TIFFmemcpy(n, &nTmp, 4);
|
|
}
|
|
else
|
|
{
|
|
uint8_t *n;
|
|
TIFFDirEntry *o;
|
|
n = dirmem;
|
|
*(uint64_t *)n = ndir;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8((uint64_t *)n);
|
|
n += 8;
|
|
o = dir;
|
|
for (m = 0; m < ndir; m++)
|
|
{
|
|
*(uint16_t *)n = o->tdir_tag;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)n);
|
|
n += 2;
|
|
*(uint16_t *)n = o->tdir_type;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)n);
|
|
n += 2;
|
|
_TIFFmemcpy(n, &o->tdir_count, 8);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8((uint64_t *)n);
|
|
n += 8;
|
|
_TIFFmemcpy(n, &o->tdir_offset, 8);
|
|
n += 8;
|
|
o++;
|
|
}
|
|
_TIFFmemcpy(n, &tif->tif_nextdiroff, 8);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8((uint64_t *)n);
|
|
}
|
|
_TIFFfreeExt(tif, dir);
|
|
dir = NULL;
|
|
if (!SeekOK(tif, tif->tif_diroff))
|
|
{
|
|
TIFFErrorExtR(tif, module, "IO error writing directory");
|
|
goto bad;
|
|
}
|
|
if (!WriteOK(tif, dirmem, (tmsize_t)dirsize))
|
|
{
|
|
TIFFErrorExtR(tif, module, "IO error writing directory");
|
|
goto bad;
|
|
}
|
|
_TIFFfreeExt(tif, dirmem);
|
|
if (imagedone)
|
|
{
|
|
TIFFFreeDirectory(tif);
|
|
tif->tif_flags &= ~TIFF_DIRTYDIRECT;
|
|
tif->tif_flags &= ~TIFF_DIRTYSTRIP;
|
|
(*tif->tif_cleanup)(tif);
|
|
/*
|
|
* Reset directory-related state for subsequent
|
|
* directories.
|
|
*/
|
|
TIFFCreateDirectory(tif);
|
|
}
|
|
return (1);
|
|
bad:
|
|
if (dir != NULL)
|
|
_TIFFfreeExt(tif, dir);
|
|
if (dirmem != NULL)
|
|
_TIFFfreeExt(tif, dirmem);
|
|
return (0);
|
|
}
|
|
|
|
static int8_t TIFFClampDoubleToInt8(double val)
|
|
{
|
|
if (val > 127)
|
|
return 127;
|
|
if (val < -128 || val != val)
|
|
return -128;
|
|
return (int8_t)val;
|
|
}
|
|
|
|
static int16_t TIFFClampDoubleToInt16(double val)
|
|
{
|
|
if (val > 32767)
|
|
return 32767;
|
|
if (val < -32768 || val != val)
|
|
return -32768;
|
|
return (int16_t)val;
|
|
}
|
|
|
|
static int32_t TIFFClampDoubleToInt32(double val)
|
|
{
|
|
if (val > 0x7FFFFFFF)
|
|
return 0x7FFFFFFF;
|
|
if (val < -0x7FFFFFFF - 1 || val != val)
|
|
return -0x7FFFFFFF - 1;
|
|
return (int32_t)val;
|
|
}
|
|
|
|
static uint8_t TIFFClampDoubleToUInt8(double val)
|
|
{
|
|
if (val < 0)
|
|
return 0;
|
|
if (val > 255 || val != val)
|
|
return 255;
|
|
return (uint8_t)val;
|
|
}
|
|
|
|
static uint16_t TIFFClampDoubleToUInt16(double val)
|
|
{
|
|
if (val < 0)
|
|
return 0;
|
|
if (val > 65535 || val != val)
|
|
return 65535;
|
|
return (uint16_t)val;
|
|
}
|
|
|
|
static uint32_t TIFFClampDoubleToUInt32(double val)
|
|
{
|
|
if (val < 0)
|
|
return 0;
|
|
if (val > 0xFFFFFFFFU || val != val)
|
|
return 0xFFFFFFFFU;
|
|
return (uint32_t)val;
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSampleformatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
double *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagSampleformatArray";
|
|
void *conv;
|
|
uint32_t i;
|
|
int ok;
|
|
conv = _TIFFmallocExt(tif, count * sizeof(double));
|
|
if (conv == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
switch (tif->tif_dir.td_sampleformat)
|
|
{
|
|
case SAMPLEFORMAT_IEEEFP:
|
|
if (tif->tif_dir.td_bitspersample <= 32)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((float *)conv)[i] = _TIFFClampDoubleToFloat(value[i]);
|
|
ok = TIFFWriteDirectoryTagFloatArray(tif, ndir, dir, tag, count,
|
|
(float *)conv);
|
|
}
|
|
else
|
|
{
|
|
ok = TIFFWriteDirectoryTagDoubleArray(tif, ndir, dir, tag,
|
|
count, value);
|
|
}
|
|
break;
|
|
case SAMPLEFORMAT_INT:
|
|
if (tif->tif_dir.td_bitspersample <= 8)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((int8_t *)conv)[i] = TIFFClampDoubleToInt8(value[i]);
|
|
ok = TIFFWriteDirectoryTagSbyteArray(tif, ndir, dir, tag, count,
|
|
(int8_t *)conv);
|
|
}
|
|
else if (tif->tif_dir.td_bitspersample <= 16)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((int16_t *)conv)[i] = TIFFClampDoubleToInt16(value[i]);
|
|
ok = TIFFWriteDirectoryTagSshortArray(tif, ndir, dir, tag,
|
|
count, (int16_t *)conv);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((int32_t *)conv)[i] = TIFFClampDoubleToInt32(value[i]);
|
|
ok = TIFFWriteDirectoryTagSlongArray(tif, ndir, dir, tag, count,
|
|
(int32_t *)conv);
|
|
}
|
|
break;
|
|
case SAMPLEFORMAT_UINT:
|
|
if (tif->tif_dir.td_bitspersample <= 8)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((uint8_t *)conv)[i] = TIFFClampDoubleToUInt8(value[i]);
|
|
ok = TIFFWriteDirectoryTagByteArray(tif, ndir, dir, tag, count,
|
|
(uint8_t *)conv);
|
|
}
|
|
else if (tif->tif_dir.td_bitspersample <= 16)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((uint16_t *)conv)[i] = TIFFClampDoubleToUInt16(value[i]);
|
|
ok = TIFFWriteDirectoryTagShortArray(tif, ndir, dir, tag, count,
|
|
(uint16_t *)conv);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
((uint32_t *)conv)[i] = TIFFClampDoubleToUInt32(value[i]);
|
|
ok = TIFFWriteDirectoryTagLongArray(tif, ndir, dir, tag, count,
|
|
(uint32_t *)conv);
|
|
}
|
|
break;
|
|
default:
|
|
ok = 0;
|
|
}
|
|
|
|
_TIFFfreeExt(tif, conv);
|
|
return (ok);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagAscii(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, char *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (
|
|
TIFFWriteDirectoryTagCheckedAscii(tif, ndir, dir, tag, count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagUndefinedArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint8_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedUndefinedArray(tif, ndir, dir, tag,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagByteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint8_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedByteArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int8_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedSbyteArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagShort(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagShortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint16_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagShortPerSample(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagShortPerSample";
|
|
uint16_t *m;
|
|
uint16_t *na;
|
|
uint16_t nb;
|
|
int o;
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
m = _TIFFmallocExt(tif, tif->tif_dir.td_samplesperpixel * sizeof(uint16_t));
|
|
if (m == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
for (na = m, nb = 0; nb < tif->tif_dir.td_samplesperpixel; na++, nb++)
|
|
*na = value;
|
|
o = TIFFWriteDirectoryTagCheckedShortArray(
|
|
tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, m);
|
|
_TIFFfreeExt(tif, m);
|
|
return (o);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int16_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedSshortArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagLongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint32_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSlongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int32_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TIFFWriteDirectoryTagLong8Array() */
|
|
/* */
|
|
/* Write either Long8 or Long array depending on file type. */
|
|
/************************************************************************/
|
|
static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagLong8Array";
|
|
uint64_t *ma;
|
|
uint32_t mb;
|
|
uint32_t *p;
|
|
uint32_t *q;
|
|
int o;
|
|
|
|
/* is this just a counting pass? */
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
|
|
/* We always write Long8 for BigTIFF, no checking needed. */
|
|
if (tif->tif_flags & TIFF_BIGTIFF)
|
|
return (TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag,
|
|
count, value));
|
|
|
|
/*
|
|
** For classic tiff we want to verify everything is in range for long
|
|
** and convert to long format.
|
|
*/
|
|
p = _TIFFmallocExt(tif, count * sizeof(uint32_t));
|
|
if (p == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
|
|
{
|
|
if (*ma > 0xFFFFFFFF)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write unsigned long value %" PRIu64
|
|
" larger than 0xFFFFFFFF for tag %d in Classic TIFF "
|
|
"file. TIFF file writing aborted",
|
|
*ma, tag);
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
*q = (uint32_t)(*ma);
|
|
}
|
|
|
|
o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, p);
|
|
_TIFFfreeExt(tif, p);
|
|
|
|
return (o);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TIFFWriteDirectoryTagSlong8Array() */
|
|
/* */
|
|
/* Write either SLong8 or SLong array depending on file type. */
|
|
/************************************************************************/
|
|
static int TIFFWriteDirectoryTagSlong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, int64_t *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagSlong8Array";
|
|
int64_t *ma;
|
|
uint32_t mb;
|
|
int32_t *p;
|
|
int32_t *q;
|
|
int o;
|
|
|
|
/* is this just a counting pass? */
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
/* We always write SLong8 for BigTIFF, no checking needed. */
|
|
if (tif->tif_flags & TIFF_BIGTIFF)
|
|
return (TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag,
|
|
count, value));
|
|
|
|
/*
|
|
** For classic tiff we want to verify everything is in range for signed-long
|
|
** and convert to signed-long format.
|
|
*/
|
|
p = _TIFFmallocExt(tif, count * sizeof(uint32_t));
|
|
if (p == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
|
|
{
|
|
if (*ma > (2147483647))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write signed long value %" PRIi64
|
|
" larger than 0x7FFFFFFF (2147483647) for tag %d in "
|
|
"Classic TIFF file. TIFF writing to file aborted",
|
|
*ma, tag);
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
else if (*ma < (-2147483647 - 1))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write signed long value %" PRIi64
|
|
" smaller than 0x80000000 (-2147483648) for tag %d "
|
|
"in Classic TIFF file. TIFF writing to file aborted",
|
|
*ma, tag);
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
*q = (int32_t)(*ma);
|
|
}
|
|
|
|
o = TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, p);
|
|
_TIFFfreeExt(tif, p);
|
|
|
|
return (o);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagRational(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
double value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedRational(tif, ndir, dir, tag, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagRationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedRationalArray(tif, ndir, dir, tag,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSrationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedSrationalArray(tif, ndir, dir, tag,
|
|
count, value));
|
|
}
|
|
|
|
/*-- Rational2Double: additional write functions */
|
|
static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
double *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif, ndir, dir, tag,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
double *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedSrationalDoubleArray(
|
|
tif, ndir, dir, tag, count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagFloatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, float *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedFloatArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, double *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedDoubleArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagIfdArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint32_t *value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
return (TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count,
|
|
value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagShortLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value)
|
|
{
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
if (value <= 0xFFFF)
|
|
return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag,
|
|
(uint16_t)value));
|
|
else
|
|
return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value));
|
|
}
|
|
|
|
static int _WriteAsType(TIFF *tif, uint64_t strile_size,
|
|
uint64_t uncompressed_threshold)
|
|
{
|
|
const uint16_t compression = tif->tif_dir.td_compression;
|
|
if (compression == COMPRESSION_NONE)
|
|
{
|
|
return strile_size > uncompressed_threshold;
|
|
}
|
|
else if (compression == COMPRESSION_JPEG ||
|
|
compression == COMPRESSION_LZW ||
|
|
compression == COMPRESSION_ADOBE_DEFLATE ||
|
|
compression == COMPRESSION_DEFLATE ||
|
|
compression == COMPRESSION_LZMA ||
|
|
compression == COMPRESSION_LERC ||
|
|
compression == COMPRESSION_ZSTD ||
|
|
compression == COMPRESSION_WEBP || compression == COMPRESSION_JXL)
|
|
{
|
|
/* For a few select compression types, we assume that in the worst */
|
|
/* case the compressed size will be 10 times the uncompressed size */
|
|
/* This is overly pessismistic ! */
|
|
return strile_size >= uncompressed_threshold / 10;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int WriteAsLong8(TIFF *tif, uint64_t strile_size)
|
|
{
|
|
return _WriteAsType(tif, strile_size, 0xFFFFFFFFU);
|
|
}
|
|
|
|
static int WriteAsLong4(TIFF *tif, uint64_t strile_size)
|
|
{
|
|
return _WriteAsType(tif, strile_size, 0xFFFFU);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TIFFWriteDirectoryTagLongLong8Array() */
|
|
/* */
|
|
/* Write out LONG8 array and write a SHORT/LONG/LONG8 depending */
|
|
/* on strile size and Classic/BigTIFF mode. */
|
|
/************************************************************************/
|
|
|
|
static int TIFFWriteDirectoryTagLongLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagLongLong8Array";
|
|
int o;
|
|
int write_aslong4;
|
|
|
|
/* is this just a counting pass? */
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
|
|
if (tif->tif_dir.td_deferstrilearraywriting)
|
|
{
|
|
return TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_NOTYPE, 0, 0,
|
|
NULL);
|
|
}
|
|
|
|
if (tif->tif_flags & TIFF_BIGTIFF)
|
|
{
|
|
int write_aslong8 = 1;
|
|
/* In the case of ByteCounts array, we may be able to write them on */
|
|
/* LONG if the strip/tilesize is not too big. */
|
|
/* Also do that for count > 1 in the case someone would want to create
|
|
*/
|
|
/* a single-strip file with a growing height, in which case using */
|
|
/* LONG8 will be safer. */
|
|
if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS)
|
|
{
|
|
write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif));
|
|
}
|
|
else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS)
|
|
{
|
|
write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif));
|
|
}
|
|
if (write_aslong8)
|
|
{
|
|
return TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag,
|
|
count, value);
|
|
}
|
|
}
|
|
|
|
write_aslong4 = 1;
|
|
if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS)
|
|
{
|
|
write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif));
|
|
}
|
|
else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS)
|
|
{
|
|
write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif));
|
|
}
|
|
if (write_aslong4)
|
|
{
|
|
/*
|
|
** For classic tiff we want to verify everything is in range for LONG
|
|
** and convert to long format.
|
|
*/
|
|
|
|
uint32_t *p = _TIFFmallocExt(tif, count * sizeof(uint32_t));
|
|
uint32_t *q;
|
|
uint64_t *ma;
|
|
uint32_t mb;
|
|
|
|
if (p == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
|
|
{
|
|
if (*ma > 0xFFFFFFFF)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write value larger than 0xFFFFFFFF "
|
|
"in LONG array.");
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
*q = (uint32_t)(*ma);
|
|
}
|
|
|
|
o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count,
|
|
p);
|
|
_TIFFfreeExt(tif, p);
|
|
}
|
|
else
|
|
{
|
|
uint16_t *p = _TIFFmallocExt(tif, count * sizeof(uint16_t));
|
|
uint16_t *q;
|
|
uint64_t *ma;
|
|
uint32_t mb;
|
|
|
|
if (p == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
|
|
{
|
|
if (*ma > 0xFFFF)
|
|
{
|
|
/* Should not happen normally given the check we did before */
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write value larger than 0xFFFF in "
|
|
"SHORT array.");
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
*q = (uint16_t)(*ma);
|
|
}
|
|
|
|
o = TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count,
|
|
p);
|
|
_TIFFfreeExt(tif, p);
|
|
}
|
|
|
|
return (o);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TIFFWriteDirectoryTagIfdIfd8Array() */
|
|
/* */
|
|
/* Write either IFD8 or IFD array depending on file type. */
|
|
/************************************************************************/
|
|
|
|
static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint64_t *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array";
|
|
uint64_t *ma;
|
|
uint32_t mb;
|
|
uint32_t *p;
|
|
uint32_t *q;
|
|
int o;
|
|
|
|
/* is this just a counting pass? */
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
|
|
/* We always write IFD8 for BigTIFF, no checking needed. */
|
|
if (tif->tif_flags & TIFF_BIGTIFF)
|
|
return TIFFWriteDirectoryTagCheckedIfd8Array(tif, ndir, dir, tag, count,
|
|
value);
|
|
|
|
/*
|
|
** For classic tiff we want to verify everything is in range for IFD
|
|
** and convert to long format.
|
|
*/
|
|
|
|
p = _TIFFmallocExt(tif, count * sizeof(uint32_t));
|
|
if (p == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
|
|
for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++)
|
|
{
|
|
if (*ma > 0xFFFFFFFF)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Attempt to write value larger than 0xFFFFFFFF in "
|
|
"Classic TIFF file.");
|
|
_TIFFfreeExt(tif, p);
|
|
return (0);
|
|
}
|
|
*q = (uint32_t)(*ma);
|
|
}
|
|
|
|
o = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count, p);
|
|
_TIFFfreeExt(tif, p);
|
|
|
|
return (o);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagColormap";
|
|
uint32_t m;
|
|
uint16_t *n;
|
|
int o;
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
m = (1 << tif->tif_dir.td_bitspersample);
|
|
n = _TIFFmallocExt(tif, 3 * m * sizeof(uint16_t));
|
|
if (n == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
_TIFFmemcpy(&n[0], tif->tif_dir.td_colormap[0], m * sizeof(uint16_t));
|
|
_TIFFmemcpy(&n[m], tif->tif_dir.td_colormap[1], m * sizeof(uint16_t));
|
|
_TIFFmemcpy(&n[2 * m], tif->tif_dir.td_colormap[2], m * sizeof(uint16_t));
|
|
o = TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, TIFFTAG_COLORMAP,
|
|
3 * m, n);
|
|
_TIFFfreeExt(tif, n);
|
|
return (o);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagTransferfunction(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagTransferfunction";
|
|
uint32_t m;
|
|
uint16_t n;
|
|
uint16_t *o;
|
|
int p;
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
/* TIFFTAG_TRANSFERFUNCTION expects (1 or 3) pointer to arrays with
|
|
* (1 << BitsPerSample) * uint16_t values.
|
|
*/
|
|
m = (1 << tif->tif_dir.td_bitspersample);
|
|
/* clang-format off */
|
|
n = (tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples) > 1 ? 3 : 1;
|
|
/* clang-format on */
|
|
|
|
/* Check for proper number of transferfunctions */
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
if (tif->tif_dir.td_transferfunction[i] == NULL)
|
|
{
|
|
TIFFWarningExtR(
|
|
tif, module,
|
|
"Too few TransferFunctions provided. Tag not written to file");
|
|
return (1); /* Not an error; only tag is not written. */
|
|
}
|
|
}
|
|
/*
|
|
* Check if the table can be written as a single column,
|
|
* or if it must be written as 3 columns. Note that we
|
|
* write a 3-column tag if there are 2 samples/pixel and
|
|
* a single column of data won't suffice--hmm.
|
|
*/
|
|
if (n == 3)
|
|
{
|
|
if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],
|
|
tif->tif_dir.td_transferfunction[2],
|
|
m * sizeof(uint16_t)) &&
|
|
!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],
|
|
tif->tif_dir.td_transferfunction[1],
|
|
m * sizeof(uint16_t)))
|
|
n = 1;
|
|
}
|
|
o = _TIFFmallocExt(tif, n * m * sizeof(uint16_t));
|
|
if (o == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
_TIFFmemcpy(&o[0], tif->tif_dir.td_transferfunction[0],
|
|
m * sizeof(uint16_t));
|
|
if (n > 1)
|
|
_TIFFmemcpy(&o[m], tif->tif_dir.td_transferfunction[1],
|
|
m * sizeof(uint16_t));
|
|
if (n > 2)
|
|
_TIFFmemcpy(&o[2 * m], tif->tif_dir.td_transferfunction[2],
|
|
m * sizeof(uint16_t));
|
|
p = TIFFWriteDirectoryTagCheckedShortArray(
|
|
tif, ndir, dir, TIFFTAG_TRANSFERFUNCTION, n * m, o);
|
|
_TIFFfreeExt(tif, o);
|
|
return (p);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagSubifd(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagSubifd";
|
|
uint64_t m;
|
|
int n;
|
|
if (tif->tif_dir.td_nsubifd == 0)
|
|
return (1);
|
|
if (dir == NULL)
|
|
{
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
m = tif->tif_dataoff;
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t *o;
|
|
uint64_t *pa;
|
|
uint32_t *pb;
|
|
uint16_t p;
|
|
o = _TIFFmallocExt(tif, tif->tif_dir.td_nsubifd * sizeof(uint32_t));
|
|
if (o == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
pa = tif->tif_dir.td_subifd;
|
|
pb = o;
|
|
for (p = 0; p < tif->tif_dir.td_nsubifd; p++)
|
|
{
|
|
assert(pa != 0);
|
|
|
|
/* Could happen if an classicTIFF has a SubIFD of type LONG8 (which
|
|
* is illegal) */
|
|
if (*pa > 0xFFFFFFFFUL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Illegal value for SubIFD tag");
|
|
_TIFFfreeExt(tif, o);
|
|
return (0);
|
|
}
|
|
*pb++ = (uint32_t)(*pa++);
|
|
}
|
|
n = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, TIFFTAG_SUBIFD,
|
|
tif->tif_dir.td_nsubifd, o);
|
|
_TIFFfreeExt(tif, o);
|
|
}
|
|
else
|
|
n = TIFFWriteDirectoryTagCheckedIfd8Array(
|
|
tif, ndir, dir, TIFFTAG_SUBIFD, tif->tif_dir.td_nsubifd,
|
|
tif->tif_dir.td_subifd);
|
|
if (!n)
|
|
return (0);
|
|
/*
|
|
* Total hack: if this directory includes a SubIFD
|
|
* tag then force the next <n> directories to be
|
|
* written as ``sub directories'' of this one. This
|
|
* is used to write things like thumbnails and
|
|
* image masks that one wants to keep out of the
|
|
* normal directory linkage access mechanism.
|
|
*/
|
|
tif->tif_flags |= TIFF_INSUBIFD;
|
|
tif->tif_nsubifd = tif->tif_dir.td_nsubifd;
|
|
if (tif->tif_dir.td_nsubifd == 1)
|
|
tif->tif_subifdoff = 0;
|
|
else
|
|
tif->tif_subifdoff = m;
|
|
return (1);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedAscii(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, char *value)
|
|
{
|
|
assert(sizeof(char) == 1);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_ASCII, count,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
uint8_t *value)
|
|
{
|
|
assert(sizeof(uint8_t) == 1);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_UNDEFINED,
|
|
count, count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedByteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint8_t *value)
|
|
{
|
|
assert(sizeof(uint8_t) == 1);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_BYTE, count,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int8_t *value)
|
|
{
|
|
assert(sizeof(int8_t) == 1);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SBYTE, count,
|
|
count, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedShort(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t value)
|
|
{
|
|
uint16_t m;
|
|
assert(sizeof(uint16_t) == 2);
|
|
m = value;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&m);
|
|
return (
|
|
TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, 1, 2, &m));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedShortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint16_t *value)
|
|
{
|
|
assert(count < 0x80000000);
|
|
assert(sizeof(uint16_t) == 2);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfShort(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, count,
|
|
count * 2, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int16_t *value)
|
|
{
|
|
assert(count < 0x80000000);
|
|
assert(sizeof(int16_t) == 2);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfShort((uint16_t *)value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SSHORT, count,
|
|
count * 2, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedLong(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t value)
|
|
{
|
|
uint32_t m;
|
|
assert(sizeof(uint32_t) == 4);
|
|
m = value;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&m);
|
|
return (
|
|
TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, 1, 4, &m));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedLongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint32_t *value)
|
|
{
|
|
assert(count < 0x40000000);
|
|
assert(sizeof(uint32_t) == 4);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, count,
|
|
count * 4, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int32_t *value)
|
|
{
|
|
assert(count < 0x40000000);
|
|
assert(sizeof(int32_t) == 4);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong((uint32_t *)value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG, count,
|
|
count * 4, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint64_t *value)
|
|
{
|
|
assert(count < 0x20000000);
|
|
assert(sizeof(uint64_t) == 8);
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
TIFFErrorExtR(tif, "TIFFWriteDirectoryTagCheckedLong8Array",
|
|
"LONG8 not allowed for ClassicTIFF");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong8(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG8, count,
|
|
count * 8, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
int64_t *value)
|
|
{
|
|
assert(count < 0x20000000);
|
|
assert(sizeof(int64_t) == 8);
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
TIFFErrorExtR(tif, "TIFFWriteDirectoryTagCheckedSlong8Array",
|
|
"SLONG8 not allowed for ClassicTIFF");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong8((uint64_t *)value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG8, count,
|
|
count * 8, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedRational(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
double value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagCheckedRational";
|
|
uint32_t m[2];
|
|
assert(sizeof(uint32_t) == 4);
|
|
if (value < 0)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Negative value is illegal");
|
|
return 0;
|
|
}
|
|
else if (value != value)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Not-a-number value is illegal");
|
|
return 0;
|
|
}
|
|
/*--Rational2Double: New function also used for non-custom rational tags.
|
|
* However, could be omitted here, because
|
|
* TIFFWriteDirectoryTagCheckedRational() is not used by code for custom
|
|
* tags, only by code for named-tiff-tags like FIELD_RESOLUTION and
|
|
* FIELD_POSITION */
|
|
else
|
|
{
|
|
DoubleToRational(value, &m[0], &m[1]);
|
|
}
|
|
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
{
|
|
TIFFSwabLong(&m[0]);
|
|
TIFFSwabLong(&m[1]);
|
|
}
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, 1, 8,
|
|
&m[0]));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
float *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray";
|
|
uint32_t *m;
|
|
float *na;
|
|
uint32_t *nb;
|
|
uint32_t nc;
|
|
int o;
|
|
assert(sizeof(uint32_t) == 4);
|
|
m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t));
|
|
if (m == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++)
|
|
{
|
|
DoubleToRational(*na, &nb[0], &nb[1]);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong(m, count * 2);
|
|
o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count,
|
|
count * 8, &m[0]);
|
|
_TIFFfreeExt(tif, m);
|
|
return (o);
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag,
|
|
uint32_t count,
|
|
float *value)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray";
|
|
int32_t *m;
|
|
float *na;
|
|
int32_t *nb;
|
|
uint32_t nc;
|
|
int o;
|
|
assert(sizeof(int32_t) == 4);
|
|
m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t));
|
|
if (m == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++)
|
|
{
|
|
DoubleToSrational(*na, &nb[0], &nb[1]);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong((uint32_t *)m, count * 2);
|
|
o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SRATIONAL, count,
|
|
count * 8, &m[0]);
|
|
_TIFFfreeExt(tif, m);
|
|
return (o);
|
|
}
|
|
|
|
/*-- Rational2Double: additional write functions for double arrays */
|
|
static int
|
|
TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, double *value)
|
|
{
|
|
static const char module[] =
|
|
"TIFFWriteDirectoryTagCheckedRationalDoubleArray";
|
|
uint32_t *m;
|
|
double *na;
|
|
uint32_t *nb;
|
|
uint32_t nc;
|
|
int o;
|
|
assert(sizeof(uint32_t) == 4);
|
|
m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t));
|
|
if (m == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++)
|
|
{
|
|
DoubleToRational(*na, &nb[0], &nb[1]);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong(m, count * 2);
|
|
o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count,
|
|
count * 8, &m[0]);
|
|
_TIFFfreeExt(tif, m);
|
|
return (o);
|
|
} /*-- TIFFWriteDirectoryTagCheckedRationalDoubleArray() ------- */
|
|
|
|
static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray(
|
|
TIFF *tif, uint32_t *ndir, TIFFDirEntry *dir, uint16_t tag, uint32_t count,
|
|
double *value)
|
|
{
|
|
static const char module[] =
|
|
"TIFFWriteDirectoryTagCheckedSrationalDoubleArray";
|
|
int32_t *m;
|
|
double *na;
|
|
int32_t *nb;
|
|
uint32_t nc;
|
|
int o;
|
|
assert(sizeof(int32_t) == 4);
|
|
m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t));
|
|
if (m == NULL)
|
|
{
|
|
TIFFErrorExtR(tif, module, "Out of memory");
|
|
return (0);
|
|
}
|
|
for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++)
|
|
{
|
|
DoubleToSrational(*na, &nb[0], &nb[1]);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong((uint32_t *)m, count * 2);
|
|
o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SRATIONAL, count,
|
|
count * 8, &m[0]);
|
|
_TIFFfreeExt(tif, m);
|
|
return (o);
|
|
} /*--- TIFFWriteDirectoryTagCheckedSrationalDoubleArray() -------- */
|
|
|
|
/** ----- Rational2Double: Double To Rational Conversion
|
|
----------------------------------------------------------
|
|
* There is a mathematical theorem to convert real numbers into a rational
|
|
(integer fraction) number.
|
|
* This is called "continuous fraction" which uses the Euclidean algorithm to
|
|
find the greatest common divisor (GCD).
|
|
* (ref. e.g. https://de.wikipedia.org/wiki/Kettenbruch or
|
|
https://en.wikipedia.org/wiki/Continued_fraction
|
|
* https://en.wikipedia.org/wiki/Euclidean_algorithm)
|
|
* The following functions implement the
|
|
* - ToRationalEuclideanGCD() auxiliary function which mainly
|
|
implements euclidean GCD
|
|
* - DoubleToRational() conversion function for un-signed
|
|
rationals
|
|
* - DoubleToSrational() conversion function for signed rationals
|
|
------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
/**---- ToRationalEuclideanGCD() -----------------------------------------
|
|
* Calculates the rational fractional of a double input value
|
|
* using the Euclidean algorithm to find the greatest common divisor (GCD)
|
|
------------------------------------------------------------------------*/
|
|
static void ToRationalEuclideanGCD(double value, int blnUseSignedRange,
|
|
int blnUseSmallRange, uint64_t *ullNum,
|
|
uint64_t *ullDenom)
|
|
{
|
|
/* Internally, the integer variables can be bigger than the external ones,
|
|
* as long as the result will fit into the external variable size.
|
|
*/
|
|
uint64_t numSum[3] = {0, 1, 0}, denomSum[3] = {1, 0, 0};
|
|
uint64_t aux, bigNum, bigDenom;
|
|
uint64_t returnLimit;
|
|
int i;
|
|
uint64_t nMax;
|
|
double fMax;
|
|
unsigned long maxDenom;
|
|
/*-- nMax and fMax defines the initial accuracy of the starting fractional,
|
|
* or better, the highest used integer numbers used within the starting
|
|
* fractional (bigNum/bigDenom). There are two approaches, which can
|
|
* accidentally lead to different accuracies just depending on the value.
|
|
* Therefore, blnUseSmallRange steers this behavior.
|
|
* For long long nMax = ((9223372036854775807-1)/2); for long nMax =
|
|
* ((2147483647-1)/2);
|
|
*/
|
|
if (blnUseSmallRange)
|
|
{
|
|
nMax = (uint64_t)((2147483647 - 1) / 2); /* for ULONG range */
|
|
}
|
|
else
|
|
{
|
|
nMax = ((9223372036854775807 - 1) / 2); /* for ULLONG range */
|
|
}
|
|
fMax = (double)nMax;
|
|
|
|
/*-- For the Euclidean GCD define the denominator range, so that it stays
|
|
* within size of unsigned long variables. maxDenom should be LONG_MAX for
|
|
* negative values and ULONG_MAX for positive ones. Also the final returned
|
|
* value of ullNum and ullDenom is limited according to signed- or
|
|
* unsigned-range.
|
|
*/
|
|
if (blnUseSignedRange)
|
|
{
|
|
maxDenom = 2147483647UL; /*LONG_MAX = 0x7FFFFFFFUL*/
|
|
returnLimit = maxDenom;
|
|
}
|
|
else
|
|
{
|
|
maxDenom = 0xFFFFFFFFUL; /*ULONG_MAX = 0xFFFFFFFFUL*/
|
|
returnLimit = maxDenom;
|
|
}
|
|
|
|
/*-- First generate a rational fraction (bigNum/bigDenom) which represents
|
|
*the value as a rational number with the highest accuracy. Therefore,
|
|
*uint64_t (uint64_t) is needed. This rational fraction is then reduced
|
|
*using the Euclidean algorithm to find the greatest common divisor (GCD).
|
|
* bigNum = big numinator of value without fraction (or cut residual
|
|
*fraction) bigDenom = big denominator of value
|
|
*-- Break-criteria so that uint64_t cast to "bigNum" introduces no error
|
|
*and bigDenom has no overflow, and stop with enlargement of fraction when
|
|
*the double-value of it reaches an integer number without fractional part.
|
|
*/
|
|
bigDenom = 1;
|
|
while ((value != floor(value)) && (value < fMax) && (bigDenom < nMax))
|
|
{
|
|
bigDenom <<= 1;
|
|
value *= 2;
|
|
}
|
|
bigNum = (uint64_t)value;
|
|
|
|
/*-- Start Euclidean algorithm to find the greatest common divisor (GCD) --
|
|
*/
|
|
#define MAX_ITERATIONS 64
|
|
for (i = 0; i < MAX_ITERATIONS; i++)
|
|
{
|
|
uint64_t val;
|
|
/* if bigDenom is not zero, calculate integer part of fraction. */
|
|
if (bigDenom == 0)
|
|
{
|
|
break;
|
|
}
|
|
val = bigNum / bigDenom;
|
|
|
|
/* Set bigDenom to reminder of bigNum/bigDenom and bigNum to previous
|
|
* denominator bigDenom. */
|
|
aux = bigNum;
|
|
bigNum = bigDenom;
|
|
bigDenom = aux % bigDenom;
|
|
|
|
/* calculate next denominator and check for its given maximum */
|
|
aux = val;
|
|
if (denomSum[1] * val + denomSum[0] >= maxDenom)
|
|
{
|
|
aux = (maxDenom - denomSum[0]) / denomSum[1];
|
|
if (aux * 2 >= val || denomSum[1] >= maxDenom)
|
|
i = (MAX_ITERATIONS +
|
|
1); /* exit but execute rest of for-loop */
|
|
else
|
|
break;
|
|
}
|
|
/* calculate next numerator to numSum2 and save previous one to numSum0;
|
|
* numSum1 just copy of numSum2. */
|
|
numSum[2] = aux * numSum[1] + numSum[0];
|
|
numSum[0] = numSum[1];
|
|
numSum[1] = numSum[2];
|
|
/* calculate next denominator to denomSum2 and save previous one to
|
|
* denomSum0; denomSum1 just copy of denomSum2. */
|
|
denomSum[2] = aux * denomSum[1] + denomSum[0];
|
|
denomSum[0] = denomSum[1];
|
|
denomSum[1] = denomSum[2];
|
|
}
|
|
|
|
/*-- Check and adapt for final variable size and return values; reduces
|
|
* internal accuracy; denominator is kept in ULONG-range with maxDenom -- */
|
|
while (numSum[1] > returnLimit || denomSum[1] > returnLimit)
|
|
{
|
|
numSum[1] = numSum[1] / 2;
|
|
denomSum[1] = denomSum[1] / 2;
|
|
}
|
|
|
|
/* return values */
|
|
*ullNum = numSum[1];
|
|
*ullDenom = denomSum[1];
|
|
|
|
} /*-- ToRationalEuclideanGCD() -------------- */
|
|
|
|
/**---- DoubleToRational() -----------------------------------------------
|
|
* Calculates the rational fractional of a double input value
|
|
* for UN-SIGNED rationals,
|
|
* using the Euclidean algorithm to find the greatest common divisor (GCD)
|
|
------------------------------------------------------------------------*/
|
|
static void DoubleToRational(double value, uint32_t *num, uint32_t *denom)
|
|
{
|
|
/*---- UN-SIGNED RATIONAL ---- */
|
|
double dblDiff, dblDiff2;
|
|
uint64_t ullNum, ullDenom, ullNum2, ullDenom2;
|
|
|
|
/*-- Check for negative values. If so it is an error. */
|
|
/* Test written that way to catch NaN */
|
|
if (!(value >= 0))
|
|
{
|
|
*num = *denom = 0;
|
|
TIFFErrorExt(0, "TIFFLib: DoubleToRational()",
|
|
" Negative Value for Unsigned Rational given.");
|
|
return;
|
|
}
|
|
|
|
/*-- Check for too big numbers (> ULONG_MAX) -- */
|
|
if (value > 0xFFFFFFFFUL)
|
|
{
|
|
*num = 0xFFFFFFFFU;
|
|
*denom = 0;
|
|
return;
|
|
}
|
|
/*-- Check for easy integer numbers -- */
|
|
if (value == (uint32_t)(value))
|
|
{
|
|
*num = (uint32_t)value;
|
|
*denom = 1;
|
|
return;
|
|
}
|
|
/*-- Check for too small numbers for "unsigned long" type rationals -- */
|
|
if (value < 1.0 / (double)0xFFFFFFFFUL)
|
|
{
|
|
*num = 0;
|
|
*denom = 0xFFFFFFFFU;
|
|
return;
|
|
}
|
|
|
|
/*-- There are two approaches using the Euclidean algorithm,
|
|
* which can accidentally lead to different accuracies just depending on
|
|
* the value. Try both and define which one was better.
|
|
*/
|
|
ToRationalEuclideanGCD(value, FALSE, FALSE, &ullNum, &ullDenom);
|
|
ToRationalEuclideanGCD(value, FALSE, TRUE, &ullNum2, &ullDenom2);
|
|
/*-- Double-Check, that returned values fit into ULONG :*/
|
|
if (ullNum > 0xFFFFFFFFUL || ullDenom > 0xFFFFFFFFUL ||
|
|
ullNum2 > 0xFFFFFFFFUL || ullDenom2 > 0xFFFFFFFFUL)
|
|
{
|
|
TIFFErrorExt(0, "TIFFLib: DoubleToRational()",
|
|
" Num or Denom exceeds ULONG: val=%14.6f, num=%12" PRIu64
|
|
", denom=%12" PRIu64 " | num2=%12" PRIu64
|
|
", denom2=%12" PRIu64 "",
|
|
value, ullNum, ullDenom, ullNum2, ullDenom2);
|
|
assert(0);
|
|
}
|
|
|
|
/* Check, which one has higher accuracy and take that. */
|
|
dblDiff = fabs(value - ((double)ullNum / (double)ullDenom));
|
|
dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2));
|
|
if (dblDiff < dblDiff2)
|
|
{
|
|
*num = (uint32_t)ullNum;
|
|
*denom = (uint32_t)ullDenom;
|
|
}
|
|
else
|
|
{
|
|
*num = (uint32_t)ullNum2;
|
|
*denom = (uint32_t)ullDenom2;
|
|
}
|
|
} /*-- DoubleToRational() -------------- */
|
|
|
|
/**---- DoubleToSrational() -----------------------------------------------
|
|
* Calculates the rational fractional of a double input value
|
|
* for SIGNED rationals,
|
|
* using the Euclidean algorithm to find the greatest common divisor (GCD)
|
|
------------------------------------------------------------------------*/
|
|
static void DoubleToSrational(double value, int32_t *num, int32_t *denom)
|
|
{
|
|
/*---- SIGNED RATIONAL ----*/
|
|
int neg = 1;
|
|
double dblDiff, dblDiff2;
|
|
uint64_t ullNum, ullDenom, ullNum2, ullDenom2;
|
|
|
|
/*-- Check for negative values and use then the positive one for internal
|
|
* calculations, but take the sign into account before returning. */
|
|
if (value < 0)
|
|
{
|
|
neg = -1;
|
|
value = -value;
|
|
}
|
|
|
|
/*-- Check for too big numbers (> LONG_MAX) -- */
|
|
if (value > 0x7FFFFFFFL)
|
|
{
|
|
*num = 0x7FFFFFFFL;
|
|
*denom = 0;
|
|
return;
|
|
}
|
|
/*-- Check for easy numbers -- */
|
|
if (value == (int32_t)(value))
|
|
{
|
|
*num = (int32_t)(neg * value);
|
|
*denom = 1;
|
|
return;
|
|
}
|
|
/*-- Check for too small numbers for "long" type rationals -- */
|
|
if (value < 1.0 / (double)0x7FFFFFFFL)
|
|
{
|
|
*num = 0;
|
|
*denom = 0x7FFFFFFFL;
|
|
return;
|
|
}
|
|
|
|
/*-- There are two approaches using the Euclidean algorithm,
|
|
* which can accidentally lead to different accuracies just depending on
|
|
* the value. Try both and define which one was better. Furthermore, set
|
|
* behavior of ToRationalEuclideanGCD() to the range of signed-long.
|
|
*/
|
|
ToRationalEuclideanGCD(value, TRUE, FALSE, &ullNum, &ullDenom);
|
|
ToRationalEuclideanGCD(value, TRUE, TRUE, &ullNum2, &ullDenom2);
|
|
/*-- Double-Check, that returned values fit into LONG :*/
|
|
if (ullNum > 0x7FFFFFFFL || ullDenom > 0x7FFFFFFFL ||
|
|
ullNum2 > 0x7FFFFFFFL || ullDenom2 > 0x7FFFFFFFL)
|
|
{
|
|
TIFFErrorExt(0, "TIFFLib: DoubleToSrational()",
|
|
" Num or Denom exceeds LONG: val=%14.6f, num=%12" PRIu64
|
|
", denom=%12" PRIu64 " | num2=%12" PRIu64
|
|
", denom2=%12" PRIu64 "",
|
|
neg * value, ullNum, ullDenom, ullNum2, ullDenom2);
|
|
assert(0);
|
|
}
|
|
|
|
/* Check, which one has higher accuracy and take that. */
|
|
dblDiff = fabs(value - ((double)ullNum / (double)ullDenom));
|
|
dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2));
|
|
if (dblDiff < dblDiff2)
|
|
{
|
|
*num = (int32_t)(neg * (long)ullNum);
|
|
*denom = (int32_t)ullDenom;
|
|
}
|
|
else
|
|
{
|
|
*num = (int32_t)(neg * (long)ullNum2);
|
|
*denom = (int32_t)ullDenom2;
|
|
}
|
|
} /*-- DoubleToSrational() --------------*/
|
|
|
|
static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
float *value)
|
|
{
|
|
assert(count < 0x40000000);
|
|
assert(sizeof(float) == 4);
|
|
TIFFCvtNativeToIEEEFloat(tif, count, &value);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfFloat(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_FLOAT, count,
|
|
count * 4, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
double *value)
|
|
{
|
|
assert(count < 0x20000000);
|
|
assert(sizeof(double) == 8);
|
|
TIFFCvtNativeToIEEEDouble(tif, count, &value);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfDouble(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_DOUBLE, count,
|
|
count * 8, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint32_t count, uint32_t *value)
|
|
{
|
|
assert(count < 0x40000000);
|
|
assert(sizeof(uint32_t) == 4);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD, count,
|
|
count * 4, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir,
|
|
uint16_t tag, uint32_t count,
|
|
uint64_t *value)
|
|
{
|
|
assert(count < 0x20000000);
|
|
assert(sizeof(uint64_t) == 8);
|
|
assert(tif->tif_flags & TIFF_BIGTIFF);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabArrayOfLong8(value, count);
|
|
return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD8, count,
|
|
count * 8, value));
|
|
}
|
|
|
|
static int TIFFWriteDirectoryTagData(TIFF *tif, uint32_t *ndir,
|
|
TIFFDirEntry *dir, uint16_t tag,
|
|
uint16_t datatype, uint32_t count,
|
|
uint32_t datalength, void *data)
|
|
{
|
|
static const char module[] = "TIFFWriteDirectoryTagData";
|
|
uint32_t m;
|
|
m = 0;
|
|
while (m < (*ndir))
|
|
{
|
|
assert(dir[m].tdir_tag != tag);
|
|
if (dir[m].tdir_tag > tag)
|
|
break;
|
|
m++;
|
|
}
|
|
if (m < (*ndir))
|
|
{
|
|
uint32_t n;
|
|
for (n = *ndir; n > m; n--)
|
|
dir[n] = dir[n - 1];
|
|
}
|
|
dir[m].tdir_tag = tag;
|
|
dir[m].tdir_type = datatype;
|
|
dir[m].tdir_count = count;
|
|
dir[m].tdir_offset.toff_long8 = 0;
|
|
if (datalength <= ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U))
|
|
{
|
|
if (data && datalength)
|
|
{
|
|
_TIFFmemcpy(&dir[m].tdir_offset, data, datalength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint64_t na, nb;
|
|
na = tif->tif_dataoff;
|
|
nb = na + datalength;
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
nb = (uint32_t)nb;
|
|
if ((nb < na) || (nb < datalength))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded");
|
|
return (0);
|
|
}
|
|
if (!SeekOK(tif, na))
|
|
{
|
|
TIFFErrorExtR(tif, module, "IO error writing tag data");
|
|
return (0);
|
|
}
|
|
if (datalength >= 0x80000000UL)
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"libtiff does not allow writing more than 2147483647 "
|
|
"bytes in a tag");
|
|
return (0);
|
|
}
|
|
if (!WriteOK(tif, data, (tmsize_t)datalength))
|
|
{
|
|
TIFFErrorExtR(tif, module, "IO error writing tag data");
|
|
return (0);
|
|
}
|
|
tif->tif_dataoff = nb;
|
|
if (tif->tif_dataoff & 1)
|
|
tif->tif_dataoff++;
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t o;
|
|
o = (uint32_t)na;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&o);
|
|
_TIFFmemcpy(&dir[m].tdir_offset, &o, 4);
|
|
}
|
|
else
|
|
{
|
|
dir[m].tdir_offset.toff_long8 = na;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&dir[m].tdir_offset.toff_long8);
|
|
}
|
|
}
|
|
(*ndir)++;
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Link the current directory into the directory chain for the file.
|
|
*/
|
|
static int TIFFLinkDirectory(TIFF *tif)
|
|
{
|
|
static const char module[] = "TIFFLinkDirectory";
|
|
|
|
tif->tif_diroff = (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1));
|
|
|
|
/*
|
|
* Handle SubIFDs
|
|
*/
|
|
if (tif->tif_flags & TIFF_INSUBIFD)
|
|
{
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t m;
|
|
m = (uint32_t)tif->tif_diroff;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&m);
|
|
(void)TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 4))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error writing SubIFD directory link");
|
|
return (0);
|
|
}
|
|
/*
|
|
* Advance to the next SubIFD or, if this is
|
|
* the last one configured, revert back to the
|
|
* normal directory linkage.
|
|
*/
|
|
if (--tif->tif_nsubifd)
|
|
tif->tif_subifdoff += 4;
|
|
else
|
|
tif->tif_flags &= ~TIFF_INSUBIFD;
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
uint64_t m;
|
|
m = tif->tif_diroff;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&m);
|
|
(void)TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module,
|
|
"Error writing SubIFD directory link");
|
|
return (0);
|
|
}
|
|
/*
|
|
* Advance to the next SubIFD or, if this is
|
|
* the last one configured, revert back to the
|
|
* normal directory linkage.
|
|
*/
|
|
if (--tif->tif_nsubifd)
|
|
tif->tif_subifdoff += 8;
|
|
else
|
|
tif->tif_flags &= ~TIFF_INSUBIFD;
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t m;
|
|
uint32_t nextdir;
|
|
m = (uint32_t)(tif->tif_diroff);
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&m);
|
|
if (tif->tif_header.classic.tiff_diroff == 0)
|
|
{
|
|
/*
|
|
* First directory, overwrite offset in header.
|
|
*/
|
|
tif->tif_header.classic.tiff_diroff = (uint32_t)tif->tif_diroff;
|
|
tif->tif_lastdiroff = tif->tif_diroff;
|
|
(void)TIFFSeekFile(tif, 4, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 4))
|
|
{
|
|
TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
/*
|
|
* Not the first directory, search to the last and append.
|
|
*/
|
|
if (tif->tif_lastdiroff != 0)
|
|
{
|
|
nextdir = (uint32_t)tif->tif_lastdiroff;
|
|
}
|
|
else
|
|
{
|
|
nextdir = tif->tif_header.classic.tiff_diroff;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
uint16_t dircount;
|
|
uint32_t nextnextdir;
|
|
|
|
if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, 2))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory count");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&dircount);
|
|
(void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12, SEEK_SET);
|
|
if (!ReadOK(tif, &nextnextdir, 4))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory link");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&nextnextdir);
|
|
if (nextnextdir == 0)
|
|
{
|
|
(void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 4))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error writing directory link");
|
|
return (0);
|
|
}
|
|
tif->tif_lastdiroff = tif->tif_diroff;
|
|
break;
|
|
}
|
|
nextdir = nextnextdir;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint64_t m;
|
|
uint64_t nextdir;
|
|
m = tif->tif_diroff;
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&m);
|
|
if (tif->tif_header.big.tiff_diroff == 0)
|
|
{
|
|
/*
|
|
* First directory, overwrite offset in header.
|
|
*/
|
|
tif->tif_header.big.tiff_diroff = tif->tif_diroff;
|
|
tif->tif_lastdiroff = tif->tif_diroff;
|
|
(void)TIFFSeekFile(tif, 8, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 8))
|
|
{
|
|
TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
/*
|
|
* Not the first directory, search to the last and append.
|
|
*/
|
|
if (tif->tif_lastdiroff != 0)
|
|
{
|
|
nextdir = tif->tif_lastdiroff;
|
|
}
|
|
else
|
|
{
|
|
nextdir = tif->tif_header.big.tiff_diroff;
|
|
}
|
|
while (1)
|
|
{
|
|
uint64_t dircount64;
|
|
uint16_t dircount;
|
|
uint64_t nextnextdir;
|
|
|
|
if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount64, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory count");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&dircount64);
|
|
if (dircount64 > 0xFFFF)
|
|
{
|
|
TIFFErrorExtR(
|
|
tif, module,
|
|
"Sanity check on tag count failed, likely corrupt TIFF");
|
|
return (0);
|
|
}
|
|
dircount = (uint16_t)dircount64;
|
|
(void)TIFFSeekFile(tif, nextdir + 8 + dircount * 20, SEEK_SET);
|
|
if (!ReadOK(tif, &nextnextdir, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error fetching directory link");
|
|
return (0);
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&nextnextdir);
|
|
if (nextnextdir == 0)
|
|
{
|
|
(void)TIFFSeekFile(tif, nextdir + 8 + dircount * 20, SEEK_SET);
|
|
if (!WriteOK(tif, &m, 8))
|
|
{
|
|
TIFFErrorExtR(tif, module, "Error writing directory link");
|
|
return (0);
|
|
}
|
|
tif->tif_lastdiroff = tif->tif_diroff;
|
|
break;
|
|
}
|
|
nextdir = nextnextdir;
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TIFFRewriteField() */
|
|
/* */
|
|
/* Rewrite a field in the directory on disk without regard to */
|
|
/* updating the TIFF directory structure in memory. Currently */
|
|
/* only supported for field that already exist in the on-disk */
|
|
/* directory. Mainly used for updating stripoffset / */
|
|
/* stripbytecount values after the directory is already on */
|
|
/* disk. */
|
|
/* */
|
|
/* Returns zero on failure, and one on success. */
|
|
/************************************************************************/
|
|
|
|
int _TIFFRewriteField(TIFF *tif, uint16_t tag, TIFFDataType in_datatype,
|
|
tmsize_t count, void *data)
|
|
{
|
|
static const char module[] = "TIFFResetField";
|
|
/* const TIFFField* fip = NULL; */
|
|
uint16_t dircount;
|
|
tmsize_t dirsize;
|
|
uint8_t direntry_raw[20];
|
|
uint16_t entry_tag = 0;
|
|
uint16_t entry_type = 0;
|
|
uint64_t entry_count = 0;
|
|
uint64_t entry_offset = 0;
|
|
int value_in_entry = 0;
|
|
uint64_t read_offset;
|
|
uint8_t *buf_to_write = NULL;
|
|
TIFFDataType datatype;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Find field definition. */
|
|
/* -------------------------------------------------------------------- */
|
|
/*fip =*/TIFFFindField(tif, tag, TIFF_ANY);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do some checking this is a straight forward case. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (isMapped(tif))
|
|
{
|
|
TIFFErrorExtR(
|
|
tif, module,
|
|
"Memory mapped files not currently supported for this operation.");
|
|
return 0;
|
|
}
|
|
|
|
if (tif->tif_diroff == 0)
|
|
{
|
|
TIFFErrorExtR(
|
|
tif, module,
|
|
"Attempt to reset field on directory not already on disk.");
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the directory entry count. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!SeekOK(tif, tif->tif_diroff))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Seek error accessing TIFF directory",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
|
|
read_offset = tif->tif_diroff;
|
|
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
if (!ReadOK(tif, &dircount, sizeof(uint16_t)))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory count",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&dircount);
|
|
dirsize = 12;
|
|
read_offset += 2;
|
|
}
|
|
else
|
|
{
|
|
uint64_t dircount64;
|
|
if (!ReadOK(tif, &dircount64, sizeof(uint64_t)))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory count",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&dircount64);
|
|
dircount = (uint16_t)dircount64;
|
|
dirsize = 20;
|
|
read_offset += 8;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read through directory to find target tag. */
|
|
/* -------------------------------------------------------------------- */
|
|
while (dircount > 0)
|
|
{
|
|
if (!ReadOK(tif, direntry_raw, dirsize))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory entry.",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&entry_tag, direntry_raw + 0, sizeof(uint16_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&entry_tag);
|
|
|
|
if (entry_tag == tag)
|
|
break;
|
|
|
|
read_offset += dirsize;
|
|
}
|
|
|
|
if (entry_tag != tag)
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Could not find tag %" PRIu16 ".",
|
|
tif->tif_name, tag);
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Extract the type, count and offset for this entry. */
|
|
/* -------------------------------------------------------------------- */
|
|
memcpy(&entry_type, direntry_raw + 2, sizeof(uint16_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort(&entry_type);
|
|
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t value;
|
|
|
|
memcpy(&value, direntry_raw + 4, sizeof(uint32_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&value);
|
|
entry_count = value;
|
|
|
|
memcpy(&value, direntry_raw + 8, sizeof(uint32_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong(&value);
|
|
entry_offset = value;
|
|
}
|
|
else
|
|
{
|
|
memcpy(&entry_count, direntry_raw + 4, sizeof(uint64_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&entry_count);
|
|
|
|
memcpy(&entry_offset, direntry_raw + 12, sizeof(uint64_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8(&entry_offset);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* When a dummy tag was written due to TIFFDeferStrileArrayWriting() */
|
|
/* -------------------------------------------------------------------- */
|
|
if (entry_offset == 0 && entry_count == 0 && entry_type == 0)
|
|
{
|
|
if (tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS)
|
|
{
|
|
entry_type =
|
|
(tif->tif_flags & TIFF_BIGTIFF) ? TIFF_LONG8 : TIFF_LONG;
|
|
}
|
|
else
|
|
{
|
|
int write_aslong8 = 1;
|
|
if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS)
|
|
{
|
|
write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif));
|
|
}
|
|
else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS)
|
|
{
|
|
write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif));
|
|
}
|
|
if (write_aslong8)
|
|
{
|
|
entry_type = TIFF_LONG8;
|
|
}
|
|
else
|
|
{
|
|
int write_aslong4 = 1;
|
|
if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS)
|
|
{
|
|
write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif));
|
|
}
|
|
else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS)
|
|
{
|
|
write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif));
|
|
}
|
|
if (write_aslong4)
|
|
{
|
|
entry_type = TIFF_LONG;
|
|
}
|
|
else
|
|
{
|
|
entry_type = TIFF_SHORT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* What data type do we want to write this as? */
|
|
/* -------------------------------------------------------------------- */
|
|
if (TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
if (in_datatype == TIFF_LONG8)
|
|
datatype = entry_type == TIFF_SHORT ? TIFF_SHORT : TIFF_LONG;
|
|
else if (in_datatype == TIFF_SLONG8)
|
|
datatype = TIFF_SLONG;
|
|
else if (in_datatype == TIFF_IFD8)
|
|
datatype = TIFF_IFD;
|
|
else
|
|
datatype = in_datatype;
|
|
}
|
|
else
|
|
{
|
|
if (in_datatype == TIFF_LONG8 &&
|
|
(entry_type == TIFF_SHORT || entry_type == TIFF_LONG ||
|
|
entry_type == TIFF_LONG8))
|
|
datatype = entry_type;
|
|
else if (in_datatype == TIFF_SLONG8 &&
|
|
(entry_type == TIFF_SLONG || entry_type == TIFF_SLONG8))
|
|
datatype = entry_type;
|
|
else if (in_datatype == TIFF_IFD8 &&
|
|
(entry_type == TIFF_IFD || entry_type == TIFF_IFD8))
|
|
datatype = entry_type;
|
|
else
|
|
datatype = in_datatype;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Prepare buffer of actual data to write. This includes */
|
|
/* swabbing as needed. */
|
|
/* -------------------------------------------------------------------- */
|
|
buf_to_write = (uint8_t *)_TIFFCheckMalloc(
|
|
tif, count, TIFFDataWidth(datatype), "for field buffer.");
|
|
if (!buf_to_write)
|
|
return 0;
|
|
|
|
if (datatype == in_datatype)
|
|
memcpy(buf_to_write, data, count * TIFFDataWidth(datatype));
|
|
else if (datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8)
|
|
{
|
|
tmsize_t i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
((int32_t *)buf_to_write)[i] = (int32_t)((int64_t *)data)[i];
|
|
if ((int64_t)((int32_t *)buf_to_write)[i] != ((int64_t *)data)[i])
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module,
|
|
"Value exceeds 32bit range of output type.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if ((datatype == TIFF_LONG && in_datatype == TIFF_LONG8) ||
|
|
(datatype == TIFF_IFD && in_datatype == TIFF_IFD8))
|
|
{
|
|
tmsize_t i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
((uint32_t *)buf_to_write)[i] = (uint32_t)((uint64_t *)data)[i];
|
|
if ((uint64_t)((uint32_t *)buf_to_write)[i] !=
|
|
((uint64_t *)data)[i])
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module,
|
|
"Value exceeds 32bit range of output type.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if (datatype == TIFF_SHORT && in_datatype == TIFF_LONG8)
|
|
{
|
|
tmsize_t i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
((uint16_t *)buf_to_write)[i] = (uint16_t)((uint64_t *)data)[i];
|
|
if ((uint64_t)((uint16_t *)buf_to_write)[i] !=
|
|
((uint64_t *)data)[i])
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module,
|
|
"Value exceeds 16bit range of output type.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIFFErrorExtR(tif, module, "Unhandled type conversion.");
|
|
return 0;
|
|
}
|
|
|
|
if (TIFFDataWidth(datatype) > 1 && (tif->tif_flags & TIFF_SWAB))
|
|
{
|
|
if (TIFFDataWidth(datatype) == 2)
|
|
TIFFSwabArrayOfShort((uint16_t *)buf_to_write, count);
|
|
else if (TIFFDataWidth(datatype) == 4)
|
|
TIFFSwabArrayOfLong((uint32_t *)buf_to_write, count);
|
|
else if (TIFFDataWidth(datatype) == 8)
|
|
TIFFSwabArrayOfLong8((uint64_t *)buf_to_write, count);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Is this a value that fits into the directory entry? */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
if (TIFFDataWidth(datatype) * count <= 4)
|
|
{
|
|
entry_offset = read_offset + 8;
|
|
value_in_entry = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TIFFDataWidth(datatype) * count <= 8)
|
|
{
|
|
entry_offset = read_offset + 12;
|
|
value_in_entry = 1;
|
|
}
|
|
}
|
|
|
|
if ((tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS) &&
|
|
tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
|
|
tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
|
|
tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0)
|
|
{
|
|
tif->tif_dir.td_stripoffset_entry.tdir_type = datatype;
|
|
tif->tif_dir.td_stripoffset_entry.tdir_count = count;
|
|
}
|
|
else if ((tag == TIFFTAG_TILEBYTECOUNTS ||
|
|
tag == TIFFTAG_STRIPBYTECOUNTS) &&
|
|
tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
|
|
tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
|
|
tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0)
|
|
{
|
|
tif->tif_dir.td_stripbytecount_entry.tdir_type = datatype;
|
|
tif->tif_dir.td_stripbytecount_entry.tdir_count = count;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If the tag type, and count match, then we just write it out */
|
|
/* over the old values without altering the directory entry at */
|
|
/* all. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (entry_count == (uint64_t)count && entry_type == (uint16_t)datatype)
|
|
{
|
|
if (!SeekOK(tif, entry_offset))
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module,
|
|
"%s: Seek error accessing TIFF directory",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
if (!WriteOK(tif, buf_to_write, count * TIFFDataWidth(datatype)))
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module, "Error writing directory link");
|
|
return (0);
|
|
}
|
|
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
return 1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Otherwise, we write the new tag data at the end of the file. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!value_in_entry)
|
|
{
|
|
entry_offset = TIFFSeekFile(tif, 0, SEEK_END);
|
|
|
|
if (!WriteOK(tif, buf_to_write, count * TIFFDataWidth(datatype)))
|
|
{
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
TIFFErrorExtR(tif, module, "Error writing directory link");
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (count * TIFFDataWidth(datatype) == 4)
|
|
{
|
|
uint32_t value;
|
|
memcpy(&value, buf_to_write, count * TIFFDataWidth(datatype));
|
|
entry_offset = value;
|
|
}
|
|
else
|
|
{
|
|
memcpy(&entry_offset, buf_to_write,
|
|
count * TIFFDataWidth(datatype));
|
|
}
|
|
}
|
|
|
|
_TIFFfreeExt(tif, buf_to_write);
|
|
buf_to_write = 0;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Adjust the directory entry. */
|
|
/* -------------------------------------------------------------------- */
|
|
entry_type = datatype;
|
|
entry_count = (uint64_t)count;
|
|
memcpy(direntry_raw + 2, &entry_type, sizeof(uint16_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabShort((uint16_t *)(direntry_raw + 2));
|
|
|
|
if (!(tif->tif_flags & TIFF_BIGTIFF))
|
|
{
|
|
uint32_t value;
|
|
|
|
value = (uint32_t)entry_count;
|
|
memcpy(direntry_raw + 4, &value, sizeof(uint32_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong((uint32_t *)(direntry_raw + 4));
|
|
|
|
value = (uint32_t)entry_offset;
|
|
memcpy(direntry_raw + 8, &value, sizeof(uint32_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong((uint32_t *)(direntry_raw + 8));
|
|
}
|
|
else
|
|
{
|
|
memcpy(direntry_raw + 4, &entry_count, sizeof(uint64_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8((uint64_t *)(direntry_raw + 4));
|
|
|
|
memcpy(direntry_raw + 12, &entry_offset, sizeof(uint64_t));
|
|
if (tif->tif_flags & TIFF_SWAB)
|
|
TIFFSwabLong8((uint64_t *)(direntry_raw + 12));
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write the directory entry out to disk. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!SeekOK(tif, read_offset))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Seek error accessing TIFF directory",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
|
|
if (!WriteOK(tif, direntry_raw, dirsize))
|
|
{
|
|
TIFFErrorExtR(tif, module, "%s: Can not write TIFF directory entry.",
|
|
tif->tif_name);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|