mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3620 lines
135 KiB
3620 lines
135 KiB
/* |
|
* 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; |
|
}
|
|
|