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.
3748 lines
115 KiB
3748 lines
115 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 n, float* fp); |
|
extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32 n, double* dp); |
|
#endif |
|
|
|
static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff); |
|
|
|
static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
#endif |
|
|
|
static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value); |
|
static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); |
|
#endif |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); |
|
static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value); |
|
static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); |
|
static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); |
|
#endif |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); |
|
#endif |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value); |
|
static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); |
|
#endif |
|
static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); |
|
#endif |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
#endif |
|
static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
#if 0 |
|
static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
#endif |
|
static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
#endif |
|
static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); |
|
static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
#endif |
|
static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); |
|
static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); |
|
static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); |
|
|
|
static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value); |
|
static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value); |
|
static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); |
|
static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value); |
|
static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); |
|
static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value); |
|
static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
|
|
/*--: Rational2Double: New functions to support true double-precision for custom rational tag types. */ |
|
static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
static int TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
static void DoubleToRational(double value, uint32 *num, uint32 *denom); |
|
static void DoubleToSrational(double value, int32 *num, int32 *denom); |
|
#if 0 |
|
static void DoubleToRational_direct(double value, unsigned long *num, unsigned long *denom); |
|
static void DoubleToSrational_direct(double value, long *num, long *denom); |
|
#endif |
|
|
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); |
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); |
|
#endif |
|
static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); |
|
static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); |
|
static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); |
|
|
|
static int TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 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) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
|
"File opened in read-only mode"); |
|
return 0; |
|
} |
|
if( tif->tif_diroff != 0 ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, 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* 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. |
|
*/ |
|
|
|
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)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
|
"Error updating TIFF header"); |
|
return (0); |
|
} |
|
} |
|
else |
|
{ |
|
uint32 nextdir; |
|
nextdir = tif->tif_header.classic.tiff_diroff; |
|
while(1) { |
|
uint16 dircount; |
|
uint32 nextnextdir; |
|
|
|
if (!SeekOK(tif, nextdir) || |
|
!ReadOK(tif, &dircount, 2)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error fetching directory link"); |
|
return (0); |
|
} |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong(&nextnextdir); |
|
if (nextnextdir==tif->tif_diroff) |
|
{ |
|
uint32 m; |
|
m=0; |
|
(void) TIFFSeekFile(tif, |
|
nextdir+2+dircount*12, SEEK_SET); |
|
if (!WriteOK(tif, &m, 4)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
tif->tif_diroff=0; |
|
break; |
|
} |
|
nextdir=nextnextdir; |
|
} |
|
} |
|
} |
|
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)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
|
"Error updating TIFF header"); |
|
return (0); |
|
} |
|
} |
|
else |
|
{ |
|
uint64 nextdir; |
|
nextdir = tif->tif_header.big.tiff_diroff; |
|
while(1) { |
|
uint64 dircount64; |
|
uint16 dircount; |
|
uint64 nextnextdir; |
|
|
|
if (!SeekOK(tif, nextdir) || |
|
!ReadOK(tif, &dircount64, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error fetching directory count"); |
|
return (0); |
|
} |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong8(&dircount64); |
|
if (dircount64>0xFFFF) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Sanity check on tag count failed, likely corrupt TIFF"); |
|
return (0); |
|
} |
|
dircount=(uint16)dircount64; |
|
(void) TIFFSeekFile(tif, |
|
nextdir+8+dircount*20, SEEK_SET); |
|
if (!ReadOK(tif, &nextnextdir, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error fetching directory link"); |
|
return (0); |
|
} |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong8(&nextnextdir); |
|
if (nextnextdir==tif->tif_diroff) |
|
{ |
|
uint64 m; |
|
m=0; |
|
(void) TIFFSeekFile(tif, |
|
nextdir+8+dircount*20, SEEK_SET); |
|
if (!WriteOK(tif, &m, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
tif->tif_diroff=0; |
|
break; |
|
} |
|
nextdir=nextnextdir; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* Now use TIFFWriteDirectory() normally. |
|
*/ |
|
|
|
return TIFFWriteDirectory( tif ); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) |
|
{ |
|
static const char module[] = "TIFFWriteDirectorySec"; |
|
uint32 ndir; |
|
TIFFDirEntry* dir; |
|
uint32 dirsize; |
|
void* dirmem; |
|
uint32 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)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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) ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error flushing data before directory write"); |
|
return (0); |
|
} |
|
} |
|
if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) |
|
{ |
|
_TIFFfree(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); |
|
} |
|
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 na; |
|
uint16* 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_SUBIFD)) |
|
{ |
|
if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir)) |
|
goto bad; |
|
} |
|
{ |
|
uint32 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 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)(strlen(pb)); |
|
if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,(uint16)o->field_tag,pa,pb)) |
|
goto bad; |
|
} |
|
break; |
|
case TIFF_SETGET_UINT16: |
|
{ |
|
uint16 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)o->field_tag,p)) |
|
goto bad; |
|
} |
|
break; |
|
case TIFF_SETGET_UINT32: |
|
{ |
|
uint32 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)o->field_tag,p)) |
|
goto bad; |
|
} |
|
break; |
|
case TIFF_SETGET_C32_UINT8: |
|
{ |
|
uint32 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)o->field_tag,pa,pb)) |
|
goto bad; |
|
} |
|
break; |
|
default: |
|
TIFFErrorExt(tif->tif_clientdata,module, |
|
"Cannot write tag %d (%s)", |
|
TIFFFieldTag(o), |
|
o->field_name ? o->field_name : "unknown"); |
|
goto bad; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
for (m=0; m<(uint32)(tif->tif_dir.td_customValueCount); m++) |
|
{ |
|
uint16 tag = (uint16)tif->tif_dir.td_customValues[m].info->field_tag; |
|
uint32 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 = _TIFFSetGetFieldSize(tif->tif_dir.td_customValues[m].info->set_field_type); |
|
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) { |
|
TIFFErrorExt(0,"TIFFLib: _TIFFWriteDirectorySec()", "Rational2Double: .set_field_type in 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 = _TIFFSetGetFieldSize(tif->tif_dir.td_customValues[m].info->set_field_type); |
|
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) { |
|
TIFFErrorExt(0,"TIFFLib: _TIFFWriteDirectorySec()", "Rational2Double: .set_field_type in 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=_TIFFmalloc(ndir*sizeof(TIFFDirEntry)); |
|
if (dir==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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)tif->tif_dataoff; |
|
if ((tif->tif_dataoff<tif->tif_diroff)||(tif->tif_dataoff<(uint64)dirsize)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded"); |
|
goto bad; |
|
} |
|
if (tif->tif_dataoff&1) |
|
tif->tif_dataoff++; |
|
if (isimage) |
|
tif->tif_curdir++; |
|
} |
|
if (isimage) |
|
{ |
|
if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0)) |
|
{ |
|
uint32 na; |
|
TIFFDirEntry* nb; |
|
for (na=0, nb=dir; ; na++, nb++) |
|
{ |
|
if( na == ndir ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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=_TIFFmalloc(dirsize); |
|
if (dirmem==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
goto bad; |
|
} |
|
if (!(tif->tif_flags&TIFF_BIGTIFF)) |
|
{ |
|
uint8* n; |
|
uint32 nTmp; |
|
TIFFDirEntry* o; |
|
n=dirmem; |
|
*(uint16*)n=(uint16)ndir; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)n); |
|
n+=2; |
|
o=dir; |
|
for (m=0; m<ndir; m++) |
|
{ |
|
*(uint16*)n=o->tdir_tag; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)n); |
|
n+=2; |
|
*(uint16*)n=o->tdir_type; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)n); |
|
n+=2; |
|
nTmp = (uint32)o->tdir_count; |
|
_TIFFmemcpy(n,&nTmp,4); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong((uint32*)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)tif->tif_nextdiroff; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong(&nTmp); |
|
_TIFFmemcpy(n,&nTmp,4); |
|
} |
|
else |
|
{ |
|
uint8* n; |
|
TIFFDirEntry* o; |
|
n=dirmem; |
|
*(uint64*)n=ndir; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8((uint64*)n); |
|
n+=8; |
|
o=dir; |
|
for (m=0; m<ndir; m++) |
|
{ |
|
*(uint16*)n=o->tdir_tag; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)n); |
|
n+=2; |
|
*(uint16*)n=o->tdir_type; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)n); |
|
n+=2; |
|
_TIFFmemcpy(n,&o->tdir_count,8); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8((uint64*)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*)n); |
|
} |
|
_TIFFfree(dir); |
|
dir=NULL; |
|
if (!SeekOK(tif,tif->tif_diroff)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); |
|
goto bad; |
|
} |
|
if (!WriteOK(tif,dirmem,(tmsize_t)dirsize)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); |
|
goto bad; |
|
} |
|
_TIFFfree(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) |
|
_TIFFfree(dir); |
|
if (dirmem!=NULL) |
|
_TIFFfree(dirmem); |
|
return(0); |
|
} |
|
|
|
static int8 TIFFClampDoubleToInt8( double val ) |
|
{ |
|
if( val > 127 ) |
|
return 127; |
|
if( val < -128 || val != val ) |
|
return -128; |
|
return (int8)val; |
|
} |
|
|
|
static int16 TIFFClampDoubleToInt16( double val ) |
|
{ |
|
if( val > 32767 ) |
|
return 32767; |
|
if( val < -32768 || val != val ) |
|
return -32768; |
|
return (int16)val; |
|
} |
|
|
|
static int32 TIFFClampDoubleToInt32( double val ) |
|
{ |
|
if( val > 0x7FFFFFFF ) |
|
return 0x7FFFFFFF; |
|
if( val < -0x7FFFFFFF-1 || val != val ) |
|
return -0x7FFFFFFF-1; |
|
return (int32)val; |
|
} |
|
|
|
static uint8 TIFFClampDoubleToUInt8( double val ) |
|
{ |
|
if( val < 0 ) |
|
return 0; |
|
if( val > 255 || val != val ) |
|
return 255; |
|
return (uint8)val; |
|
} |
|
|
|
static uint16 TIFFClampDoubleToUInt16( double val ) |
|
{ |
|
if( val < 0 ) |
|
return 0; |
|
if( val > 65535 || val != val ) |
|
return 65535; |
|
return (uint16)val; |
|
} |
|
|
|
static uint32 TIFFClampDoubleToUInt32( double val ) |
|
{ |
|
if( val < 0 ) |
|
return 0; |
|
if( val > 0xFFFFFFFFU || val != val ) |
|
return 0xFFFFFFFFU; |
|
return (uint32)val; |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagSampleformatArray"; |
|
void* conv; |
|
uint32 i; |
|
int ok; |
|
conv = _TIFFmalloc(count*sizeof(double)); |
|
if (conv == NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, 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*)conv)[i] = TIFFClampDoubleToInt8(value[i]); |
|
ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8*)conv); |
|
} |
|
else if (tif->tif_dir.td_bitspersample<=16) |
|
{ |
|
for (i = 0; i < count; ++i) |
|
((int16*)conv)[i] = TIFFClampDoubleToInt16(value[i]); |
|
ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16*)conv); |
|
} |
|
else |
|
{ |
|
for (i = 0; i < count; ++i) |
|
((int32*)conv)[i] = TIFFClampDoubleToInt32(value[i]); |
|
ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32*)conv); |
|
} |
|
break; |
|
case SAMPLEFORMAT_UINT: |
|
if (tif->tif_dir.td_bitspersample<=8) |
|
{ |
|
for (i = 0; i < count; ++i) |
|
((uint8*)conv)[i] = TIFFClampDoubleToUInt8(value[i]); |
|
ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8*)conv); |
|
} |
|
else if (tif->tif_dir.td_bitspersample<=16) |
|
{ |
|
for (i = 0; i < count; ++i) |
|
((uint16*)conv)[i] = TIFFClampDoubleToUInt16(value[i]); |
|
ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16*)conv); |
|
} |
|
else |
|
{ |
|
for (i = 0; i < count; ++i) |
|
((uint32*)conv)[i] = TIFFClampDoubleToUInt32(value[i]); |
|
ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32*)conv); |
|
} |
|
break; |
|
default: |
|
ok = 0; |
|
} |
|
|
|
_TIFFfree(conv); |
|
return (ok); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
switch (tif->tif_dir.td_sampleformat) |
|
{ |
|
case SAMPLEFORMAT_IEEEFP: |
|
if (tif->tif_dir.td_bitspersample<=32) |
|
return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value)); |
|
else |
|
return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value)); |
|
case SAMPLEFORMAT_INT: |
|
if (tif->tif_dir.td_bitspersample<=8) |
|
return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8)value)); |
|
else if (tif->tif_dir.td_bitspersample<=16) |
|
return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16)value)); |
|
else |
|
return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32)value)); |
|
case SAMPLEFORMAT_UINT: |
|
if (tif->tif_dir.td_bitspersample<=8) |
|
return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8)value)); |
|
else if (tif->tif_dir.td_bitspersample<=16) |
|
return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16)value)); |
|
else |
|
return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32)value)); |
|
default: |
|
return(1); |
|
} |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagBytePerSample"; |
|
uint8* m; |
|
uint8* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagSbytePerSample"; |
|
int8* m; |
|
int8* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagShortPerSample"; |
|
uint16* m; |
|
uint16* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagSshortPerSample"; |
|
int16* m; |
|
int16* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagLongPerSample"; |
|
uint32* m; |
|
uint32* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int |
|
TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagSlongPerSample"; |
|
int32* m; |
|
int32* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagSrationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedSrationalDoubleArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagFloatPerSample"; |
|
float* m; |
|
float* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
#ifdef notdef |
|
static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value)); |
|
} |
|
#endif |
|
|
|
static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#if 0 |
|
static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagDoublePerSample"; |
|
double* m; |
|
double* na; |
|
uint16 nb; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++) |
|
*na=value; |
|
o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) |
|
{ |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
if (value<=0xFFFF) |
|
return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16)value)); |
|
else |
|
return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); |
|
} |
|
|
|
static int _WriteAsType(TIFF* tif, uint64 strile_size, uint64 uncompressed_threshold) |
|
{ |
|
const uint16 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_LZMA || |
|
compression == COMPRESSION_LERC || |
|
compression == COMPRESSION_ZSTD || |
|
compression == COMPRESSION_WEBP ) |
|
{ |
|
/* 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 strile_size) |
|
{ |
|
return _WriteAsType(tif, strile_size, 0xFFFFFFFFU); |
|
} |
|
|
|
static int WriteAsLong4(TIFF* tif, uint64 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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* 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* p = _TIFFmalloc(count*sizeof(uint32)); |
|
uint32* q; |
|
uint64* ma; |
|
uint32 mb; |
|
|
|
if (p==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
|
|
for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++) |
|
{ |
|
if (*ma>0xFFFFFFFF) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module, |
|
"Attempt to write value larger than 0xFFFFFFFF in LONG array."); |
|
_TIFFfree(p); |
|
return(0); |
|
} |
|
*q= (uint32)(*ma); |
|
} |
|
|
|
o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p); |
|
_TIFFfree(p); |
|
} |
|
else |
|
{ |
|
uint16* p = _TIFFmalloc(count*sizeof(uint16)); |
|
uint16* q; |
|
uint64* ma; |
|
uint32 mb; |
|
|
|
if (p==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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 */ |
|
TIFFErrorExt(tif->tif_clientdata,module, |
|
"Attempt to write value larger than 0xFFFF in SHORT array."); |
|
_TIFFfree(p); |
|
return(0); |
|
} |
|
*q= (uint16)(*ma); |
|
} |
|
|
|
o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p); |
|
_TIFFfree(p); |
|
} |
|
|
|
return(o); |
|
} |
|
|
|
/************************************************************************/ |
|
/* TIFFWriteDirectoryTagIfdIfd8Array() */ |
|
/* */ |
|
/* Write either IFD8 or IFD array depending on file type. */ |
|
/************************************************************************/ |
|
|
|
static int |
|
TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array"; |
|
uint64* ma; |
|
uint32 mb; |
|
uint32* p; |
|
uint32* 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 = _TIFFmalloc(count*sizeof(uint32)); |
|
if (p==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
|
|
for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++) |
|
{ |
|
if (*ma>0xFFFFFFFF) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module, |
|
"Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file."); |
|
_TIFFfree(p); |
|
return(0); |
|
} |
|
*q= (uint32)(*ma); |
|
} |
|
|
|
o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p); |
|
_TIFFfree(p); |
|
|
|
return(o); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array"; |
|
uint64* ma; |
|
uint32 mb; |
|
uint8 n; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
n=0; |
|
for (ma=value, mb=0; mb<count; ma++, mb++) |
|
{ |
|
if ((n==0)&&(*ma>0xFFFF)) |
|
n=1; |
|
if ((n==1)&&(*ma>0xFFFFFFFF)) |
|
{ |
|
n=2; |
|
break; |
|
} |
|
} |
|
if (n==0) |
|
{ |
|
uint16* p; |
|
uint16* q; |
|
p=_TIFFmalloc(count*sizeof(uint16)); |
|
if (p==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++) |
|
*q=(uint16)(*ma); |
|
o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p); |
|
_TIFFfree(p); |
|
} |
|
else if (n==1) |
|
{ |
|
uint32* p; |
|
uint32* q; |
|
p=_TIFFmalloc(count*sizeof(uint32)); |
|
if (p==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++) |
|
*q=(uint32)(*ma); |
|
o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p); |
|
_TIFFfree(p); |
|
} |
|
else |
|
{ |
|
assert(n==2); |
|
o=TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value); |
|
} |
|
return(o); |
|
} |
|
#endif |
|
static int |
|
TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagColormap"; |
|
uint32 m; |
|
uint16* n; |
|
int o; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=(1<<tif->tif_dir.td_bitspersample); |
|
n=_TIFFmalloc(3*m*sizeof(uint16)); |
|
if (n==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
_TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16)); |
|
_TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16)); |
|
_TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16)); |
|
o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n); |
|
_TIFFfree(n); |
|
return(o); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagTransferfunction"; |
|
uint32 m; |
|
uint16 n; |
|
uint16* o; |
|
int p; |
|
if (dir==NULL) |
|
{ |
|
(*ndir)++; |
|
return(1); |
|
} |
|
m=(1<<tif->tif_dir.td_bitspersample); |
|
n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples; |
|
/* |
|
* 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) |
|
n=3; |
|
if (n==3) |
|
{ |
|
if (tif->tif_dir.td_transferfunction[2] == NULL || |
|
!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16))) |
|
n=2; |
|
} |
|
if (n==2) |
|
{ |
|
if (tif->tif_dir.td_transferfunction[1] == NULL || |
|
!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16))) |
|
n=1; |
|
} |
|
if (n==0) |
|
n=1; |
|
o=_TIFFmalloc(n*m*sizeof(uint16)); |
|
if (o==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
_TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16)); |
|
if (n>1) |
|
_TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16)); |
|
if (n>2) |
|
_TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16)); |
|
p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o); |
|
_TIFFfree(o); |
|
return(p); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagSubifd"; |
|
uint64 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* o; |
|
uint64* pa; |
|
uint32* pb; |
|
uint16 p; |
|
o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32)); |
|
if (o==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Illegal value for SubIFD tag"); |
|
_TIFFfree(o); |
|
return(0); |
|
} |
|
*pb++=(uint32)(*pa++); |
|
} |
|
n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o); |
|
_TIFFfree(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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value) |
|
{ |
|
assert(sizeof(char)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) |
|
{ |
|
assert(sizeof(uint8)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) |
|
{ |
|
assert(sizeof(uint8)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) |
|
{ |
|
assert(sizeof(uint8)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) |
|
{ |
|
assert(sizeof(int8)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value) |
|
{ |
|
assert(sizeof(int8)==1); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) |
|
{ |
|
uint16 m; |
|
assert(sizeof(uint16)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value) |
|
{ |
|
assert(count<0x80000000); |
|
assert(sizeof(uint16)==2); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfShort(value,count); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) |
|
{ |
|
int16 m; |
|
assert(sizeof(int16)==2); |
|
m=value; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort((uint16*)(&m)); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value) |
|
{ |
|
assert(count<0x80000000); |
|
assert(sizeof(int16)==2); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfShort((uint16*)value,count); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) |
|
{ |
|
uint32 m; |
|
assert(sizeof(uint32)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) |
|
{ |
|
assert(count<0x40000000); |
|
assert(sizeof(uint32)==4); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfLong(value,count); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) |
|
{ |
|
int32 m; |
|
assert(sizeof(int32)==4); |
|
m=value; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong((uint32*)(&m)); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value) |
|
{ |
|
assert(count<0x40000000); |
|
assert(sizeof(int32)==4); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfLong((uint32*)value,count); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value) |
|
{ |
|
uint64 m; |
|
assert(sizeof(uint64)==8); |
|
if( !(tif->tif_flags&TIFF_BIGTIFF) ) { |
|
TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedLong8","LONG8 not allowed for ClassicTIFF"); |
|
return(0); |
|
} |
|
m=value; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8(&m); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
assert(count<0x20000000); |
|
assert(sizeof(uint64)==8); |
|
if( !(tif->tif_flags&TIFF_BIGTIFF) ) { |
|
TIFFErrorExt(tif->tif_clientdata,"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)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value) |
|
{ |
|
int64 m; |
|
assert(sizeof(int64)==8); |
|
if( !(tif->tif_flags&TIFF_BIGTIFF) ) { |
|
TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedSlong8","SLONG8 not allowed for ClassicTIFF"); |
|
return(0); |
|
} |
|
m=value; |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8((uint64*)(&m)); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value) |
|
{ |
|
assert(count<0x20000000); |
|
assert(sizeof(int64)==8); |
|
if( !(tif->tif_flags&TIFF_BIGTIFF) ) { |
|
TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedSlong8Array","SLONG8 not allowed for ClassicTIFF"); |
|
return(0); |
|
} |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfLong8((uint64*)value,count); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value)); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagCheckedRational"; |
|
uint32 m[2]; |
|
assert(sizeof(uint32)==4); |
|
if (value < 0) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, "Negative value is illegal"); |
|
return 0; |
|
} |
|
else if (value != value) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, "Not-a-number value is illegal"); |
|
return 0; |
|
} |
|
#ifdef not_def |
|
else if (value==0.0) |
|
{ |
|
m[0]=0; |
|
m[1]=1; |
|
} |
|
else if (value <= 0xFFFFFFFFU && value==(double)(uint32)value) |
|
{ |
|
m[0]=(uint32)value; |
|
m[1]=1; |
|
} |
|
else if (value<1.0) |
|
{ |
|
m[0]=(uint32)(value*0xFFFFFFFF); |
|
m[1]=0xFFFFFFFF; |
|
} |
|
else |
|
{ |
|
m[0]=0xFFFFFFFF; |
|
m[1]=(uint32)(0xFFFFFFFF/value); |
|
} |
|
#else |
|
/*--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]); |
|
} |
|
#endif |
|
|
|
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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray"; |
|
uint32* m; |
|
float* na; |
|
uint32* nb; |
|
uint32 nc; |
|
int o; |
|
assert(sizeof(uint32)==4); |
|
m=_TIFFmalloc(count*2*sizeof(uint32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++) |
|
{ |
|
#ifdef not_def |
|
if (*na<=0.0 || *na != *na) |
|
{ |
|
nb[0]=0; |
|
nb[1]=1; |
|
} |
|
else if (*na >= 0 && *na <= (float)0xFFFFFFFFU && |
|
*na==(float)(uint32)(*na)) |
|
{ |
|
nb[0]=(uint32)(*na); |
|
nb[1]=1; |
|
} |
|
else if (*na<1.0) |
|
{ |
|
nb[0]=(uint32)((double)(*na)*0xFFFFFFFF); |
|
nb[1]=0xFFFFFFFF; |
|
} |
|
else |
|
{ |
|
nb[0]=0xFFFFFFFF; |
|
nb[1]=(uint32)((double)0xFFFFFFFF/(*na)); |
|
} |
|
#else |
|
/*-- Rational2Double: Also for float precision accuracy is sometimes enhanced --*/ |
|
DoubleToRational(*na, &nb[0], &nb[1]); |
|
#endif |
|
} |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfLong(m,count*2); |
|
o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray"; |
|
int32* m; |
|
float* na; |
|
int32* nb; |
|
uint32 nc; |
|
int o; |
|
assert(sizeof(int32)==4); |
|
m=_TIFFmalloc(count*2*sizeof(int32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); |
|
return(0); |
|
} |
|
for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++) |
|
{ |
|
#ifdef not_def |
|
if (*na<0.0) |
|
{ |
|
if (*na==(int32)(*na)) |
|
{ |
|
nb[0]=(int32)(*na); |
|
nb[1]=1; |
|
} |
|
else if (*na>-1.0) |
|
{ |
|
nb[0]=-(int32)((double)(-*na)*0x7FFFFFFF); |
|
nb[1]=0x7FFFFFFF; |
|
} |
|
else |
|
{ |
|
nb[0]=-0x7FFFFFFF; |
|
nb[1]=(int32)((double)0x7FFFFFFF/(-*na)); |
|
} |
|
} |
|
else |
|
{ |
|
if (*na==(int32)(*na)) |
|
{ |
|
nb[0]=(int32)(*na); |
|
nb[1]=1; |
|
} |
|
else if (*na<1.0) |
|
{ |
|
nb[0]=(int32)((double)(*na)*0x7FFFFFFF); |
|
nb[1]=0x7FFFFFFF; |
|
} |
|
else |
|
{ |
|
nb[0]=0x7FFFFFFF; |
|
nb[1]=(int32)((double)0x7FFFFFFF/(*na)); |
|
} |
|
} |
|
#else |
|
/*-- Rational2Double: Also for float precision accuracy is sometimes enhanced --*/ |
|
DoubleToSrational(*na, &nb[0], &nb[1]); |
|
#endif |
|
} |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabArrayOfLong((uint32*)m,count*2); |
|
o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]); |
|
_TIFFfree(m); |
|
return(o); |
|
} |
|
|
|
/*-- Rational2Double: additional write functions for double arrays */ |
|
static int |
|
TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagCheckedRationalDoubleArray"; |
|
uint32* m; |
|
double* na; |
|
uint32* nb; |
|
uint32 nc; |
|
int o; |
|
assert(sizeof(uint32)==4); |
|
m=_TIFFmalloc(count*2*sizeof(uint32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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]); |
|
_TIFFfree(m); |
|
return(o); |
|
} /*-- TIFFWriteDirectoryTagCheckedRationalDoubleArray() ------- */ |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedSrationalDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalDoubleArray"; |
|
int32* m; |
|
double* na; |
|
int32* nb; |
|
uint32 nc; |
|
int o; |
|
assert(sizeof(int32)==4); |
|
m=_TIFFmalloc(count*2*sizeof(int32)); |
|
if (m==NULL) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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*)m,count*2); |
|
o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]); |
|
_TIFFfree(m); |
|
return(o); |
|
} /*--- TIFFWriteDirectoryTagCheckedSrationalDoubleArray() -------- */ |
|
|
|
#if 0 |
|
static |
|
void DoubleToRational_direct(double value, unsigned long *num, unsigned long *denom) |
|
{ |
|
/*--- OLD Code for debugging and comparison ---- */ |
|
/* code merged from TIFFWriteDirectoryTagCheckedRationalArray() and TIFFWriteDirectoryTagCheckedRational() */ |
|
|
|
/* First check for zero and also check for negative numbers (which are illegal for RATIONAL) |
|
* and also check for "not-a-number". In each case just set this to zero to support also rational-arrays. |
|
*/ |
|
if (value<=0.0 || value != value) |
|
{ |
|
*num=0; |
|
*denom=1; |
|
} |
|
else if (value <= 0xFFFFFFFFU && (value==(double)(uint32)(value))) /* check for integer values */ |
|
{ |
|
*num=(uint32)(value); |
|
*denom=1; |
|
} |
|
else if (value<1.0) |
|
{ |
|
*num = (uint32)((value) * (double)0xFFFFFFFFU); |
|
*denom=0xFFFFFFFFU; |
|
} |
|
else |
|
{ |
|
*num=0xFFFFFFFFU; |
|
*denom=(uint32)((double)0xFFFFFFFFU/(value)); |
|
} |
|
} /*-- DoubleToRational_direct() -------------- */ |
|
#endif |
|
|
|
#if 0 |
|
static |
|
void DoubleToSrational_direct(double value, long *num, long *denom) |
|
{ |
|
/*--- OLD Code for debugging and comparison -- SIGNED-version ----*/ |
|
/* code was amended from original TIFFWriteDirectoryTagCheckedSrationalArray() */ |
|
|
|
/* First check for zero and also check for negative numbers (which are illegal for RATIONAL) |
|
* and also check for "not-a-number". In each case just set this to zero to support also rational-arrays. |
|
*/ |
|
if (value<0.0) |
|
{ |
|
if (value==(int32)(value)) |
|
{ |
|
*num=(int32)(value); |
|
*denom=1; |
|
} |
|
else if (value>-1.0) |
|
{ |
|
*num=-(int32)((-value) * (double)0x7FFFFFFF); |
|
*denom=0x7FFFFFFF; |
|
} |
|
else |
|
{ |
|
*num=-0x7FFFFFFF; |
|
*denom=(int32)((double)0x7FFFFFFF / (-value)); |
|
} |
|
} |
|
else |
|
{ |
|
if (value==(int32)(value)) |
|
{ |
|
*num=(int32)(value); |
|
*denom=1; |
|
} |
|
else if (value<1.0) |
|
{ |
|
*num=(int32)((value) *(double)0x7FFFFFFF); |
|
*denom=0x7FFFFFFF; |
|
} |
|
else |
|
{ |
|
*num=0x7FFFFFFF; |
|
*denom=(int32)((double)0x7FFFFFFF / (value)); |
|
} |
|
} |
|
} /*-- DoubleToSrational_direct() --------------*/ |
|
#endif |
|
|
|
//#define DOUBLE2RAT_DEBUGOUTPUT |
|
/** ----- 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, unsigned long long *ullNum, unsigned long long *ullDenom) |
|
{ |
|
/* Internally, the integer variables can be bigger than the external ones, |
|
* as long as the result will fit into the external variable size. |
|
*/ |
|
unsigned long long val, numSum[3] = { 0, 1, 0 }, denomSum[3] = { 1, 0, 0 }; |
|
unsigned long long aux, bigNum, bigDenom; |
|
unsigned long long returnLimit; |
|
int i; |
|
unsigned long long 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 = (unsigned long long)((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, unsigned long long (uint64) 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 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 = (unsigned long long)value; |
|
|
|
/*-- Start Euclidean algorithm to find the greatest common divisor (GCD) -- */ |
|
#define MAX_ITERATIONS 64 |
|
for (i = 0; i < MAX_ITERATIONS; i++) { |
|
/* if bigDenom is not zero, calculate integer part of fraction. */ |
|
if (bigDenom == 0) { |
|
val = 0; |
|
break; |
|
} |
|
else { |
|
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 *num, uint32 *denom) |
|
{ |
|
/*---- UN-SIGNED RATIONAL ---- */ |
|
double dblDiff, dblDiff2; |
|
unsigned long long 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)(value)) { |
|
*num = (uint32)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) { |
|
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) |
|
TIFFErrorExt(0, "TIFFLib: DoubleToRational()", " Num or Denom exceeds ULONG: val=%14.6f, num=%I64u, denom=%I64u | num2=%I64u, denom2=%I64u", value, ullNum, ullDenom, ullNum2, ullDenom2); |
|
#else |
|
TIFFErrorExt(0, "TIFFLib: DoubleToRational()", " Num or Denom exceeds ULONG: val=%14.6f, num=%12llu, denom=%12llu | num2=%12llu, denom2=%12llu", value, ullNum, ullDenom, ullNum2, ullDenom2); |
|
#endif |
|
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)ullNum; |
|
*denom = (uint32)ullDenom; |
|
} |
|
else { |
|
*num = (uint32)ullNum2; |
|
*denom = (uint32)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 *num, int32 *denom) |
|
{ |
|
/*---- SIGNED RATIONAL ----*/ |
|
int neg = 1; |
|
double dblDiff, dblDiff2; |
|
unsigned long long 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)(value)) { |
|
*num = (int32)(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) { |
|
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) |
|
TIFFErrorExt(0, "TIFFLib: DoubleToSrational()", " Num or Denom exceeds LONG: val=%14.6f, num=%I64u, denom=%I64u | num2=%I64u, denom2=%I64u", neg*value, ullNum, ullDenom, ullNum2, ullDenom2); |
|
#else |
|
TIFFErrorExt(0, "TIFFLib: DoubleToSrational()", " Num or Denom exceeds LONG: val=%14.6f, num=%12llu, denom=%12llu | num2=%12llu, denom2=%12llu", neg*value, ullNum, ullDenom, ullNum2, ullDenom2); |
|
#endif |
|
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)(neg * (long)ullNum); |
|
*denom = (int32)ullDenom; |
|
} |
|
else { |
|
*num = (int32)(neg * (long)ullNum2); |
|
*denom = (int32)ullDenom2; |
|
} |
|
} /*-- DoubleToSrational() --------------*/ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) |
|
{ |
|
float m; |
|
assert(sizeof(float)==4); |
|
m=value; |
|
TIFFCvtNativeToIEEEFloat(tif,1,&m); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabFloat(&m); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 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)); |
|
} |
|
|
|
#ifdef notdef |
|
static int |
|
TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) |
|
{ |
|
double m; |
|
assert(sizeof(double)==8); |
|
m=value; |
|
TIFFCvtNativeToIEEEDouble(tif,1,&m); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabDouble(&m); |
|
return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m)); |
|
} |
|
#endif |
|
|
|
static int |
|
TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) |
|
{ |
|
assert(count<0x40000000); |
|
assert(sizeof(uint32)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) |
|
{ |
|
assert(count<0x20000000); |
|
assert(sizeof(uint64)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data) |
|
{ |
|
static const char module[] = "TIFFWriteDirectoryTagData"; |
|
uint32 m; |
|
m=0; |
|
while (m<(*ndir)) |
|
{ |
|
assert(dir[m].tdir_tag!=tag); |
|
if (dir[m].tdir_tag>tag) |
|
break; |
|
m++; |
|
} |
|
if (m<(*ndir)) |
|
{ |
|
uint32 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 na,nb; |
|
na=tif->tif_dataoff; |
|
nb=na+datalength; |
|
if (!(tif->tif_flags&TIFF_BIGTIFF)) |
|
nb=(uint32)nb; |
|
if ((nb<na)||(nb<datalength)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded"); |
|
return(0); |
|
} |
|
if (!SeekOK(tif,na)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data"); |
|
return(0); |
|
} |
|
assert(datalength<0x80000000UL); |
|
if (!WriteOK(tif,data,(tmsize_t)datalength)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,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 o; |
|
o=(uint32)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 m; |
|
m = (uint32)tif->tif_diroff; |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong(&m); |
|
(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); |
|
if (!WriteOK(tif, &m, 4)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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 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)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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 m; |
|
uint32 nextdir; |
|
m = (uint32)(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) tif->tif_diroff; |
|
(void) TIFFSeekFile(tif,4, SEEK_SET); |
|
if (!WriteOK(tif, &m, 4)) { |
|
TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
|
"Error writing TIFF header"); |
|
return (0); |
|
} |
|
return (1); |
|
} |
|
/* |
|
* Not the first directory, search to the last and append. |
|
*/ |
|
nextdir = tif->tif_header.classic.tiff_diroff; |
|
while(1) { |
|
uint16 dircount; |
|
uint32 nextnextdir; |
|
|
|
if (!SeekOK(tif, nextdir) || |
|
!ReadOK(tif, &dircount, 2)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
break; |
|
} |
|
nextdir=nextnextdir; |
|
} |
|
} |
|
else |
|
{ |
|
uint64 m; |
|
uint64 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; |
|
(void) TIFFSeekFile(tif,8, SEEK_SET); |
|
if (!WriteOK(tif, &m, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
|
"Error writing TIFF header"); |
|
return (0); |
|
} |
|
return (1); |
|
} |
|
/* |
|
* Not the first directory, search to the last and append. |
|
*/ |
|
nextdir = tif->tif_header.big.tiff_diroff; |
|
while(1) { |
|
uint64 dircount64; |
|
uint16 dircount; |
|
uint64 nextnextdir; |
|
|
|
if (!SeekOK(tif, nextdir) || |
|
!ReadOK(tif, &dircount64, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error fetching directory count"); |
|
return (0); |
|
} |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong8(&dircount64); |
|
if (dircount64>0xFFFF) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Sanity check on tag count failed, likely corrupt TIFF"); |
|
return (0); |
|
} |
|
dircount=(uint16)dircount64; |
|
(void) TIFFSeekFile(tif, |
|
nextdir+8+dircount*20, SEEK_SET); |
|
if (!ReadOK(tif, &nextnextdir, 8)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
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 tag, TIFFDataType in_datatype, |
|
tmsize_t count, void* data) |
|
{ |
|
static const char module[] = "TIFFResetField"; |
|
/* const TIFFField* fip = NULL; */ |
|
uint16 dircount; |
|
tmsize_t dirsize; |
|
uint8 direntry_raw[20]; |
|
uint16 entry_tag = 0; |
|
uint16 entry_type = 0; |
|
uint64 entry_count = 0; |
|
uint64 entry_offset = 0; |
|
int value_in_entry = 0; |
|
uint64 read_offset; |
|
uint8 *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) ) |
|
{ |
|
TIFFErrorExt( tif->tif_clientdata, module, |
|
"Memory mapped files not currently supported for this operation." ); |
|
return 0; |
|
} |
|
|
|
if( tif->tif_diroff == 0 ) |
|
{ |
|
TIFFErrorExt( tif->tif_clientdata, module, |
|
"Attempt to reset field on directory not already on disk." ); |
|
return 0; |
|
} |
|
|
|
/* -------------------------------------------------------------------- */ |
|
/* Read the directory entry count. */ |
|
/* -------------------------------------------------------------------- */ |
|
if (!SeekOK(tif, tif->tif_diroff)) { |
|
TIFFErrorExt(tif->tif_clientdata, 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))) { |
|
TIFFErrorExt(tif->tif_clientdata, 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 dircount64; |
|
if (!ReadOK(tif, &dircount64, sizeof (uint64))) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Can not read TIFF directory count", |
|
tif->tif_name); |
|
return 0; |
|
} |
|
if (tif->tif_flags & TIFF_SWAB) |
|
TIFFSwabLong8(&dircount64); |
|
dircount = (uint16)dircount64; |
|
dirsize = 20; |
|
read_offset += 8; |
|
} |
|
|
|
/* -------------------------------------------------------------------- */ |
|
/* Read through directory to find target tag. */ |
|
/* -------------------------------------------------------------------- */ |
|
while( dircount > 0 ) |
|
{ |
|
if (!ReadOK(tif, direntry_raw, dirsize)) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Can not read TIFF directory entry.", |
|
tif->tif_name); |
|
return 0; |
|
} |
|
|
|
memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort( &entry_tag ); |
|
|
|
if( entry_tag == tag ) |
|
break; |
|
|
|
read_offset += dirsize; |
|
} |
|
|
|
if( entry_tag != tag ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Could not find tag %d.", |
|
tif->tif_name, tag ); |
|
return 0; |
|
} |
|
|
|
/* -------------------------------------------------------------------- */ |
|
/* Extract the type, count and offset for this entry. */ |
|
/* -------------------------------------------------------------------- */ |
|
memcpy( &entry_type, direntry_raw + 2, sizeof(uint16) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort( &entry_type ); |
|
|
|
if (!(tif->tif_flags&TIFF_BIGTIFF)) |
|
{ |
|
uint32 value; |
|
|
|
memcpy( &value, direntry_raw + 4, sizeof(uint32) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong( &value ); |
|
entry_count = value; |
|
|
|
memcpy( &value, direntry_raw + 8, sizeof(uint32) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong( &value ); |
|
entry_offset = value; |
|
} |
|
else |
|
{ |
|
memcpy( &entry_count, direntry_raw + 4, sizeof(uint64) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8( &entry_count ); |
|
|
|
memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64) ); |
|
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 *)_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 *) buf_to_write)[i] = |
|
(int32) ((int64 *) data)[i]; |
|
if( (int64) ((int32 *) buf_to_write)[i] != ((int64 *) data)[i] ) |
|
{ |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt( tif->tif_clientdata, 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 *) buf_to_write)[i] = |
|
(uint32) ((uint64 *) data)[i]; |
|
if( (uint64) ((uint32 *) buf_to_write)[i] != ((uint64 *) data)[i] ) |
|
{ |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt( tif->tif_clientdata, 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 *) buf_to_write)[i] = |
|
(uint16) ((uint64 *) data)[i]; |
|
if( (uint64) ((uint16 *) buf_to_write)[i] != ((uint64 *) data)[i] ) |
|
{ |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt( tif->tif_clientdata, module, |
|
"Value exceeds 16bit range of output type." ); |
|
return 0; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
TIFFErrorExt( tif->tif_clientdata, module, |
|
"Unhandled type conversion." ); |
|
return 0; |
|
} |
|
|
|
if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) ) |
|
{ |
|
if( TIFFDataWidth(datatype) == 2 ) |
|
TIFFSwabArrayOfShort( (uint16 *) buf_to_write, count ); |
|
else if( TIFFDataWidth(datatype) == 4 ) |
|
TIFFSwabArrayOfLong( (uint32 *) buf_to_write, count ); |
|
else if( TIFFDataWidth(datatype) == 8 ) |
|
TIFFSwabArrayOfLong8( (uint64 *) 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)count && entry_type == (uint16) datatype ) |
|
{ |
|
if (!SeekOK(tif, entry_offset)) { |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Seek error accessing TIFF directory", |
|
tif->tif_name); |
|
return 0; |
|
} |
|
if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) { |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
|
|
_TIFFfree( 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))) { |
|
_TIFFfree( buf_to_write ); |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Error writing directory link"); |
|
return (0); |
|
} |
|
} |
|
else |
|
{ |
|
memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype)); |
|
} |
|
|
|
_TIFFfree( buf_to_write ); |
|
buf_to_write = 0; |
|
|
|
/* -------------------------------------------------------------------- */ |
|
/* Adjust the directory entry. */ |
|
/* -------------------------------------------------------------------- */ |
|
entry_type = datatype; |
|
entry_count = (uint64)count; |
|
memcpy( direntry_raw + 2, &entry_type, sizeof(uint16) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabShort( (uint16 *) (direntry_raw + 2) ); |
|
|
|
if (!(tif->tif_flags&TIFF_BIGTIFF)) |
|
{ |
|
uint32 value; |
|
|
|
value = (uint32) entry_count; |
|
memcpy( direntry_raw + 4, &value, sizeof(uint32) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong( (uint32 *) (direntry_raw + 4) ); |
|
|
|
value = (uint32) entry_offset; |
|
memcpy( direntry_raw + 8, &value, sizeof(uint32) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong( (uint32 *) (direntry_raw + 8) ); |
|
} |
|
else |
|
{ |
|
memcpy( direntry_raw + 4, &entry_count, sizeof(uint64) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8( (uint64 *) (direntry_raw + 4) ); |
|
|
|
memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64) ); |
|
if (tif->tif_flags&TIFF_SWAB) |
|
TIFFSwabLong8( (uint64 *) (direntry_raw + 12) ); |
|
} |
|
|
|
/* -------------------------------------------------------------------- */ |
|
/* Write the directory entry out to disk. */ |
|
/* -------------------------------------------------------------------- */ |
|
if (!SeekOK(tif, read_offset )) { |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Seek error accessing TIFF directory", |
|
tif->tif_name); |
|
return 0; |
|
} |
|
|
|
if (!WriteOK(tif, direntry_raw,dirsize)) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"%s: Can not write TIFF directory entry.", |
|
tif->tif_name); |
|
return 0; |
|
} |
|
|
|
return 1; |
|
} |
|
/* vim: set ts=8 sts=8 sw=8 noet: */ |
|
/* |
|
* Local Variables: |
|
* mode: c |
|
* c-basic-offset: 8 |
|
* fill-column: 78 |
|
* End: |
|
*/
|
|
|