| /* | |
| * 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" | |
| #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); | |
| #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: | |
| if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SRATIONAL: | |
| if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| 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)); | |
| } | |
| #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; | |
| } | |
| 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); | |
| } | |
| 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++) | |
| { | |
| 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)); | |
| } | |
| } | |
| 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++) | |
| { | |
| 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)); | |
| } | |
| } | |
| } | |
| 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); | |
| } | |
| #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: | |
| */ |