| /* | |
| * Copyright (c) 1988-1997 Sam Leffler | |
| * Copyright (c) 1991-1997 Silicon Graphics, Inc. | |
| * | |
| * Permission to use, copy, modify, distribute, and sell this software and | |
| * its documentation for any purpose is hereby granted without fee, provided | |
| * that (i) the above copyright notices and this permission notice appear in | |
| * all copies of the software and related documentation, and (ii) the names of | |
| * Sam Leffler and Silicon Graphics may not be used in any advertising or | |
| * publicity relating to the software without the specific, prior written | |
| * permission of Sam Leffler and Silicon Graphics. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, | |
| * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY | |
| * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
| * | |
| * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR | |
| * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, | |
| * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
| * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF | |
| * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
| * OF THIS SOFTWARE. | |
| */ | |
| /* | |
| * TIFF Library. | |
| * | |
| * Directory Write Support Routines. | |
| */ | |
| #include "tiffiop.h" | |
| #include <float.h> /*--: for Rational2Double */ | |
| #include <math.h> /*--: for Rational2Double */ | |
| #ifdef HAVE_IEEEFP | |
| #define TIFFCvtNativeToIEEEFloat(tif, n, fp) | |
| #define TIFFCvtNativeToIEEEDouble(tif, n, dp) | |
| #else | |
| /* If your machine does not support IEEE floating point then you will need to | |
| * add support to tif_machdep.c to convert between the native format and | |
| * IEEE format. */ | |
| extern void TIFFCvtNativeToIEEEFloat(TIFF *tif, uint32_t n, float *fp); | |
| extern void TIFFCvtNativeToIEEEDouble(TIFF *tif, uint32_t n, double *dp); | |
| #endif | |
| static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, | |
| uint64_t *pdiroff); | |
| static int TIFFWriteDirectoryTagSampleformatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| double *value); | |
| static int TIFFWriteDirectoryTagAscii(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, char *value); | |
| static int TIFFWriteDirectoryTagUndefinedArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint8_t *value); | |
| static int TIFFWriteDirectoryTagByteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint8_t *value); | |
| static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int8_t *value); | |
| static int TIFFWriteDirectoryTagShort(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value); | |
| static int TIFFWriteDirectoryTagShortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint16_t *value); | |
| static int TIFFWriteDirectoryTagShortPerSample(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value); | |
| static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int16_t *value); | |
| static int TIFFWriteDirectoryTagLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value); | |
| static int TIFFWriteDirectoryTagLongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint32_t *value); | |
| static int TIFFWriteDirectoryTagSlongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int32_t *value); | |
| static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value); | |
| static int TIFFWriteDirectoryTagSlong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int64_t *value); | |
| static int TIFFWriteDirectoryTagRational(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| double value); | |
| static int TIFFWriteDirectoryTagRationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value); | |
| static int TIFFWriteDirectoryTagSrationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value); | |
| static int TIFFWriteDirectoryTagFloatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value); | |
| static int TIFFWriteDirectoryTagDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, double *value); | |
| static int TIFFWriteDirectoryTagIfdArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint32_t *value); | |
| static int TIFFWriteDirectoryTagShortLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value); | |
| static int TIFFWriteDirectoryTagLongLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value); | |
| static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value); | |
| static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir); | |
| static int TIFFWriteDirectoryTagTransferfunction(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir); | |
| static int TIFFWriteDirectoryTagSubifd(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir); | |
| static int TIFFWriteDirectoryTagCheckedAscii(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, char *value); | |
| static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| uint8_t *value); | |
| static int TIFFWriteDirectoryTagCheckedByteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint8_t *value); | |
| static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int8_t *value); | |
| static int TIFFWriteDirectoryTagCheckedShort(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value); | |
| static int TIFFWriteDirectoryTagCheckedShortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint16_t *value); | |
| static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int16_t *value); | |
| static int TIFFWriteDirectoryTagCheckedLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value); | |
| static int TIFFWriteDirectoryTagCheckedLongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint32_t *value); | |
| static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int32_t *value); | |
| static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint64_t *value); | |
| static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int64_t *value); | |
| static int TIFFWriteDirectoryTagCheckedRational(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| double value); | |
| static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| float *value); | |
| static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| float *value); | |
| /*--: Rational2Double: New functions to support true double-precision for custom | |
| * rational tag types. */ | |
| static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| double *value); | |
| static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| double *value); | |
| static int | |
| TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, double *value); | |
| static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray( | |
| TIFF *tif, uint32_t *ndir, TIFFDirEntry *dir, uint16_t tag, uint32_t count, | |
| double *value); | |
| static void DoubleToRational(double value, uint32_t *num, uint32_t *denom); | |
| static void DoubleToSrational(double value, int32_t *num, int32_t *denom); | |
| static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| float *value); | |
| static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| double *value); | |
| static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, | |
| uint32_t *value); | |
| static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint64_t *value); | |
| static int TIFFWriteDirectoryTagData(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t datatype, uint32_t count, | |
| uint32_t datalength, void *data); | |
| static int TIFFLinkDirectory(TIFF *); | |
| /* | |
| * Write the contents of the current directory | |
| * to the specified file. This routine doesn't | |
| * handle overwriting a directory with auxiliary | |
| * storage that's been changed. | |
| */ | |
| int TIFFWriteDirectory(TIFF *tif) | |
| { | |
| return TIFFWriteDirectorySec(tif, TRUE, TRUE, NULL); | |
| } | |
| /* | |
| * This is an advanced writing function that must be used in a particular | |
| * sequence, and generally together with TIFFForceStrileArrayWriting(), | |
| * to make its intended effect. Its aim is to modify the location | |
| * where the [Strip/Tile][Offsets/ByteCounts] arrays are located in the file. | |
| * More precisely, when TIFFWriteCheck() will be called, the tag entries for | |
| * those arrays will be written with type = count = offset = 0 as a temporary | |
| * value. | |
| * | |
| * Its effect is only valid for the current directory, and before | |
| * TIFFWriteDirectory() is first called, and will be reset when | |
| * changing directory. | |
| * | |
| * The typical sequence of calls is: | |
| * TIFFOpen() | |
| * [ TIFFCreateDirectory(tif) ] | |
| * Set fields with calls to TIFFSetField(tif, ...) | |
| * TIFFDeferStrileArrayWriting(tif) | |
| * TIFFWriteCheck(tif, ...) | |
| * TIFFWriteDirectory(tif) | |
| * ... potentially create other directories and come back to the above directory | |
| * TIFFForceStrileArrayWriting(tif): emit the arrays at the end of file | |
| * | |
| * Returns 1 in case of success, 0 otherwise. | |
| */ | |
| int TIFFDeferStrileArrayWriting(TIFF *tif) | |
| { | |
| static const char module[] = "TIFFDeferStrileArrayWriting"; | |
| if (tif->tif_mode == O_RDONLY) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, "File opened in read-only mode"); | |
| return 0; | |
| } | |
| if (tif->tif_diroff != 0) | |
| { | |
| TIFFErrorExtR(tif, module, "Directory has already been written"); | |
| return 0; | |
| } | |
| tif->tif_dir.td_deferstrilearraywriting = TRUE; | |
| return 1; | |
| } | |
| /* | |
| * Similar to TIFFWriteDirectory(), writes the directory out | |
| * but leaves all data structures in memory so that it can be | |
| * written again. This will make a partially written TIFF file | |
| * readable before it is successfully completed/closed. | |
| */ | |
| int TIFFCheckpointDirectory(TIFF *tif) | |
| { | |
| int rc; | |
| /* Setup the strips arrays, if they haven't already been. */ | |
| if (tif->tif_dir.td_stripoffset_p == NULL) | |
| (void)TIFFSetupStrips(tif); | |
| rc = TIFFWriteDirectorySec(tif, TRUE, FALSE, NULL); | |
| (void)TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); | |
| return rc; | |
| } | |
| int TIFFWriteCustomDirectory(TIFF *tif, uint64_t *pdiroff) | |
| { | |
| return TIFFWriteDirectorySec(tif, FALSE, FALSE, pdiroff); | |
| } | |
| /* | |
| * Similar to TIFFWriteDirectorySec(), 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. | |
| */ | |
| static int TIFFRewriteDirectorySec(TIFF *tif, int isimage, int imagedone, | |
| uint64_t *pdiroff) | |
| { | |
| static const char module[] = "TIFFRewriteDirectory"; | |
| /* We don't need to do anything special if it hasn't been written. */ | |
| if (tif->tif_diroff == 0) | |
| return TIFFWriteDirectory(tif); | |
| /* | |
| * Find and zero the pointer to this directory, so that TIFFLinkDirectory | |
| * will cause it to be added after this directories current pre-link. | |
| */ | |
| uint64_t torewritediroff = tif->tif_diroff; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff) | |
| { | |
| tif->tif_header.classic.tiff_diroff = 0; | |
| tif->tif_diroff = 0; | |
| TIFFSeekFile(tif, 4, SEEK_SET); | |
| if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff), 4)) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, "Error updating TIFF header"); | |
| return (0); | |
| } | |
| } | |
| else if (tif->tif_diroff > 0xFFFFFFFFU) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "tif->tif_diroff exceeds 32 bit range allowed for " | |
| "Classic TIFF"); | |
| return (0); | |
| } | |
| else | |
| { | |
| uint32_t nextdir; | |
| nextdir = tif->tif_header.classic.tiff_diroff; | |
| while (1) | |
| { | |
| uint16_t dircount; | |
| uint32_t nextnextdir; | |
| if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, 2)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error fetching directory count"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&dircount); | |
| (void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12U, SEEK_SET); | |
| if (!ReadOK(tif, &nextnextdir, 4)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory link"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&nextnextdir); | |
| if (nextnextdir == tif->tif_diroff) | |
| { | |
| uint32_t m; | |
| m = 0; | |
| (void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12U, | |
| SEEK_SET); | |
| if (!WriteOK(tif, &m, 4)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error writing directory link"); | |
| return (0); | |
| } | |
| tif->tif_diroff = 0; | |
| /* Force a full-traversal to reach the zeroed pointer */ | |
| tif->tif_lastdiroff = 0; | |
| break; | |
| } | |
| nextdir = nextnextdir; | |
| } | |
| } | |
| /* Remove skipped offset from IFD loop directory list. */ | |
| _TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff); | |
| } | |
| else | |
| { | |
| if (tif->tif_header.big.tiff_diroff == tif->tif_diroff) | |
| { | |
| tif->tif_header.big.tiff_diroff = 0; | |
| tif->tif_diroff = 0; | |
| TIFFSeekFile(tif, 8, SEEK_SET); | |
| if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff), 8)) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, "Error updating TIFF header"); | |
| return (0); | |
| } | |
| } | |
| else | |
| { | |
| uint64_t nextdir; | |
| nextdir = tif->tif_header.big.tiff_diroff; | |
| while (1) | |
| { | |
| uint64_t dircount64; | |
| uint64_t nextnextdir; | |
| if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount64, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error fetching directory count"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&dircount64); | |
| if (dircount64 > 0xFFFF) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on tag count failed, likely " | |
| "corrupt TIFF"); | |
| return (0); | |
| } | |
| (void)TIFFSeekFile(tif, nextdir + 8 + dircount64 * 20, | |
| SEEK_SET); | |
| if (!ReadOK(tif, &nextnextdir, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory link"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&nextnextdir); | |
| if (nextnextdir == tif->tif_diroff) | |
| { | |
| uint64_t m; | |
| m = 0; | |
| (void)TIFFSeekFile(tif, nextdir + 8 + dircount64 * 20, | |
| SEEK_SET); | |
| if (!WriteOK(tif, &m, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error writing directory link"); | |
| return (0); | |
| } | |
| tif->tif_diroff = 0; | |
| /* Force a full-traversal to reach the zeroed pointer */ | |
| tif->tif_lastdiroff = 0; | |
| break; | |
| } | |
| nextdir = nextnextdir; | |
| } | |
| } | |
| /* Remove skipped offset from IFD loop directory list. */ | |
| _TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff); | |
| } | |
| /* | |
| * Now use TIFFWriteDirectorySec() normally. | |
| */ | |
| return TIFFWriteDirectorySec(tif, isimage, imagedone, pdiroff); | |
| } /*-- TIFFRewriteDirectorySec() --*/ | |
| /* | |
| * 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) | |
| { | |
| return TIFFRewriteDirectorySec(tif, TRUE, TRUE, NULL); | |
| } | |
| static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, | |
| uint64_t *pdiroff) | |
| { | |
| static const char module[] = "TIFFWriteDirectorySec"; | |
| uint32_t ndir; | |
| TIFFDirEntry *dir; | |
| uint32_t dirsize; | |
| void *dirmem; | |
| uint32_t m; | |
| if (tif->tif_mode == O_RDONLY) | |
| return (1); | |
| _TIFFFillStriles(tif); | |
| /* | |
| * Clear write state so that subsequent images with | |
| * different characteristics get the right buffers | |
| * setup for them. | |
| */ | |
| if (imagedone) | |
| { | |
| if (tif->tif_flags & TIFF_POSTENCODE) | |
| { | |
| tif->tif_flags &= ~TIFF_POSTENCODE; | |
| if (!(*tif->tif_postencode)(tif)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error post-encoding before directory write"); | |
| return (0); | |
| } | |
| } | |
| (*tif->tif_close)(tif); /* shutdown encoder */ | |
| /* | |
| * Flush any data that might have been written | |
| * by the compression close+cleanup routines. But | |
| * be careful not to write stuff if we didn't add data | |
| * in the previous steps as the "rawcc" data may well be | |
| * a previously read tile/strip in mixed read/write mode. | |
| */ | |
| if (tif->tif_rawcc > 0 && (tif->tif_flags & TIFF_BEENWRITING) != 0) | |
| { | |
| if (!TIFFFlushData1(tif)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error flushing data before directory write"); | |
| return (0); | |
| } | |
| } | |
| if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) | |
| { | |
| _TIFFfreeExt(tif, tif->tif_rawdata); | |
| tif->tif_rawdata = NULL; | |
| tif->tif_rawcp = NULL; | |
| tif->tif_rawcc = 0; | |
| tif->tif_rawdatasize = 0; | |
| tif->tif_rawdataoff = 0; | |
| tif->tif_rawdataloaded = 0; | |
| } | |
| tif->tif_flags &= ~(TIFF_BEENWRITING | TIFF_BUFFERSETUP); | |
| } | |
| if (TIFFFieldSet(tif, FIELD_COMPRESSION) && | |
| (tif->tif_dir.td_compression == COMPRESSION_DEFLATE)) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Creating TIFF with legacy Deflate codec identifier, " | |
| "COMPRESSION_ADOBE_DEFLATE is more widely supported"); | |
| } | |
| dir = NULL; | |
| dirmem = NULL; | |
| dirsize = 0; | |
| while (1) | |
| { | |
| /* The first loop only determines "ndir" and uses TIFFLinkDirectory() to | |
| * set the offset at which the IFD is to be written to the file. | |
| * The second loop writes IFD entries to the file. */ | |
| ndir = 0; | |
| if (dir == NULL) | |
| tif->tif_dir.td_dirdatasize_write = 0; | |
| if (isimage) | |
| { | |
| /*-- Step 1: Process named tags for an image with FIELD bits | |
| * associated. --*/ | |
| 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, | |
| (double)tif->tif_dir.td_xresolution)) | |
| goto bad; | |
| if (!TIFFWriteDirectoryTagRational( | |
| tif, &ndir, dir, TIFFTAG_YRESOLUTION, | |
| (double)tif->tif_dir.td_yresolution)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_POSITION)) | |
| { | |
| if (!TIFFWriteDirectoryTagRational( | |
| tif, &ndir, dir, TIFFTAG_XPOSITION, | |
| (double)tif->tif_dir.td_xposition)) | |
| goto bad; | |
| if (!TIFFWriteDirectoryTagRational( | |
| tif, &ndir, dir, TIFFTAG_YPOSITION, | |
| (double)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)) | |
| { | |
| /* Check td_stripbytecount_p for NULL pointer (bug#749) */ | |
| if (tif->tif_dir.td_stripbytecount_p == NULL) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "StripByteCount array is not set, pointer is NULL"); | |
| goto bad; | |
| } | |
| 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)) | |
| { | |
| /* Check td_stripoffset_p for NULL pointer (bug#749) */ | |
| if (tif->tif_dir.td_stripoffset_p == NULL) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "StripByteOffset array is not set, pointer is NULL"); | |
| goto bad; | |
| } | |
| if (!isTiled(tif)) | |
| { | |
| /* td_stripoffset_p might be NULL in an odd OJPEG case. See | |
| * tif_dirread.c around line 3634. | |
| * XXX: OJPEG hack. | |
| * If a) compression is OJPEG, b) it's not a tiled TIFF, | |
| * and c) the number of strips is 1, | |
| * then we tolerate the absence of stripoffsets tag, | |
| * because, presumably, all required data is in the | |
| * JpegInterchangeFormat stream. | |
| * We can get here when using tiffset on such a file. | |
| * See http://bugzilla.maptools.org/show_bug.cgi?id=2500 | |
| */ | |
| if (tif->tif_dir.td_stripoffset_p != NULL && | |
| !TIFFWriteDirectoryTagLongLong8Array( | |
| tif, &ndir, dir, TIFFTAG_STRIPOFFSETS, | |
| tif->tif_dir.td_nstrips, | |
| tif->tif_dir.td_stripoffset_p)) | |
| goto bad; | |
| } | |
| else | |
| { | |
| if (!TIFFWriteDirectoryTagLongLong8Array( | |
| tif, &ndir, dir, TIFFTAG_TILEOFFSETS, | |
| tif->tif_dir.td_nstrips, | |
| tif->tif_dir.td_stripoffset_p)) | |
| goto bad; | |
| } | |
| } | |
| if (TIFFFieldSet(tif, FIELD_COLORMAP)) | |
| { | |
| if (!TIFFWriteDirectoryTagColormap(tif, &ndir, dir)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_EXTRASAMPLES)) | |
| { | |
| if (tif->tif_dir.td_extrasamples) | |
| { | |
| uint16_t na; | |
| uint16_t *nb; | |
| TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &na, &nb); | |
| if (!TIFFWriteDirectoryTagShortArray( | |
| tif, &ndir, dir, TIFFTAG_EXTRASAMPLES, na, nb)) | |
| goto bad; | |
| } | |
| } | |
| if (TIFFFieldSet(tif, FIELD_SAMPLEFORMAT)) | |
| { | |
| if (!TIFFWriteDirectoryTagShortPerSample( | |
| tif, &ndir, dir, TIFFTAG_SAMPLEFORMAT, | |
| tif->tif_dir.td_sampleformat)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_SMINSAMPLEVALUE)) | |
| { | |
| if (!TIFFWriteDirectoryTagSampleformatArray( | |
| tif, &ndir, dir, TIFFTAG_SMINSAMPLEVALUE, | |
| tif->tif_dir.td_samplesperpixel, | |
| tif->tif_dir.td_sminsamplevalue)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_SMAXSAMPLEVALUE)) | |
| { | |
| if (!TIFFWriteDirectoryTagSampleformatArray( | |
| tif, &ndir, dir, TIFFTAG_SMAXSAMPLEVALUE, | |
| tif->tif_dir.td_samplesperpixel, | |
| tif->tif_dir.td_smaxsamplevalue)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_IMAGEDEPTH)) | |
| { | |
| if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir, | |
| TIFFTAG_IMAGEDEPTH, | |
| tif->tif_dir.td_imagedepth)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_TILEDEPTH)) | |
| { | |
| if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir, | |
| TIFFTAG_TILEDEPTH, | |
| tif->tif_dir.td_tiledepth)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_HALFTONEHINTS)) | |
| { | |
| if (!TIFFWriteDirectoryTagShortArray( | |
| tif, &ndir, dir, TIFFTAG_HALFTONEHINTS, 2, | |
| &tif->tif_dir.td_halftonehints[0])) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_YCBCRSUBSAMPLING)) | |
| { | |
| if (!TIFFWriteDirectoryTagShortArray( | |
| tif, &ndir, dir, TIFFTAG_YCBCRSUBSAMPLING, 2, | |
| &tif->tif_dir.td_ycbcrsubsampling[0])) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_YCBCRPOSITIONING)) | |
| { | |
| if (!TIFFWriteDirectoryTagShort( | |
| tif, &ndir, dir, TIFFTAG_YCBCRPOSITIONING, | |
| tif->tif_dir.td_ycbcrpositioning)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_REFBLACKWHITE)) | |
| { | |
| if (!TIFFWriteDirectoryTagRationalArray( | |
| tif, &ndir, dir, TIFFTAG_REFERENCEBLACKWHITE, 6, | |
| tif->tif_dir.td_refblackwhite)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_TRANSFERFUNCTION)) | |
| { | |
| if (!TIFFWriteDirectoryTagTransferfunction(tif, &ndir, dir)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_INKNAMES)) | |
| { | |
| if (!TIFFWriteDirectoryTagAscii( | |
| tif, &ndir, dir, TIFFTAG_INKNAMES, | |
| (uint32_t)tif->tif_dir.td_inknameslen, | |
| tif->tif_dir.td_inknames)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) | |
| { | |
| if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir, | |
| TIFFTAG_NUMBEROFINKS, | |
| tif->tif_dir.td_numberofinks)) | |
| goto bad; | |
| } | |
| if (TIFFFieldSet(tif, FIELD_SUBIFD)) | |
| { | |
| if (!TIFFWriteDirectoryTagSubifd(tif, &ndir, dir)) | |
| goto bad; | |
| } | |
| /*-- Step 2: Process named tags for an image with FIELD bits | |
| added by a codec. | |
| Attention: There is only code for some field_types, | |
| which are actually used by current codecs. --*/ | |
| { | |
| uint32_t n; | |
| for (n = 0; n < tif->tif_nfields; n++) | |
| { | |
| const TIFFField *o; | |
| o = tif->tif_fields[n]; | |
| if ((o->field_bit >= FIELD_CODEC) && | |
| (TIFFFieldSet(tif, o->field_bit))) | |
| { | |
| switch (o->set_get_field_type) | |
| { | |
| case TIFF_SETGET_ASCII: | |
| { | |
| uint32_t pa; | |
| char *pb; | |
| assert(o->field_type == TIFF_ASCII); | |
| assert(o->field_readcount == TIFF_VARIABLE); | |
| assert(o->field_passcount == 0); | |
| TIFFGetField(tif, o->field_tag, &pb); | |
| pa = (uint32_t)(strlen(pb) + 1); | |
| if (!TIFFWriteDirectoryTagAscii( | |
| tif, &ndir, dir, (uint16_t)o->field_tag, | |
| pa, pb)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFF_SETGET_UINT16: | |
| { | |
| uint16_t p; | |
| assert(o->field_type == TIFF_SHORT); | |
| assert(o->field_readcount == 1); | |
| assert(o->field_passcount == 0); | |
| TIFFGetField(tif, o->field_tag, &p); | |
| if (!TIFFWriteDirectoryTagShort( | |
| tif, &ndir, dir, (uint16_t)o->field_tag, | |
| p)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFF_SETGET_UINT32: | |
| { | |
| uint32_t p; | |
| assert(o->field_type == TIFF_LONG); | |
| assert(o->field_readcount == 1); | |
| assert(o->field_passcount == 0); | |
| TIFFGetField(tif, o->field_tag, &p); | |
| if (!TIFFWriteDirectoryTagLong( | |
| tif, &ndir, dir, (uint16_t)o->field_tag, | |
| p)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFF_SETGET_C32_UINT8: | |
| { | |
| uint32_t pa; | |
| void *pb; | |
| assert(o->field_type == TIFF_UNDEFINED); | |
| assert(o->field_readcount == TIFF_VARIABLE2); | |
| assert(o->field_passcount == 1); | |
| TIFFGetField(tif, o->field_tag, &pa, &pb); | |
| if (!TIFFWriteDirectoryTagUndefinedArray( | |
| tif, &ndir, dir, (uint16_t)o->field_tag, | |
| pa, (uint8_t *)pb)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFF_SETGET_UNDEFINED: | |
| case TIFF_SETGET_SINT8: | |
| case TIFF_SETGET_SINT16: | |
| case TIFF_SETGET_SINT32: | |
| case TIFF_SETGET_UINT64: | |
| case TIFF_SETGET_SINT64: | |
| case TIFF_SETGET_FLOAT: | |
| case TIFF_SETGET_DOUBLE: | |
| case TIFF_SETGET_IFD8: | |
| case TIFF_SETGET_INT: | |
| case TIFF_SETGET_UINT16_PAIR: | |
| case TIFF_SETGET_C0_ASCII: | |
| case TIFF_SETGET_C0_UINT8: | |
| case TIFF_SETGET_C0_SINT8: | |
| case TIFF_SETGET_C0_UINT16: | |
| case TIFF_SETGET_C0_SINT16: | |
| case TIFF_SETGET_C0_UINT32: | |
| case TIFF_SETGET_C0_SINT32: | |
| case TIFF_SETGET_C0_UINT64: | |
| case TIFF_SETGET_C0_SINT64: | |
| case TIFF_SETGET_C0_FLOAT: | |
| case TIFF_SETGET_C0_DOUBLE: | |
| case TIFF_SETGET_C0_IFD8: | |
| case TIFF_SETGET_C16_ASCII: | |
| case TIFF_SETGET_C16_UINT8: | |
| case TIFF_SETGET_C16_SINT8: | |
| case TIFF_SETGET_C16_UINT16: | |
| case TIFF_SETGET_C16_SINT16: | |
| case TIFF_SETGET_C16_UINT32: | |
| case TIFF_SETGET_C16_SINT32: | |
| case TIFF_SETGET_C16_UINT64: | |
| case TIFF_SETGET_C16_SINT64: | |
| case TIFF_SETGET_C16_FLOAT: | |
| case TIFF_SETGET_C16_DOUBLE: | |
| case TIFF_SETGET_C16_IFD8: | |
| case TIFF_SETGET_C32_ASCII: | |
| case TIFF_SETGET_C32_SINT8: | |
| case TIFF_SETGET_C32_UINT16: | |
| case TIFF_SETGET_C32_SINT16: | |
| case TIFF_SETGET_C32_UINT32: | |
| case TIFF_SETGET_C32_SINT32: | |
| case TIFF_SETGET_C32_UINT64: | |
| case TIFF_SETGET_C32_SINT64: | |
| case TIFF_SETGET_C32_FLOAT: | |
| case TIFF_SETGET_C32_DOUBLE: | |
| case TIFF_SETGET_C32_IFD8: | |
| case TIFF_SETGET_UINT8: | |
| case TIFF_SETGET_OTHER: | |
| default: | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Cannot write tag %" PRIu32 " (%s)", | |
| TIFFFieldTag(o), | |
| o->field_name ? o->field_name : "unknown"); | |
| goto bad; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /*-- Step 3: Process custom tags without FIELD bit for an image | |
| * or for custom IFDs (e.g. EXIF) with !isimage. --*/ | |
| for (m = 0; m < (uint32_t)(tif->tif_dir.td_customValueCount); m++) | |
| { | |
| uint16_t tag = | |
| (uint16_t)tif->tif_dir.td_customValues[m].info->field_tag; | |
| uint32_t count = (uint32_t)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, | |
| (char *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_UNDEFINED: | |
| if (!TIFFWriteDirectoryTagUndefinedArray( | |
| tif, &ndir, dir, tag, count, | |
| (uint8_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_BYTE: | |
| if (!TIFFWriteDirectoryTagByteArray( | |
| tif, &ndir, dir, tag, count, | |
| (uint8_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SBYTE: | |
| if (!TIFFWriteDirectoryTagSbyteArray( | |
| tif, &ndir, dir, tag, count, | |
| (int8_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SHORT: | |
| if (!TIFFWriteDirectoryTagShortArray( | |
| tif, &ndir, dir, tag, count, | |
| (uint16_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SSHORT: | |
| if (!TIFFWriteDirectoryTagSshortArray( | |
| tif, &ndir, dir, tag, count, | |
| (int16_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_LONG: | |
| if (!TIFFWriteDirectoryTagLongArray( | |
| tif, &ndir, dir, tag, count, | |
| (uint32_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SLONG: | |
| if (!TIFFWriteDirectoryTagSlongArray( | |
| tif, &ndir, dir, tag, count, | |
| (int32_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_LONG8: | |
| if (!TIFFWriteDirectoryTagLong8Array( | |
| tif, &ndir, dir, tag, count, | |
| (uint64_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_SLONG8: | |
| if (!TIFFWriteDirectoryTagSlong8Array( | |
| tif, &ndir, dir, tag, count, | |
| (int64_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_RATIONAL: | |
| { | |
| /*-- Rational2Double: For Rationals evaluate | |
| * "set_get_field_type" to determine internal storage size. | |
| */ | |
| int tv_size; | |
| tv_size = TIFFFieldSetGetSize( | |
| tif->tif_dir.td_customValues[m].info); | |
| if (tv_size == 8) | |
| { | |
| if (!TIFFWriteDirectoryTagRationalDoubleArray( | |
| tif, &ndir, dir, tag, count, | |
| (double *)tif->tif_dir.td_customValues[m] | |
| .value)) | |
| goto bad; | |
| } | |
| else | |
| { | |
| /*-- default should be tv_size == 4 */ | |
| if (!TIFFWriteDirectoryTagRationalArray( | |
| tif, &ndir, dir, tag, count, | |
| (float *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| /*-- ToDo: After Testing, this should be removed and | |
| * tv_size==4 should be set as default. */ | |
| if (tv_size != 4) | |
| { | |
| TIFFErrorExtR( | |
| tif, "TIFFLib: _TIFFWriteDirectorySec()", | |
| "Rational2Double: .set_get_field_type is " | |
| "not 4 but %d", | |
| tv_size); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SRATIONAL: | |
| { | |
| /*-- Rational2Double: For Rationals evaluate | |
| * "set_get_field_type" to determine internal storage size. | |
| */ | |
| int tv_size; | |
| tv_size = TIFFFieldSetGetSize( | |
| tif->tif_dir.td_customValues[m].info); | |
| if (tv_size == 8) | |
| { | |
| if (!TIFFWriteDirectoryTagSrationalDoubleArray( | |
| tif, &ndir, dir, tag, count, | |
| (double *)tif->tif_dir.td_customValues[m] | |
| .value)) | |
| goto bad; | |
| } | |
| else | |
| { | |
| /*-- default should be tv_size == 4 */ | |
| if (!TIFFWriteDirectoryTagSrationalArray( | |
| tif, &ndir, dir, tag, count, | |
| (float *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| /*-- ToDo: After Testing, this should be removed and | |
| * tv_size==4 should be set as default. */ | |
| if (tv_size != 4) | |
| { | |
| TIFFErrorExtR( | |
| tif, "TIFFLib: _TIFFWriteDirectorySec()", | |
| "Rational2Double: .set_get_field_type is " | |
| "not 4 but %d", | |
| tv_size); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_FLOAT: | |
| if (!TIFFWriteDirectoryTagFloatArray( | |
| tif, &ndir, dir, tag, count, | |
| (float *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_DOUBLE: | |
| if (!TIFFWriteDirectoryTagDoubleArray( | |
| tif, &ndir, dir, tag, count, | |
| (double *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_IFD: | |
| if (!TIFFWriteDirectoryTagIfdArray( | |
| tif, &ndir, dir, tag, count, | |
| (uint32_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_IFD8: | |
| if (!TIFFWriteDirectoryTagIfdIfd8Array( | |
| tif, &ndir, dir, tag, count, | |
| (uint64_t *)tif->tif_dir.td_customValues[m].value)) | |
| goto bad; | |
| break; | |
| case TIFF_NOTYPE: | |
| default: | |
| assert(0); /* we should never get here */ | |
| break; | |
| } | |
| } | |
| /* "break" if IFD has been written above in second pass.*/ | |
| if (dir != NULL) | |
| break; | |
| /* Evaluate IFD data size: Finally, add the size of the IFD tag entries | |
| * themselves. */ | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| tif->tif_dir.td_dirdatasize_write += 2 + ndir * 12 + 4; | |
| else | |
| tif->tif_dir.td_dirdatasize_write += 8 + ndir * 20 + 8; | |
| /* Setup a new directory within first pass. */ | |
| dir = (TIFFDirEntry *)_TIFFmallocExt( | |
| tif, (tmsize_t)((size_t)ndir * sizeof(TIFFDirEntry))); | |
| if (dir == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| goto bad; | |
| } | |
| if (isimage) | |
| { | |
| /* Check, weather the IFD to be written is new or an already written | |
| * IFD can be overwritten or needs to be re-written to a different | |
| * location in the file because the IFD is extended with additional | |
| * tags or the IFD data size is increased. | |
| * - tif_diroff == 0, if a new directory has to be linked. | |
| * - tif_diroff != 0, IFD has been re-read from file and will be | |
| * overwritten or re-written. | |
| */ | |
| if (tif->tif_diroff == 0) | |
| { | |
| if (!TIFFLinkDirectory(tif)) | |
| goto bad; | |
| } | |
| else if (tif->tif_dir.td_dirdatasize_write > | |
| tif->tif_dir.td_dirdatasize_read) | |
| { | |
| if (dir != NULL) | |
| { | |
| _TIFFfreeExt(tif, dir); | |
| dir = NULL; | |
| } | |
| if (!TIFFRewriteDirectorySec(tif, isimage, imagedone, pdiroff)) | |
| goto bad; | |
| return (1); | |
| } | |
| } | |
| else | |
| { | |
| /* For !isimage, which means custom-IFD like EXIFIFD or | |
| * checkpointing an IFD, determine whether to overwrite or append at | |
| * the end of the file. | |
| */ | |
| if (!((tif->tif_dir.td_dirdatasize_read > 0) && | |
| (tif->tif_dir.td_dirdatasize_write <= | |
| tif->tif_dir.td_dirdatasize_read))) | |
| { | |
| /* Append at end of file and increment to an even offset. */ | |
| tif->tif_diroff = | |
| (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1)); | |
| } | |
| } | |
| /* Return IFD offset */ | |
| if (pdiroff != NULL) | |
| *pdiroff = tif->tif_diroff; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| dirsize = 2 + ndir * 12 + 4; | |
| else | |
| dirsize = 8 + ndir * 20 + 8; | |
| /* Append IFD data stright after the IFD tag entries. | |
| * Data that does not fit into an IFD tag entry is written to the file | |
| * in the second pass of the while loop. That offset is stored in "dir". | |
| */ | |
| tif->tif_dataoff = tif->tif_diroff + dirsize; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| tif->tif_dataoff = (uint32_t)tif->tif_dataoff; | |
| if ((tif->tif_dataoff < tif->tif_diroff) || | |
| (tif->tif_dataoff < (uint64_t)dirsize)) | |
| { | |
| TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); | |
| goto bad; | |
| } | |
| if (tif->tif_dataoff & 1) | |
| tif->tif_dataoff++; | |
| } /* while() */ | |
| if (isimage) | |
| { | |
| /* For SubIFDs remember offset of SubIFD tag within main IFD. | |
| * However, might be already done in TIFFWriteDirectoryTagSubifd() if | |
| * there are more than one SubIFD. */ | |
| if (TIFFFieldSet(tif, FIELD_SUBIFD) && (tif->tif_subifdoff == 0)) | |
| { | |
| uint32_t na; | |
| TIFFDirEntry *nb; | |
| for (na = 0, nb = dir;; na++, nb++) | |
| { | |
| if (na == ndir) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot find SubIFD tag"); | |
| goto bad; | |
| } | |
| if (nb->tdir_tag == TIFFTAG_SUBIFD) | |
| break; | |
| } | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| tif->tif_subifdoff = tif->tif_diroff + 2 + na * 12 + 8; | |
| else | |
| tif->tif_subifdoff = tif->tif_diroff + 8 + na * 20 + 12; | |
| } | |
| } | |
| /* Copy/swab IFD entries from "dir" into "dirmem", | |
| * which is then written to file. */ | |
| dirmem = _TIFFmallocExt(tif, dirsize); | |
| if (dirmem == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| goto bad; | |
| } | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint8_t *n; | |
| uint32_t nTmp; | |
| TIFFDirEntry *o; | |
| n = (uint8_t *)dirmem; | |
| *(uint16_t *)n = (uint16_t)ndir; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)n); | |
| n += 2; | |
| o = dir; | |
| for (m = 0; m < ndir; m++) | |
| { | |
| *(uint16_t *)n = o->tdir_tag; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)n); | |
| n += 2; | |
| *(uint16_t *)n = o->tdir_type; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)n); | |
| n += 2; | |
| nTmp = (uint32_t)o->tdir_count; | |
| _TIFFmemcpy(n, &nTmp, 4); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)n); | |
| n += 4; | |
| /* This is correct. The data has been */ | |
| /* swabbed previously in TIFFWriteDirectoryTagData */ | |
| _TIFFmemcpy(n, &o->tdir_offset, 4); | |
| n += 4; | |
| o++; | |
| } | |
| nTmp = (uint32_t)tif->tif_nextdiroff; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&nTmp); | |
| _TIFFmemcpy(n, &nTmp, 4); | |
| } | |
| else | |
| { | |
| uint8_t *n; | |
| TIFFDirEntry *o; | |
| n = (uint8_t *)dirmem; | |
| *(uint64_t *)n = ndir; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)n); | |
| n += 8; | |
| o = dir; | |
| for (m = 0; m < ndir; m++) | |
| { | |
| *(uint16_t *)n = o->tdir_tag; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)n); | |
| n += 2; | |
| *(uint16_t *)n = o->tdir_type; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)n); | |
| n += 2; | |
| _TIFFmemcpy(n, &o->tdir_count, 8); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)n); | |
| n += 8; | |
| _TIFFmemcpy(n, &o->tdir_offset, 8); | |
| n += 8; | |
| o++; | |
| } | |
| _TIFFmemcpy(n, &tif->tif_nextdiroff, 8); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)n); | |
| } | |
| _TIFFfreeExt(tif, dir); | |
| dir = NULL; | |
| if (!SeekOK(tif, tif->tif_diroff)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "IO error writing directory at seek to offset"); | |
| goto bad; | |
| } | |
| if (!WriteOK(tif, dirmem, (tmsize_t)dirsize)) | |
| { | |
| TIFFErrorExtR(tif, module, "IO error writing directory"); | |
| goto bad; | |
| } | |
| _TIFFfreeExt(tif, dirmem); | |
| /* Increment tif_curdir if IFD wasn't already written to file and no error | |
| * occurred during IFD writing above. */ | |
| if (isimage && !tif->tif_dir.td_iswrittentofile) | |
| { | |
| if (!((tif->tif_flags & TIFF_INSUBIFD) && | |
| !(TIFFFieldSet(tif, FIELD_SUBIFD)))) | |
| { | |
| /*-- Normal main-IFD case --*/ | |
| if (tif->tif_curdircount != TIFF_NON_EXISTENT_DIR_NUMBER) | |
| { | |
| tif->tif_curdir = tif->tif_curdircount; | |
| } | |
| else | |
| { | |
| /*ToDo SU: NEW_IFD_CURDIR_INCREMENTING: Delete this | |
| * unexpected case after some testing time. */ | |
| /* Attention: tif->tif_curdircount is already set within | |
| * TIFFNumberOfDirectories() */ | |
| tif->tif_curdircount = TIFFNumberOfDirectories(tif); | |
| tif->tif_curdir = tif->tif_curdircount; | |
| TIFFErrorExtR( | |
| tif, module, | |
| "tif_curdircount is TIFF_NON_EXISTENT_DIR_NUMBER, " | |
| "not expected !! Line %d", | |
| __LINE__); | |
| goto bad; | |
| } | |
| } | |
| else | |
| { | |
| /*-- SubIFD case -- */ | |
| /* tif_curdir is always set to 0 for all SubIFDs. */ | |
| tif->tif_curdir = 0; | |
| } | |
| } | |
| /* Increment tif_curdircount only if main-IFD of an image was not already | |
| * present on file. */ | |
| /* Check in combination with (... && !(TIFFFieldSet(tif, FIELD_SUBIFD))) | |
| * is necessary here because TIFF_INSUBIFD was already set above for the | |
| * next SubIFD when this main-IFD (with FIELD_SUBIFD) is currently being | |
| * written. */ | |
| if (isimage && !tif->tif_dir.td_iswrittentofile && | |
| !((tif->tif_flags & TIFF_INSUBIFD) && | |
| !(TIFFFieldSet(tif, FIELD_SUBIFD)))) | |
| tif->tif_curdircount++; | |
| tif->tif_dir.td_iswrittentofile = TRUE; | |
| /* Reset SubIFD writing stage after last SubIFD has been written. */ | |
| if (imagedone && (tif->tif_flags & TIFF_INSUBIFD) && tif->tif_nsubifd == 0) | |
| tif->tif_flags &= ~TIFF_INSUBIFD; | |
| /* Add or update this directory to the IFD list. */ | |
| if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, tif->tif_diroff)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64 | |
| ") might cause an IFD loop", | |
| tif->tif_curdir, tif->tif_diroff, tif->tif_diroff); | |
| } | |
| if (imagedone) | |
| { | |
| TIFFFreeDirectory(tif); | |
| tif->tif_flags &= ~TIFF_DIRTYDIRECT; | |
| tif->tif_flags &= ~TIFF_DIRTYSTRIP; | |
| /* Reset directory-related state for subsequent directories. */ | |
| TIFFCreateDirectory(tif); | |
| } | |
| else | |
| { | |
| /* IFD is only checkpointed to file (or a custom IFD like EXIF is | |
| * written), thus set IFD data size written to file. */ | |
| tif->tif_dir.td_dirdatasize_read = tif->tif_dir.td_dirdatasize_write; | |
| } | |
| return (1); | |
| bad: | |
| if (dir != NULL) | |
| _TIFFfreeExt(tif, dir); | |
| if (dirmem != NULL) | |
| _TIFFfreeExt(tif, dirmem); | |
| return (0); | |
| } | |
| static int8_t TIFFClampDoubleToInt8(double val) | |
| { | |
| if (val > 127) | |
| return 127; | |
| if (val < -128 || isnan(val)) | |
| return -128; | |
| return (int8_t)val; | |
| } | |
| static int16_t TIFFClampDoubleToInt16(double val) | |
| { | |
| if (val > 32767) | |
| return 32767; | |
| if (val < -32768 || isnan(val)) | |
| return -32768; | |
| return (int16_t)val; | |
| } | |
| static int32_t TIFFClampDoubleToInt32(double val) | |
| { | |
| if (val > 0x7FFFFFFF) | |
| return 0x7FFFFFFF; | |
| if (val < -0x7FFFFFFF - 1 || isnan(val)) | |
| return -0x7FFFFFFF - 1; | |
| return (int32_t)val; | |
| } | |
| static uint8_t TIFFClampDoubleToUInt8(double val) | |
| { | |
| if (val < 0) | |
| return 0; | |
| if (val > 255 || isnan(val)) | |
| return 255; | |
| return (uint8_t)val; | |
| } | |
| static uint16_t TIFFClampDoubleToUInt16(double val) | |
| { | |
| if (val < 0) | |
| return 0; | |
| if (val > 65535 || isnan(val)) | |
| return 65535; | |
| return (uint16_t)val; | |
| } | |
| static uint32_t TIFFClampDoubleToUInt32(double val) | |
| { | |
| if (val < 0) | |
| return 0; | |
| if (val > 0xFFFFFFFFU || isnan(val)) | |
| return 0xFFFFFFFFU; | |
| return (uint32_t)val; | |
| } | |
| static int TIFFWriteDirectoryTagSampleformatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| double *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagSampleformatArray"; | |
| void *conv; | |
| uint32_t i; | |
| int ok; | |
| conv = _TIFFmallocExt(tif, (tmsize_t)((size_t)count * sizeof(double))); | |
| if (conv == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| switch (tif->tif_dir.td_sampleformat) | |
| { | |
| case SAMPLEFORMAT_IEEEFP: | |
| if (tif->tif_dir.td_bitspersample <= 32) | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((float *)conv)[i] = _TIFFClampDoubleToFloat(value[i]); | |
| ok = TIFFWriteDirectoryTagFloatArray(tif, ndir, dir, tag, count, | |
| (float *)conv); | |
| } | |
| else | |
| { | |
| ok = TIFFWriteDirectoryTagDoubleArray(tif, ndir, dir, tag, | |
| count, value); | |
| } | |
| break; | |
| case SAMPLEFORMAT_INT: | |
| if (tif->tif_dir.td_bitspersample <= 8) | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((int8_t *)conv)[i] = TIFFClampDoubleToInt8(value[i]); | |
| ok = TIFFWriteDirectoryTagSbyteArray(tif, ndir, dir, tag, count, | |
| (int8_t *)conv); | |
| } | |
| else if (tif->tif_dir.td_bitspersample <= 16) | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((int16_t *)conv)[i] = TIFFClampDoubleToInt16(value[i]); | |
| ok = TIFFWriteDirectoryTagSshortArray(tif, ndir, dir, tag, | |
| count, (int16_t *)conv); | |
| } | |
| else | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((int32_t *)conv)[i] = TIFFClampDoubleToInt32(value[i]); | |
| ok = TIFFWriteDirectoryTagSlongArray(tif, ndir, dir, tag, count, | |
| (int32_t *)conv); | |
| } | |
| break; | |
| case SAMPLEFORMAT_UINT: | |
| if (tif->tif_dir.td_bitspersample <= 8) | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((uint8_t *)conv)[i] = TIFFClampDoubleToUInt8(value[i]); | |
| ok = TIFFWriteDirectoryTagByteArray(tif, ndir, dir, tag, count, | |
| (uint8_t *)conv); | |
| } | |
| else if (tif->tif_dir.td_bitspersample <= 16) | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((uint16_t *)conv)[i] = TIFFClampDoubleToUInt16(value[i]); | |
| ok = TIFFWriteDirectoryTagShortArray(tif, ndir, dir, tag, count, | |
| (uint16_t *)conv); | |
| } | |
| else | |
| { | |
| for (i = 0; i < count; ++i) | |
| ((uint32_t *)conv)[i] = TIFFClampDoubleToUInt32(value[i]); | |
| ok = TIFFWriteDirectoryTagLongArray(tif, ndir, dir, tag, count, | |
| (uint32_t *)conv); | |
| } | |
| break; | |
| default: | |
| ok = 0; | |
| } | |
| _TIFFfreeExt(tif, conv); | |
| return (ok); | |
| } | |
| static int TIFFWriteDirectoryTagAscii(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, char *value) | |
| { | |
| return ( | |
| TIFFWriteDirectoryTagCheckedAscii(tif, ndir, dir, tag, count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagUndefinedArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint8_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedUndefinedArray(tif, ndir, dir, tag, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagByteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint8_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedByteArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int8_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedSbyteArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagShort(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, value)); | |
| } | |
| static int TIFFWriteDirectoryTagShortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint16_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagShortPerSample(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagShortPerSample"; | |
| uint16_t *m; | |
| uint16_t *na; | |
| uint16_t nb; | |
| int o; | |
| if (dir == NULL) | |
| { | |
| /* only evaluate IFD data size and inc. ndir */ | |
| return (TIFFWriteDirectoryTagCheckedShortArray( | |
| tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, NULL)); | |
| } | |
| m = (uint16_t *)_TIFFmallocExt( | |
| tif, | |
| (tmsize_t)((size_t)tif->tif_dir.td_samplesperpixel * sizeof(uint16_t))); | |
| if (m == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (na = m, nb = 0; nb < tif->tif_dir.td_samplesperpixel; na++, nb++) | |
| *na = value; | |
| o = TIFFWriteDirectoryTagCheckedShortArray( | |
| tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, m); | |
| _TIFFfreeExt(tif, m); | |
| return (o); | |
| } | |
| static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int16_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedSshortArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value)); | |
| } | |
| static int TIFFWriteDirectoryTagLongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint32_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagSlongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int32_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| /************************************************************************/ | |
| /* TIFFWriteDirectoryTagLong8Array() */ | |
| /* */ | |
| /* Write either Long8 or Long array depending on file type. */ | |
| /************************************************************************/ | |
| static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagLong8Array"; | |
| uint64_t *ma; | |
| uint32_t mb; | |
| uint32_t *p; | |
| uint32_t *q; | |
| int o; | |
| /* We always write Long8 for BigTIFF, no checking needed. */ | |
| if (tif->tif_flags & TIFF_BIGTIFF) | |
| return (TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag, | |
| count, value)); | |
| /* | |
| ** For classic tiff we want to verify everything is in range for long | |
| ** and convert to long format. | |
| */ | |
| p = (uint32_t *)_TIFFmallocExt( | |
| tif, (tmsize_t)((size_t)count * sizeof(uint32_t))); | |
| if (p == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) | |
| { | |
| if (*ma > 0xFFFFFFFF) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write unsigned long value %" PRIu64 | |
| " larger than 0xFFFFFFFF for tag %d in Classic TIFF " | |
| "file. TIFF file writing aborted", | |
| *ma, tag); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| *q = (uint32_t)(*ma); | |
| } | |
| o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, p); | |
| _TIFFfreeExt(tif, p); | |
| return (o); | |
| } | |
| /************************************************************************/ | |
| /* TIFFWriteDirectoryTagSlong8Array() */ | |
| /* */ | |
| /* Write either SLong8 or SLong array depending on file type. */ | |
| /************************************************************************/ | |
| static int TIFFWriteDirectoryTagSlong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, int64_t *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagSlong8Array"; | |
| int64_t *ma; | |
| uint32_t mb; | |
| int32_t *p; | |
| int32_t *q; | |
| int o; | |
| /* We always write SLong8 for BigTIFF, no checking needed. */ | |
| if (tif->tif_flags & TIFF_BIGTIFF) | |
| return (TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag, | |
| count, value)); | |
| /* | |
| ** For classic tiff we want to verify everything is in range for signed-long | |
| ** and convert to signed-long format. | |
| */ | |
| p = (int32_t *)_TIFFmallocExt(tif, | |
| (tmsize_t)((size_t)count * sizeof(uint32_t))); | |
| if (p == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) | |
| { | |
| if (*ma > (2147483647)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write signed long value %" PRIi64 | |
| " larger than 0x7FFFFFFF (2147483647) for tag %d in " | |
| "Classic TIFF file. TIFF writing to file aborted", | |
| *ma, tag); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| else if (*ma < (-2147483647 - 1)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write signed long value %" PRIi64 | |
| " smaller than 0x80000000 (-2147483648) for tag %d " | |
| "in Classic TIFF file. TIFF writing to file aborted", | |
| *ma, tag); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| *q = (int32_t)(*ma); | |
| } | |
| o = TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, p); | |
| _TIFFfreeExt(tif, p); | |
| return (o); | |
| } | |
| static int TIFFWriteDirectoryTagRational(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| double value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedRational(tif, ndir, dir, tag, value)); | |
| } | |
| static int TIFFWriteDirectoryTagRationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedRationalArray(tif, ndir, dir, tag, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagSrationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedSrationalArray(tif, ndir, dir, tag, | |
| count, value)); | |
| } | |
| /*-- Rational2Double: additional write functions */ | |
| static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| double *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif, ndir, dir, tag, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| double *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedSrationalDoubleArray( | |
| tif, ndir, dir, tag, count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagFloatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, float *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedFloatArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, double *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedDoubleArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagIfdArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint32_t *value) | |
| { | |
| return (TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count, | |
| value)); | |
| } | |
| static int TIFFWriteDirectoryTagShortLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value) | |
| { | |
| if (value <= 0xFFFF) | |
| return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, | |
| (uint16_t)value)); | |
| else | |
| return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value)); | |
| } | |
| static int _WriteAsType(TIFF *tif, uint64_t strile_size, | |
| uint64_t uncompressed_threshold) | |
| { | |
| const uint16_t compression = tif->tif_dir.td_compression; | |
| if (compression == COMPRESSION_NONE) | |
| { | |
| return strile_size > uncompressed_threshold; | |
| } | |
| else if (compression == COMPRESSION_JPEG || | |
| compression == COMPRESSION_LZW || | |
| compression == COMPRESSION_ADOBE_DEFLATE || | |
| compression == COMPRESSION_DEFLATE || | |
| compression == COMPRESSION_LZMA || | |
| compression == COMPRESSION_LERC || | |
| compression == COMPRESSION_ZSTD || | |
| compression == COMPRESSION_WEBP || compression == COMPRESSION_JXL) | |
| { | |
| /* For a few select compression types, we assume that in the worst */ | |
| /* case the compressed size will be 10 times the uncompressed size. */ | |
| /* This is overly pessismistic ! */ | |
| return strile_size >= uncompressed_threshold / 10; | |
| } | |
| return 1; | |
| } | |
| static int WriteAsLong8(TIFF *tif, uint64_t strile_size) | |
| { | |
| return _WriteAsType(tif, strile_size, 0xFFFFFFFFU); | |
| } | |
| static int WriteAsLong4(TIFF *tif, uint64_t strile_size) | |
| { | |
| return _WriteAsType(tif, strile_size, 0xFFFFU); | |
| } | |
| /************************************************************************/ | |
| /* TIFFWriteDirectoryTagLongLong8Array() */ | |
| /* */ | |
| /* Write out LONG8 array and write a SHORT/LONG/LONG8 depending */ | |
| /* on strile size and Classic/BigTIFF mode. */ | |
| /************************************************************************/ | |
| static int TIFFWriteDirectoryTagLongLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagLongLong8Array"; | |
| int o; | |
| int write_aslong4; | |
| if (tif->tif_dir.td_deferstrilearraywriting) | |
| { | |
| if (dir == NULL) | |
| { | |
| /* This is just a counting pass to count IFD entries. | |
| * For deferstrilearraywriting no extra bytes will be written | |
| * into IFD space. */ | |
| (*ndir)++; | |
| return 1; | |
| } | |
| return TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_NOTYPE, 0, 0, | |
| NULL); | |
| } | |
| if (tif->tif_flags & TIFF_BIGTIFF) | |
| { | |
| int write_aslong8 = 1; | |
| /* In the case of ByteCounts array, we may be able to write them on LONG | |
| * if the strip/tilesize is not too big. Also do that for count > 1 in | |
| * the case someone would want to create a single-strip file with a | |
| * growing height, in which case using LONG8 will be safer. */ | |
| if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS) | |
| { | |
| write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif)); | |
| } | |
| else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS) | |
| { | |
| write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif)); | |
| } | |
| if (write_aslong8) | |
| { | |
| return TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag, | |
| count, value); | |
| } | |
| } | |
| write_aslong4 = 1; | |
| if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS) | |
| { | |
| write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif)); | |
| } | |
| else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS) | |
| { | |
| write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif)); | |
| } | |
| if (write_aslong4) | |
| { | |
| /* | |
| ** For classic tiff we want to verify everything is in range for LONG | |
| ** and convert to long format. | |
| */ | |
| uint32_t *p = (uint32_t *)_TIFFmallocExt( | |
| tif, (tmsize_t)((size_t)count * sizeof(uint32_t))); | |
| uint32_t *q; | |
| uint64_t *ma; | |
| uint32_t mb; | |
| if (p == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) | |
| { | |
| if (*ma > 0xFFFFFFFF) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write value larger than 0xFFFFFFFF " | |
| "in LONG array."); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| *q = (uint32_t)(*ma); | |
| } | |
| o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, | |
| p); | |
| _TIFFfreeExt(tif, p); | |
| } | |
| else | |
| { | |
| uint16_t *p = (uint16_t *)_TIFFmallocExt( | |
| tif, (tmsize_t)((size_t)count * sizeof(uint16_t))); | |
| uint16_t *q; | |
| uint64_t *ma; | |
| uint32_t mb; | |
| if (p == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) | |
| { | |
| if (*ma > 0xFFFF) | |
| { | |
| /* Should not happen normally given the check we did before */ | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write value larger than 0xFFFF in " | |
| "SHORT array."); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| *q = (uint16_t)(*ma); | |
| } | |
| o = TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count, | |
| p); | |
| _TIFFfreeExt(tif, p); | |
| } | |
| return (o); | |
| } | |
| /************************************************************************/ | |
| /* TIFFWriteDirectoryTagIfdIfd8Array() */ | |
| /* */ | |
| /* Write either IFD8 or IFD array depending on file type. */ | |
| /************************************************************************/ | |
| static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint64_t *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array"; | |
| uint64_t *ma; | |
| uint32_t mb; | |
| uint32_t *p; | |
| uint32_t *q; | |
| int o; | |
| /* 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 = (uint32_t *)_TIFFmallocExt( | |
| tif, (tmsize_t)((size_t)count * sizeof(uint32_t))); | |
| if (p == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) | |
| { | |
| if (*ma > 0xFFFFFFFF) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Attempt to write value larger than 0xFFFFFFFF in " | |
| "Classic TIFF file."); | |
| _TIFFfreeExt(tif, p); | |
| return (0); | |
| } | |
| *q = (uint32_t)(*ma); | |
| } | |
| o = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count, p); | |
| _TIFFfreeExt(tif, p); | |
| return (o); | |
| } | |
| /* | |
| * Auxiliary function to determine the IFD data size to be written to the file. | |
| * The IFD data size is finally the size of the IFD tag entries plus the IFD | |
| * data that is written directly after the IFD tag entries. | |
| */ | |
| static void EvaluateIFDdatasizeWrite(TIFF *tif, uint32_t count, | |
| uint32_t typesize, uint32_t *ndir) | |
| { | |
| uint64_t datalength = (uint64_t)count * typesize; | |
| if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U)) | |
| { | |
| /* LibTIFF increments write address to an even offset, thus datalength | |
| * written is also incremented. */ | |
| if (datalength & 1) | |
| datalength++; | |
| tif->tif_dir.td_dirdatasize_write += datalength; | |
| } | |
| (*ndir)++; | |
| } | |
| static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagColormap"; | |
| uint32_t m; | |
| uint32_t count; | |
| uint64_t count64; | |
| tmsize_t total_values; | |
| tmsize_t plane_bytes; | |
| uint16_t *n; | |
| int o; | |
| if (tif->tif_dir.td_bitspersample >= 32) | |
| { | |
| TIFFErrorExtR(tif, module, "BitsPerSample too large for Colormap"); | |
| return (0); | |
| } | |
| m = 1U << tif->tif_dir.td_bitspersample; | |
| count64 = _TIFFMultiply64(tif, 3U, m, module); | |
| if (count64 == 0) | |
| return (0); | |
| count = _TIFFCastUInt64ToUInt32(tif, count64, module); | |
| total_values = _TIFFCastUInt64ToSSize(tif, count64, module); | |
| plane_bytes = _TIFFCastUInt64ToSSize( | |
| tif, _TIFFMultiply64(tif, m, sizeof(uint16_t), module), module); | |
| if (count == 0 || total_values == 0 || plane_bytes == 0) | |
| return (0); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, sizeof(uint16_t), ndir); | |
| return 1; | |
| } | |
| n = (uint16_t *)_TIFFCheckMalloc(tif, total_values, sizeof(uint16_t), | |
| module); | |
| if (n == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| _TIFFmemcpy(&n[0], tif->tif_dir.td_colormap[0], plane_bytes); | |
| _TIFFmemcpy(&n[m], tif->tif_dir.td_colormap[1], plane_bytes); | |
| _TIFFmemcpy(&n[2 * m], tif->tif_dir.td_colormap[2], plane_bytes); | |
| o = TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, TIFFTAG_COLORMAP, | |
| count, n); | |
| _TIFFfreeExt(tif, n); | |
| return (o); | |
| } | |
| static int TIFFWriteDirectoryTagTransferfunction(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagTransferfunction"; | |
| uint32_t m; | |
| uint32_t count; | |
| uint64_t count64; | |
| tmsize_t total_values; | |
| tmsize_t plane_bytes; | |
| uint16_t n; | |
| uint16_t *o; | |
| int p; | |
| /* TIFFTAG_TRANSFERFUNCTION expects (1 or 3) pointer to arrays with | |
| * 2**BitsPerSample uint16_t values. | |
| */ | |
| if (tif->tif_dir.td_bitspersample >= 32) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "BitsPerSample too large for TransferFunction"); | |
| return (0); | |
| } | |
| m = 1U << tif->tif_dir.td_bitspersample; | |
| plane_bytes = _TIFFCastUInt64ToSSize( | |
| tif, _TIFFMultiply64(tif, m, sizeof(uint16_t), module), module); | |
| if (plane_bytes == 0) | |
| return (0); | |
| /* clang-format off */ | |
| n = (tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples) > 1 ? 3 : 1; | |
| /* clang-format on */ | |
| /* Check for proper number of transferfunctions */ | |
| for (int i = 0; i < n; i++) | |
| { | |
| if (tif->tif_dir.td_transferfunction[i] == NULL) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Too few TransferFunctions provided. Tag " | |
| "not written to file"); | |
| return (1); /* Not an error; only tag is not written. */ | |
| } | |
| } | |
| /* | |
| * Check if the table can be written as a single column, | |
| * or if it must be written as 3 columns. Note that we | |
| * write a 3-column tag if there are 2 samples/pixel and | |
| * a single column of data won't suffice--hmm. | |
| */ | |
| if (n == 3) | |
| { | |
| if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0], | |
| tif->tif_dir.td_transferfunction[2], plane_bytes) && | |
| !_TIFFmemcmp(tif->tif_dir.td_transferfunction[0], | |
| tif->tif_dir.td_transferfunction[1], plane_bytes)) | |
| n = 1; | |
| } | |
| count64 = _TIFFMultiply64(tif, n, m, module); | |
| if (count64 == 0) | |
| return (0); | |
| count = _TIFFCastUInt64ToUInt32(tif, count64, module); | |
| total_values = _TIFFCastUInt64ToSSize(tif, count64, module); | |
| if (count == 0 || total_values == 0) | |
| return (0); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 2, ndir); | |
| return 1; | |
| } | |
| o = (uint16_t *)_TIFFCheckMalloc(tif, total_values, sizeof(uint16_t), | |
| module); | |
| if (o == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| _TIFFmemcpy(&o[0], tif->tif_dir.td_transferfunction[0], plane_bytes); | |
| if (n > 1) | |
| _TIFFmemcpy(&o[m], tif->tif_dir.td_transferfunction[1], plane_bytes); | |
| if (n > 2) | |
| _TIFFmemcpy(&o[2 * m], tif->tif_dir.td_transferfunction[2], | |
| plane_bytes); | |
| p = TIFFWriteDirectoryTagCheckedShortArray( | |
| tif, ndir, dir, TIFFTAG_TRANSFERFUNCTION, count, o); | |
| _TIFFfreeExt(tif, o); | |
| return (p); | |
| } | |
| static int TIFFWriteDirectoryTagSubifd(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagSubifd"; | |
| uint64_t m; | |
| int n; | |
| if (tif->tif_dir.td_nsubifd == 0) | |
| return (1); | |
| m = tif->tif_dataoff; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t *o; | |
| uint64_t *pa; | |
| uint32_t *pb; | |
| uint16_t p; | |
| o = (uint32_t *)_TIFFmallocExt( | |
| tif, | |
| (tmsize_t)((size_t)tif->tif_dir.td_nsubifd * sizeof(uint32_t))); | |
| if (o == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| pa = tif->tif_dir.td_subifd; | |
| pb = o; | |
| for (p = 0; p < tif->tif_dir.td_nsubifd; p++) | |
| { | |
| assert(pa != 0); | |
| /* Could happen if an classicTIFF has a SubIFD of type LONG8 (which | |
| * is illegal) */ | |
| if (*pa > 0xFFFFFFFFUL) | |
| { | |
| TIFFErrorExtR(tif, module, "Illegal value for SubIFD tag"); | |
| _TIFFfreeExt(tif, o); | |
| return (0); | |
| } | |
| *pb++ = (uint32_t)(*pa++); | |
| } | |
| n = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, TIFFTAG_SUBIFD, | |
| tif->tif_dir.td_nsubifd, o); | |
| _TIFFfreeExt(tif, o); | |
| } | |
| else | |
| n = TIFFWriteDirectoryTagCheckedIfd8Array( | |
| tif, ndir, dir, TIFFTAG_SUBIFD, tif->tif_dir.td_nsubifd, | |
| tif->tif_dir.td_subifd); | |
| if (dir == NULL) | |
| /* Just have evaluated IFD data size and incremented ndir | |
| * above in sub-functions. */ | |
| return (n); | |
| if (!n) | |
| return (0); | |
| /* | |
| * Total hack: if this directory includes a SubIFD | |
| * tag then force the next <n> directories to be | |
| * written as ``sub directories'' of this one. This | |
| * is used to write things like thumbnails and | |
| * image masks that one wants to keep out of the | |
| * normal directory linkage access mechanism. | |
| */ | |
| tif->tif_flags |= TIFF_INSUBIFD; | |
| tif->tif_nsubifd = tif->tif_dir.td_nsubifd; | |
| if (tif->tif_dir.td_nsubifd == 1) | |
| tif->tif_subifdoff = 0; | |
| else | |
| tif->tif_subifdoff = m; | |
| return (1); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedAscii(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, char *value) | |
| { | |
| assert(sizeof(char) == 1); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 1, ndir); | |
| return 1; | |
| } | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_ASCII, count, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| uint8_t *value) | |
| { | |
| assert(sizeof(uint8_t) == 1); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 1, ndir); | |
| return 1; | |
| } | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_UNDEFINED, | |
| count, count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedByteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint8_t *value) | |
| { | |
| assert(sizeof(uint8_t) == 1); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 1, ndir); | |
| return 1; | |
| } | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_BYTE, count, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int8_t *value) | |
| { | |
| assert(sizeof(int8_t) == 1); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 1, ndir); | |
| return 1; | |
| } | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SBYTE, count, | |
| count, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedShort(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t value) | |
| { | |
| uint16_t m; | |
| assert(sizeof(uint16_t) == 2); | |
| if (dir == NULL) | |
| { | |
| /* No additional data to IFD data size just increment ndir. */ | |
| (*ndir)++; | |
| return 1; | |
| } | |
| m = value; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&m); | |
| return ( | |
| TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, 1, 2, &m)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedShortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint16_t *value) | |
| { | |
| assert(count < 0x80000000); | |
| assert(sizeof(uint16_t) == 2); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 2, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfShort(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, count, | |
| count * 2, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int16_t *value) | |
| { | |
| assert(count < 0x80000000); | |
| assert(sizeof(int16_t) == 2); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 2, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfShort((uint16_t *)value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SSHORT, count, | |
| count * 2, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedLong(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t value) | |
| { | |
| uint32_t m; | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir == NULL) | |
| { | |
| /* No additional data to IFD data size just increment ndir. */ | |
| (*ndir)++; | |
| return 1; | |
| } | |
| m = value; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&m); | |
| return ( | |
| TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, 1, 4, &m)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedLongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint32_t *value) | |
| { | |
| assert(count < 0x40000000); | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 4, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, count, | |
| count * 4, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int32_t *value) | |
| { | |
| assert(count < 0x40000000); | |
| assert(sizeof(int32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 4, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG, count, | |
| count * 4, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint64_t *value) | |
| { | |
| assert(count < 0x20000000); | |
| assert(sizeof(uint64_t) == 8); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| TIFFErrorExtR(tif, "TIFFWriteDirectoryTagCheckedLong8Array", | |
| "LONG8 not allowed for ClassicTIFF"); | |
| return (0); | |
| } | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 8, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG8, count, | |
| count * 8, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| int64_t *value) | |
| { | |
| assert(count < 0x20000000); | |
| assert(sizeof(int64_t) == 8); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| TIFFErrorExtR(tif, "TIFFWriteDirectoryTagCheckedSlong8Array", | |
| "SLONG8 not allowed for ClassicTIFF"); | |
| return (0); | |
| } | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 8, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8((uint64_t *)value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG8, count, | |
| count * 8, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedRational(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| double value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagCheckedRational"; | |
| uint32_t m[2]; | |
| assert(sizeof(uint32_t) == 4); | |
| if (value < 0) | |
| { | |
| TIFFErrorExtR(tif, module, "Negative value is illegal"); | |
| return 0; | |
| } | |
| else if (isnan(value)) | |
| { | |
| TIFFErrorExtR(tif, module, "Not-a-number value is illegal"); | |
| return 0; | |
| } | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| tif->tif_dir.td_dirdatasize_write += | |
| (tif->tif_flags & TIFF_BIGTIFF) ? 0 : 0x8U; | |
| (*ndir)++; | |
| return 1; | |
| } | |
| DoubleToRational(value, &m[0], &m[1]); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| { | |
| TIFFSwabLong(&m[0]); | |
| TIFFSwabLong(&m[1]); | |
| } | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, 1, 8, | |
| &m[0])); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| float *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray"; | |
| uint32_t *m; | |
| float *na; | |
| uint32_t *nb; | |
| uint32_t nc; | |
| int o; | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir); | |
| return 1; | |
| } | |
| m = (uint32_t *)_TIFFCheckMalloc(tif, count, 2 * sizeof(uint32_t), | |
| "for rational array"); | |
| if (m == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) | |
| { | |
| DoubleToRational((double)*na, &nb[0], &nb[1]); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m, count * 2); | |
| o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count, | |
| count * 8, &m[0]); | |
| _TIFFfreeExt(tif, m); | |
| return (o); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, | |
| uint32_t count, | |
| float *value) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray"; | |
| int32_t *m; | |
| float *na; | |
| int32_t *nb; | |
| uint32_t nc; | |
| int o; | |
| assert(sizeof(int32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir); | |
| return 1; | |
| } | |
| m = (int32_t *)_TIFFCheckMalloc(tif, count, 2 * sizeof(int32_t), | |
| "for srational array"); | |
| if (m == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) | |
| { | |
| DoubleToSrational((double)*na, &nb[0], &nb[1]); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)m, count * 2); | |
| o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SRATIONAL, count, | |
| count * 8, &m[0]); | |
| _TIFFfreeExt(tif, m); | |
| return (o); | |
| } | |
| /*-- Rational2Double: additional write functions for double arrays */ | |
| static int | |
| TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, double *value) | |
| { | |
| static const char module[] = | |
| "TIFFWriteDirectoryTagCheckedRationalDoubleArray"; | |
| uint32_t *m; | |
| double *na; | |
| uint32_t *nb; | |
| uint32_t nc; | |
| int o; | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir); | |
| return 1; | |
| } | |
| m = (uint32_t *)_TIFFCheckMalloc(tif, count, 2 * sizeof(uint32_t), | |
| "for rational double array"); | |
| if (m == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) | |
| { | |
| DoubleToRational((double)*na, &nb[0], &nb[1]); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m, count * 2); | |
| o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count, | |
| count * 8, &m[0]); | |
| _TIFFfreeExt(tif, m); | |
| return (o); | |
| } /*-- TIFFWriteDirectoryTagCheckedRationalDoubleArray() ------- */ | |
| static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray( | |
| TIFF *tif, uint32_t *ndir, TIFFDirEntry *dir, uint16_t tag, uint32_t count, | |
| double *value) | |
| { | |
| static const char module[] = | |
| "TIFFWriteDirectoryTagCheckedSrationalDoubleArray"; | |
| int32_t *m; | |
| double *na; | |
| int32_t *nb; | |
| uint32_t nc; | |
| int o; | |
| assert(sizeof(int32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir); | |
| return 1; | |
| } | |
| m = (int32_t *)_TIFFCheckMalloc(tif, count, 2 * sizeof(int32_t), | |
| "for srational double array"); | |
| if (m == NULL) | |
| { | |
| TIFFErrorExtR(tif, module, "Out of memory"); | |
| return (0); | |
| } | |
| for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) | |
| { | |
| DoubleToSrational((double)*na, &nb[0], &nb[1]); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)m, count * 2); | |
| o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SRATIONAL, count, | |
| count * 8, &m[0]); | |
| _TIFFfreeExt(tif, m); | |
| return (o); | |
| } /*--- TIFFWriteDirectoryTagCheckedSrationalDoubleArray() -------- */ | |
| /** ----- Rational2Double: Double To Rational Conversion | |
| ---------------------------------------------------------- | |
| * There is a mathematical theorem to convert real numbers into a rational | |
| (integer fraction) number. | |
| * This is called "continuous fraction" which uses the Euclidean algorithm to | |
| find the greatest common divisor (GCD). | |
| * (ref. e.g. https://de.wikipedia.org/wiki/Kettenbruch or | |
| https://en.wikipedia.org/wiki/Continued_fraction | |
| * https://en.wikipedia.org/wiki/Euclidean_algorithm) | |
| * The following functions implement the | |
| * - ToRationalEuclideanGCD() auxiliary function which mainly | |
| implements euclidean GCD | |
| * - DoubleToRational() conversion function for un-signed | |
| rationals | |
| * - DoubleToSrational() conversion function for signed rationals | |
| ------------------------------------------------------------------------------------------------------------------*/ | |
| /**---- ToRationalEuclideanGCD() ----------------------------------------- | |
| * Calculates the rational fractional of a double input value | |
| * using the Euclidean algorithm to find the greatest common divisor (GCD) | |
| ------------------------------------------------------------------------*/ | |
| static void ToRationalEuclideanGCD(double value, int blnUseSignedRange, | |
| int blnUseSmallRange, uint64_t *ullNum, | |
| uint64_t *ullDenom) | |
| { | |
| /* Internally, the integer variables can be bigger than the external ones, | |
| * as long as the result will fit into the external variable size. | |
| */ | |
| uint64_t numSum[3] = {0, 1, 0}, denomSum[3] = {1, 0, 0}; | |
| uint64_t aux, bigNum, bigDenom; | |
| uint64_t returnLimit; | |
| int i; | |
| uint64_t nMax; | |
| double fMax; | |
| unsigned long maxDenom; | |
| /*-- nMax and fMax defines the initial accuracy of the starting fractional, | |
| * or better, the highest used integer numbers used within the starting | |
| * fractional (bigNum/bigDenom). There are two approaches, which can | |
| * accidentally lead to different accuracies just depending on the value. | |
| * Therefore, blnUseSmallRange steers this behavior. | |
| * For long long nMax = ((9223372036854775807-1)/2); for long nMax = | |
| * ((2147483647-1)/2); | |
| */ | |
| if (blnUseSmallRange) | |
| { | |
| nMax = (uint64_t)((2147483647 - 1) / 2); /* for ULONG range */ | |
| } | |
| else | |
| { | |
| nMax = ((9223372036854775807 - 1) / 2); /* for ULLONG range */ | |
| } | |
| fMax = (double)nMax; | |
| /*-- For the Euclidean GCD define the denominator range, so that it stays | |
| * within size of unsigned long variables. maxDenom should be LONG_MAX for | |
| * negative values and ULONG_MAX for positive ones. Also the final returned | |
| * value of ullNum and ullDenom is limited according to signed- or | |
| * unsigned-range. | |
| */ | |
| if (blnUseSignedRange) | |
| { | |
| maxDenom = 2147483647UL; /*LONG_MAX = 0x7FFFFFFFUL*/ | |
| returnLimit = maxDenom; | |
| } | |
| else | |
| { | |
| maxDenom = 0xFFFFFFFFUL; /*ULONG_MAX = 0xFFFFFFFFUL*/ | |
| returnLimit = maxDenom; | |
| } | |
| /*-- First generate a rational fraction (bigNum/bigDenom) which represents | |
| *the value as a rational number with the highest accuracy. Therefore, | |
| *uint64_t (uint64_t) is needed. This rational fraction is then reduced | |
| *using the Euclidean algorithm to find the greatest common divisor (GCD). | |
| * bigNum = big numinator of value without fraction (or cut residual | |
| *fraction) bigDenom = big denominator of value | |
| *-- Break-criteria so that uint64_t cast to "bigNum" introduces no error | |
| *and bigDenom has no overflow, and stop with enlargement of fraction when | |
| *the double-value of it reaches an integer number without fractional part. | |
| */ | |
| bigDenom = 1; | |
| while ((!TIFF_DOUBLE_EQ(value, floor(value))) && (value < fMax) && | |
| (bigDenom < nMax)) | |
| { | |
| bigDenom <<= 1; | |
| value *= 2; | |
| } | |
| bigNum = (uint64_t)value; | |
| /*-- Start Euclidean algorithm to find the greatest common divisor (GCD) -- | |
| */ | |
| #define MAX_ITERATIONS 64 | |
| for (i = 0; i < MAX_ITERATIONS; i++) | |
| { | |
| uint64_t val; | |
| /* if bigDenom is not zero, calculate integer part of fraction. */ | |
| if (bigDenom == 0) | |
| { | |
| break; | |
| } | |
| val = bigNum / bigDenom; | |
| /* Set bigDenom to reminder of bigNum/bigDenom and bigNum to previous | |
| * denominator bigDenom. */ | |
| aux = bigNum; | |
| bigNum = bigDenom; | |
| bigDenom = aux % bigDenom; | |
| /* calculate next denominator and check for its given maximum */ | |
| aux = val; | |
| if (denomSum[1] * val + denomSum[0] >= maxDenom) | |
| { | |
| aux = (maxDenom - denomSum[0]) / denomSum[1]; | |
| if (aux * 2 >= val || denomSum[1] >= maxDenom) | |
| i = (MAX_ITERATIONS + | |
| 1); /* exit but execute rest of for-loop */ | |
| else | |
| break; | |
| } | |
| /* calculate next numerator to numSum2 and save previous one to numSum0; | |
| * numSum1 just copy of numSum2. */ | |
| numSum[2] = aux * numSum[1] + numSum[0]; | |
| numSum[0] = numSum[1]; | |
| numSum[1] = numSum[2]; | |
| /* calculate next denominator to denomSum2 and save previous one to | |
| * denomSum0; denomSum1 just copy of denomSum2. */ | |
| denomSum[2] = aux * denomSum[1] + denomSum[0]; | |
| denomSum[0] = denomSum[1]; | |
| denomSum[1] = denomSum[2]; | |
| } | |
| /*-- Check and adapt for final variable size and return values; reduces | |
| * internal accuracy; denominator is kept in ULONG-range with maxDenom -- */ | |
| while (numSum[1] > returnLimit || denomSum[1] > returnLimit) | |
| { | |
| numSum[1] = numSum[1] / 2; | |
| denomSum[1] = denomSum[1] / 2; | |
| } | |
| /* return values */ | |
| *ullNum = numSum[1]; | |
| *ullDenom = denomSum[1]; | |
| } /*-- ToRationalEuclideanGCD() -------------- */ | |
| /**---- DoubleToRational() ----------------------------------------------- | |
| * Calculates the rational fractional of a double input value | |
| * for UN-SIGNED rationals, | |
| * using the Euclidean algorithm to find the greatest common divisor (GCD) | |
| ------------------------------------------------------------------------*/ | |
| static void DoubleToRational(double value, uint32_t *num, uint32_t *denom) | |
| { | |
| /*---- UN-SIGNED RATIONAL ---- */ | |
| double dblDiff, dblDiff2; | |
| uint64_t ullNum, ullDenom, ullNum2, ullDenom2; | |
| /*-- Check for negative values. If so it is an error. */ | |
| /* Test written that way to catch NaN */ | |
| if (!(value >= 0)) | |
| { | |
| *num = *denom = 0; | |
| TIFFErrorExt(0, "TIFFLib: DoubleToRational()", | |
| " Negative Value for Unsigned Rational given."); | |
| return; | |
| } | |
| /*-- Check for too big numbers (> ULONG_MAX) -- */ | |
| if (value > 0xFFFFFFFFUL) | |
| { | |
| *num = 0xFFFFFFFFU; | |
| *denom = 0; | |
| return; | |
| } | |
| /*-- Check for easy integer numbers -- */ | |
| if (TIFF_DOUBLE_EQ(value, (double)(uint32_t)value)) | |
| { | |
| *num = (uint32_t)value; | |
| *denom = 1; | |
| return; | |
| } | |
| /*-- Check for too small numbers for "unsigned long" type rationals -- */ | |
| if (value < 1.0 / (double)0xFFFFFFFFUL) | |
| { | |
| *num = 0; | |
| *denom = 0xFFFFFFFFU; | |
| return; | |
| } | |
| /*-- There are two approaches using the Euclidean algorithm, | |
| * which can accidentally lead to different accuracies just depending on | |
| * the value. Try both and define which one was better. | |
| */ | |
| ToRationalEuclideanGCD(value, FALSE, FALSE, &ullNum, &ullDenom); | |
| ToRationalEuclideanGCD(value, FALSE, TRUE, &ullNum2, &ullDenom2); | |
| /*-- Double-Check, that returned values fit into ULONG :*/ | |
| if (ullNum > 0xFFFFFFFFUL || ullDenom > 0xFFFFFFFFUL || | |
| ullNum2 > 0xFFFFFFFFUL || ullDenom2 > 0xFFFFFFFFUL) | |
| { | |
| TIFFErrorExt(0, "TIFFLib: DoubleToRational()", | |
| " Num or Denom exceeds ULONG: val=%14.6f, num=%12" PRIu64 | |
| ", denom=%12" PRIu64 " | num2=%12" PRIu64 | |
| ", denom2=%12" PRIu64 "", | |
| value, ullNum, ullDenom, ullNum2, ullDenom2); | |
| assert(0); | |
| } | |
| /* Check, which one has higher accuracy and take that. */ | |
| dblDiff = fabs(value - ((double)ullNum / (double)ullDenom)); | |
| dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2)); | |
| if (dblDiff < dblDiff2) | |
| { | |
| *num = (uint32_t)ullNum; | |
| *denom = (uint32_t)ullDenom; | |
| } | |
| else | |
| { | |
| *num = (uint32_t)ullNum2; | |
| *denom = (uint32_t)ullDenom2; | |
| } | |
| } /*-- DoubleToRational() -------------- */ | |
| /**---- DoubleToSrational() ----------------------------------------------- | |
| * Calculates the rational fractional of a double input value | |
| * for SIGNED rationals, | |
| * using the Euclidean algorithm to find the greatest common divisor (GCD) | |
| ------------------------------------------------------------------------*/ | |
| static void DoubleToSrational(double value, int32_t *num, int32_t *denom) | |
| { | |
| /*---- SIGNED RATIONAL ----*/ | |
| int neg = 1; | |
| double dblDiff, dblDiff2; | |
| uint64_t ullNum, ullDenom, ullNum2, ullDenom2; | |
| /*-- Check for negative values and use then the positive one for internal | |
| * calculations, but take the sign into account before returning. */ | |
| if (value < 0) | |
| { | |
| neg = -1; | |
| value = -value; | |
| } | |
| /*-- Check for too big numbers (> LONG_MAX) -- */ | |
| if (value > 0x7FFFFFFFL) | |
| { | |
| *num = 0x7FFFFFFFL; | |
| *denom = 0; | |
| return; | |
| } | |
| /*-- Check for easy numbers -- */ | |
| if (TIFF_DOUBLE_EQ(value, (double)(int32_t)value)) | |
| { | |
| *num = (int32_t)(neg * value); | |
| *denom = 1; | |
| return; | |
| } | |
| /*-- Check for too small numbers for "long" type rationals -- */ | |
| if (value < 1.0 / (double)0x7FFFFFFFL) | |
| { | |
| *num = 0; | |
| *denom = 0x7FFFFFFFL; | |
| return; | |
| } | |
| /*-- There are two approaches using the Euclidean algorithm, | |
| * which can accidentally lead to different accuracies just depending on | |
| * the value. Try both and define which one was better. Furthermore, set | |
| * behavior of ToRationalEuclideanGCD() to the range of signed-long. | |
| */ | |
| ToRationalEuclideanGCD(value, TRUE, FALSE, &ullNum, &ullDenom); | |
| ToRationalEuclideanGCD(value, TRUE, TRUE, &ullNum2, &ullDenom2); | |
| /*-- Double-Check, that returned values fit into LONG :*/ | |
| if (ullNum > 0x7FFFFFFFL || ullDenom > 0x7FFFFFFFL || | |
| ullNum2 > 0x7FFFFFFFL || ullDenom2 > 0x7FFFFFFFL) | |
| { | |
| TIFFErrorExt(0, "TIFFLib: DoubleToSrational()", | |
| " Num or Denom exceeds LONG: val=%14.6f, num=%12" PRIu64 | |
| ", denom=%12" PRIu64 " | num2=%12" PRIu64 | |
| ", denom2=%12" PRIu64 "", | |
| neg * value, ullNum, ullDenom, ullNum2, ullDenom2); | |
| assert(0); | |
| } | |
| /* Check, which one has higher accuracy and take that. */ | |
| dblDiff = fabs(value - ((double)ullNum / (double)ullDenom)); | |
| dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2)); | |
| if (dblDiff < dblDiff2) | |
| { | |
| *num = (int32_t)(neg * (long)ullNum); | |
| *denom = (int32_t)ullDenom; | |
| } | |
| else | |
| { | |
| *num = (int32_t)(neg * (long)ullNum2); | |
| *denom = (int32_t)ullDenom2; | |
| } | |
| } /*-- DoubleToSrational() --------------*/ | |
| static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| float *value) | |
| { | |
| assert(count < 0x40000000); | |
| assert(sizeof(float) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 4, ndir); | |
| return 1; | |
| } | |
| TIFFCvtNativeToIEEEFloat(tif, count, value); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfFloat(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_FLOAT, count, | |
| count * 4, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| double *value) | |
| { | |
| assert(count < 0x20000000); | |
| assert(sizeof(double) == 8); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 8, ndir); | |
| return 1; | |
| } | |
| TIFFCvtNativeToIEEEDouble(tif, count, value); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfDouble(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_DOUBLE, count, | |
| count * 8, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint32_t count, uint32_t *value) | |
| { | |
| assert(count < 0x40000000); | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 4, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD, count, | |
| count * 4, value)); | |
| } | |
| static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, | |
| uint16_t tag, uint32_t count, | |
| uint64_t *value) | |
| { | |
| assert(count < 0x20000000); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(tif->tif_flags & TIFF_BIGTIFF); | |
| if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ | |
| { | |
| EvaluateIFDdatasizeWrite(tif, count, 8, ndir); | |
| return 1; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8(value, count); | |
| return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD8, count, | |
| count * 8, value)); | |
| } | |
| static int TIFFWriteDirectoryTagData(TIFF *tif, uint32_t *ndir, | |
| TIFFDirEntry *dir, uint16_t tag, | |
| uint16_t datatype, uint32_t count, | |
| uint32_t datalength, void *data) | |
| { | |
| static const char module[] = "TIFFWriteDirectoryTagData"; | |
| uint32_t m; | |
| m = 0; | |
| while (m < (*ndir)) | |
| { | |
| assert(dir[m].tdir_tag != tag); | |
| if (dir[m].tdir_tag > tag) | |
| break; | |
| m++; | |
| } | |
| if (m < (*ndir)) | |
| { | |
| uint32_t n; | |
| for (n = *ndir; n > m; n--) | |
| dir[n] = dir[n - 1]; | |
| } | |
| dir[m].tdir_tag = tag; | |
| dir[m].tdir_type = datatype; | |
| dir[m].tdir_count = count; | |
| dir[m].tdir_offset.toff_long8 = 0; | |
| if (datalength <= ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U)) | |
| { | |
| if (data && datalength) | |
| { | |
| _TIFFmemcpy(&dir[m].tdir_offset, data, datalength); | |
| } | |
| } | |
| else | |
| { | |
| uint64_t na, nb; | |
| na = tif->tif_dataoff; | |
| nb = na + datalength; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| nb = (uint32_t)nb; | |
| if ((nb < na) || (nb < datalength)) | |
| { | |
| TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); | |
| return (0); | |
| } | |
| if (!SeekOK(tif, na)) | |
| { | |
| TIFFErrorExtR(tif, module, "IO error writing tag data"); | |
| return (0); | |
| } | |
| if (datalength >= 0x80000000UL) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "libtiff does not allow writing more than 2147483647 " | |
| "bytes in a tag"); | |
| return (0); | |
| } | |
| if (!WriteOK(tif, data, (tmsize_t)datalength)) | |
| { | |
| TIFFErrorExtR(tif, module, "IO error writing tag data"); | |
| return (0); | |
| } | |
| tif->tif_dataoff = nb; | |
| if (tif->tif_dataoff & 1) | |
| tif->tif_dataoff++; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t o; | |
| o = (uint32_t)na; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&o); | |
| _TIFFmemcpy(&dir[m].tdir_offset, &o, 4); | |
| } | |
| else | |
| { | |
| dir[m].tdir_offset.toff_long8 = na; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&dir[m].tdir_offset.toff_long8); | |
| } | |
| } | |
| (*ndir)++; | |
| return (1); | |
| } | |
| /* | |
| * Link the current directory into the directory chain for the file. | |
| */ | |
| static int TIFFLinkDirectory(TIFF *tif) | |
| { | |
| static const char module[] = "TIFFLinkDirectory"; | |
| tif->tif_diroff = (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1)); | |
| /* | |
| * Handle SubIFDs | |
| */ | |
| if (tif->tif_flags & TIFF_INSUBIFD) | |
| { | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t m; | |
| m = (uint32_t)tif->tif_diroff; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&m); | |
| (void)TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); | |
| if (!WriteOK(tif, &m, 4)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error writing SubIFD directory link"); | |
| return (0); | |
| } | |
| /* | |
| * Advance to the next SubIFD or, if this is | |
| * the last one configured, reverting back to the | |
| * normal directory linkage is done in TIFFWriteDirectorySec() | |
| * by tif->tif_flags &= ~TIFF_INSUBIFD;. | |
| */ | |
| if (--tif->tif_nsubifd) | |
| tif->tif_subifdoff += 4; | |
| return (1); | |
| } | |
| else | |
| { | |
| uint64_t m; | |
| m = tif->tif_diroff; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&m); | |
| (void)TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); | |
| if (!WriteOK(tif, &m, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Error writing SubIFD directory link"); | |
| return (0); | |
| } | |
| /* | |
| * Advance to the next SubIFD or, if this is | |
| * the last one configured, reverting back to the | |
| * normal directory linkage is done in TIFFWriteDirectorySec() | |
| * by tif->tif_flags &= ~TIFF_INSUBIFD;. | |
| */ | |
| if (--tif->tif_nsubifd) | |
| tif->tif_subifdoff += 8; | |
| return (1); | |
| } | |
| } | |
| /* | |
| * Handle main-IFDs | |
| */ | |
| tdir_t ndir = 1; /* count current number of main-IFDs */ | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t m; | |
| uint32_t nextdir; | |
| m = (uint32_t)(tif->tif_diroff); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&m); | |
| if (tif->tif_header.classic.tiff_diroff == 0) | |
| { | |
| /* | |
| * First directory, overwrite offset in header. | |
| */ | |
| tif->tif_header.classic.tiff_diroff = (uint32_t)tif->tif_diroff; | |
| tif->tif_lastdiroff = tif->tif_diroff; | |
| (void)TIFFSeekFile(tif, 4, SEEK_SET); | |
| if (!WriteOK(tif, &m, 4)) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); | |
| return (0); | |
| } | |
| if (!tif->tif_dir.td_iswrittentofile) | |
| tif->tif_curdircount = 0; | |
| return (1); | |
| } | |
| /* | |
| * Not the first directory, search to the last and append. | |
| */ | |
| tdir_t dirn = 0; | |
| if (tif->tif_lastdiroff != 0 && | |
| _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn)) | |
| { | |
| /* Start searching from the lastely written IFD. Thus get its IFD | |
| * number. */ | |
| nextdir = (uint32_t)tif->tif_lastdiroff; | |
| ndir = dirn + 1; | |
| } | |
| else | |
| { | |
| nextdir = tif->tif_header.classic.tiff_diroff; | |
| ndir = 1; /* start searching from the first IFD */ | |
| } | |
| while (1) | |
| { | |
| uint16_t dircount; | |
| uint32_t nextnextdir; | |
| /* Update IDF loop list and check for IFD loop. | |
| * ndir is IFD ID plus one. */ | |
| if (!_TIFFCheckDirNumberAndOffset(tif, ndir - 1, nextdir)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error IFD loop detected"); | |
| return 0; /* bad offset (IFD looping or more than | |
| TIFF_MAX_DIR_COUNT IFDs) */ | |
| } | |
| if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, 2)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory count"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&dircount); | |
| (void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12U, SEEK_SET); | |
| if (!ReadOK(tif, &nextnextdir, 4)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory link"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&nextnextdir); | |
| if (nextnextdir == 0) | |
| { | |
| (void)TIFFSeekFile(tif, nextdir + 2 + dircount * 12U, SEEK_SET); | |
| if (!WriteOK(tif, &m, 4)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error writing directory link"); | |
| return (0); | |
| } | |
| tif->tif_lastdiroff = tif->tif_diroff; | |
| break; | |
| } | |
| nextdir = nextnextdir; | |
| ndir++; | |
| } | |
| } | |
| else | |
| { | |
| /*- BigTIFF -*/ | |
| uint64_t m; | |
| uint64_t nextdir; | |
| m = tif->tif_diroff; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&m); | |
| if (tif->tif_header.big.tiff_diroff == 0) | |
| { | |
| /* | |
| * First directory, overwrite offset in header. | |
| */ | |
| tif->tif_header.big.tiff_diroff = tif->tif_diroff; | |
| tif->tif_lastdiroff = tif->tif_diroff; | |
| (void)TIFFSeekFile(tif, 8, SEEK_SET); | |
| if (!WriteOK(tif, &m, 8)) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); | |
| return (0); | |
| } | |
| if (!tif->tif_dir.td_iswrittentofile) | |
| tif->tif_curdircount = 0; | |
| return (1); | |
| } | |
| /* | |
| * Not the first directory, search to the last and append. | |
| */ | |
| tdir_t dirn = 0; | |
| if (tif->tif_lastdiroff != 0 && | |
| _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn)) | |
| { | |
| /* Start searching from the lastely written IFD. Thus get its IFD | |
| * number. */ | |
| nextdir = tif->tif_lastdiroff; | |
| ndir = dirn + 1; | |
| } | |
| else | |
| { | |
| nextdir = tif->tif_header.big.tiff_diroff; | |
| ndir = 1; /* start searching from the first IFD */ | |
| } | |
| while (1) | |
| { | |
| uint64_t dircount64; | |
| uint64_t nextnextdir; | |
| /* Update IDF loop list and check for IFD loop. */ | |
| if (!_TIFFCheckDirNumberAndOffset(tif, ndir - 1, nextdir)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error IFD loop detected"); | |
| return 0; /* bad offset (IFD looping or more than | |
| TIFF_MAX_DIR_COUNT IFDs) */ | |
| } | |
| if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount64, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory count"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&dircount64); | |
| if (dircount64 > 0xFFFF) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on tag count failed, " | |
| "likely corrupt TIFF"); | |
| return (0); | |
| } | |
| (void)TIFFSeekFile(tif, nextdir + 8 + dircount64 * 20, SEEK_SET); | |
| if (!ReadOK(tif, &nextnextdir, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error fetching directory link"); | |
| return (0); | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&nextnextdir); | |
| if (nextnextdir == 0) | |
| { | |
| (void)TIFFSeekFile(tif, nextdir + 8 + dircount64 * 20, | |
| SEEK_SET); | |
| if (!WriteOK(tif, &m, 8)) | |
| { | |
| TIFFErrorExtR(tif, module, "Error writing directory link"); | |
| return (0); | |
| } | |
| tif->tif_lastdiroff = tif->tif_diroff; | |
| break; | |
| } | |
| nextdir = nextnextdir; | |
| ndir++; | |
| } | |
| } | |
| /* Offset of next IFD is written to file. | |
| * Update number of main-IFDs in file. | |
| * However, tif_curdircount shall count only newly written main-IFDs with | |
| * entries and not only number of linked offsets! Thus, tif_curdircount is | |
| * incremented at the end of TIFFWriteDirectorySec(). | |
| * TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs' | |
| * 0 means 'empty file opened for writing, but no IFD written yet' */ | |
| if (!tif->tif_dir.td_iswrittentofile && !(tif->tif_flags & TIFF_INSUBIFD)) | |
| { | |
| tif->tif_curdircount = ndir; | |
| } | |
| return (1); | |
| } | |
| /************************************************************************/ | |
| /* TIFFRewriteField() */ | |
| /* */ | |
| /* Rewrite a field in the directory on disk without regard to */ | |
| /* updating the TIFF directory structure in memory. Currently */ | |
| /* only supported for field that already exist in the on-disk */ | |
| /* directory. Mainly used for updating stripoffset / */ | |
| /* stripbytecount values after the directory is already on */ | |
| /* disk. */ | |
| /* */ | |
| /* Returns zero on failure, and one on success. */ | |
| /************************************************************************/ | |
| int _TIFFRewriteField(TIFF *tif, uint16_t tag, TIFFDataType in_datatype, | |
| tmsize_t count, void *data) | |
| { | |
| static const char module[] = "TIFFResetField"; | |
| /* const TIFFField* fip = NULL; */ | |
| uint16_t dircount; | |
| tmsize_t dirsize; | |
| uint8_t direntry_raw[20]; | |
| uint16_t entry_tag = 0; | |
| uint16_t entry_type = 0; | |
| uint64_t entry_count = 0; | |
| uint64_t entry_offset = 0; | |
| int value_in_entry = 0; | |
| uint64_t read_offset; | |
| uint8_t *buf_to_write = NULL; | |
| TIFFDataType datatype; | |
| /* -------------------------------------------------------------------- */ | |
| /* Find field definition. */ | |
| /* -------------------------------------------------------------------- */ | |
| /*fip =*/TIFFFindField(tif, tag, TIFF_ANY); | |
| /* -------------------------------------------------------------------- */ | |
| /* Do some checking this is a straight forward case. */ | |
| /* -------------------------------------------------------------------- */ | |
| if (isMapped(tif)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Memory mapped files not currently supported for " | |
| "this operation."); | |
| return 0; | |
| } | |
| if (tif->tif_diroff == 0) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Attempt to reset field on directory not already on disk."); | |
| return 0; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Read the directory entry count. */ | |
| /* -------------------------------------------------------------------- */ | |
| if (!SeekOK(tif, tif->tif_diroff)) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Seek error accessing TIFF directory", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| read_offset = tif->tif_diroff; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (!ReadOK(tif, &dircount, sizeof(uint16_t))) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory count", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&dircount); | |
| dirsize = 12; | |
| read_offset += 2; | |
| } | |
| else | |
| { | |
| uint64_t dircount64; | |
| if (!ReadOK(tif, &dircount64, sizeof(uint64_t))) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory count", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&dircount64); | |
| dircount = (uint16_t)dircount64; | |
| dirsize = 20; | |
| read_offset += 8; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Read through directory to find target tag. */ | |
| /* -------------------------------------------------------------------- */ | |
| while (dircount > 0) | |
| { | |
| if (!ReadOK(tif, direntry_raw, dirsize)) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Can not read TIFF directory entry.", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| memcpy(&entry_tag, direntry_raw + 0, sizeof(uint16_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&entry_tag); | |
| if (entry_tag == tag) | |
| break; | |
| read_offset += (uint64_t)dirsize; | |
| } | |
| if (entry_tag != tag) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Could not find tag %" PRIu16 ".", | |
| tif->tif_name, tag); | |
| return 0; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Extract the type, count and offset for this entry. */ | |
| /* -------------------------------------------------------------------- */ | |
| memcpy(&entry_type, direntry_raw + 2, sizeof(uint16_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&entry_type); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t value; | |
| memcpy(&value, direntry_raw + 4, sizeof(uint32_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&value); | |
| entry_count = value; | |
| memcpy(&value, direntry_raw + 8, sizeof(uint32_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&value); | |
| entry_offset = value; | |
| } | |
| else | |
| { | |
| memcpy(&entry_count, direntry_raw + 4, sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&entry_count); | |
| memcpy(&entry_offset, direntry_raw + 12, sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&entry_offset); | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* When a dummy tag was written due to TIFFDeferStrileArrayWriting() */ | |
| /* -------------------------------------------------------------------- */ | |
| if (entry_offset == 0 && entry_count == 0 && entry_type == 0) | |
| { | |
| if (tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS) | |
| { | |
| entry_type = | |
| (tif->tif_flags & TIFF_BIGTIFF) ? TIFF_LONG8 : TIFF_LONG; | |
| } | |
| else | |
| { | |
| int write_aslong8 = 1; | |
| if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS) | |
| { | |
| write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif)); | |
| } | |
| else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS) | |
| { | |
| write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif)); | |
| } | |
| if (write_aslong8) | |
| { | |
| entry_type = TIFF_LONG8; | |
| } | |
| else | |
| { | |
| int write_aslong4 = 1; | |
| if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS) | |
| { | |
| write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif)); | |
| } | |
| else if (count > 1 && tag == TIFFTAG_TILEBYTECOUNTS) | |
| { | |
| write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif)); | |
| } | |
| if (write_aslong4) | |
| { | |
| entry_type = TIFF_LONG; | |
| } | |
| else | |
| { | |
| entry_type = TIFF_SHORT; | |
| } | |
| } | |
| } | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* What data type do we want to write this as? */ | |
| /* -------------------------------------------------------------------- */ | |
| if (TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (in_datatype == TIFF_LONG8) | |
| datatype = entry_type == TIFF_SHORT ? TIFF_SHORT : TIFF_LONG; | |
| else if (in_datatype == TIFF_SLONG8) | |
| datatype = TIFF_SLONG; | |
| else if (in_datatype == TIFF_IFD8) | |
| datatype = TIFF_IFD; | |
| else | |
| datatype = in_datatype; | |
| } | |
| else | |
| { | |
| if (in_datatype == TIFF_LONG8 && | |
| (entry_type == TIFF_SHORT || entry_type == TIFF_LONG || | |
| entry_type == TIFF_LONG8)) | |
| datatype = (TIFFDataType)entry_type; | |
| else if (in_datatype == TIFF_SLONG8 && | |
| (entry_type == TIFF_SLONG || entry_type == TIFF_SLONG8)) | |
| datatype = (TIFFDataType)entry_type; | |
| else if (in_datatype == TIFF_IFD8 && | |
| (entry_type == TIFF_IFD || entry_type == TIFF_IFD8)) | |
| datatype = (TIFFDataType)entry_type; | |
| else | |
| datatype = in_datatype; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Prepare buffer of actual data to write. This includes */ | |
| /* swabbing as needed. */ | |
| /* -------------------------------------------------------------------- */ | |
| buf_to_write = (uint8_t *)_TIFFCheckMalloc( | |
| tif, count, TIFFDataWidth(datatype), "for field buffer."); | |
| if (!buf_to_write) | |
| return 0; | |
| if (datatype == in_datatype) | |
| memcpy(buf_to_write, data, | |
| (size_t)count * (size_t)TIFFDataWidth(datatype)); | |
| else if (datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8) | |
| { | |
| tmsize_t i; | |
| for (i = 0; i < count; i++) | |
| { | |
| ((int32_t *)buf_to_write)[i] = (int32_t)((int64_t *)data)[i]; | |
| if ((int64_t)((int32_t *)buf_to_write)[i] != ((int64_t *)data)[i]) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, | |
| "Value exceeds 32bit range of output type."); | |
| return 0; | |
| } | |
| } | |
| } | |
| else if ((datatype == TIFF_LONG && in_datatype == TIFF_LONG8) || | |
| (datatype == TIFF_IFD && in_datatype == TIFF_IFD8)) | |
| { | |
| tmsize_t i; | |
| for (i = 0; i < count; i++) | |
| { | |
| ((uint32_t *)buf_to_write)[i] = (uint32_t)((uint64_t *)data)[i]; | |
| if ((uint64_t)((uint32_t *)buf_to_write)[i] != | |
| ((uint64_t *)data)[i]) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, | |
| "Value exceeds 32bit range of output type."); | |
| return 0; | |
| } | |
| } | |
| } | |
| else if (datatype == TIFF_SHORT && in_datatype == TIFF_LONG8) | |
| { | |
| tmsize_t i; | |
| for (i = 0; i < count; i++) | |
| { | |
| ((uint16_t *)buf_to_write)[i] = (uint16_t)((uint64_t *)data)[i]; | |
| if ((uint64_t)((uint16_t *)buf_to_write)[i] != | |
| ((uint64_t *)data)[i]) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, | |
| "Value exceeds 16bit range of output type."); | |
| return 0; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| TIFFErrorExtR(tif, module, "Unhandled type conversion."); | |
| return 0; | |
| } | |
| if (TIFFDataWidth(datatype) > 1 && (tif->tif_flags & TIFF_SWAB)) | |
| { | |
| if (TIFFDataWidth(datatype) == 2) | |
| TIFFSwabArrayOfShort((uint16_t *)buf_to_write, count); | |
| else if (TIFFDataWidth(datatype) == 4) | |
| TIFFSwabArrayOfLong((uint32_t *)buf_to_write, count); | |
| else if (TIFFDataWidth(datatype) == 8) | |
| TIFFSwabArrayOfLong8((uint64_t *)buf_to_write, count); | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Is this a value that fits into the directory entry? */ | |
| /* -------------------------------------------------------------------- */ | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (TIFFDataWidth(datatype) * count <= 4) | |
| { | |
| entry_offset = read_offset + 8; | |
| value_in_entry = 1; | |
| } | |
| } | |
| else | |
| { | |
| if (TIFFDataWidth(datatype) * count <= 8) | |
| { | |
| entry_offset = read_offset + 12; | |
| value_in_entry = 1; | |
| } | |
| } | |
| if ((tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS) && | |
| tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && | |
| tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && | |
| tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0) | |
| { | |
| tif->tif_dir.td_stripoffset_entry.tdir_type = (uint16_t)datatype; | |
| tif->tif_dir.td_stripoffset_entry.tdir_count = (uint64_t)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 = (uint16_t)datatype; | |
| tif->tif_dir.td_stripbytecount_entry.tdir_count = (uint64_t)count; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* If the tag type, and count match, then we just write it out */ | |
| /* over the old values without altering the directory entry at */ | |
| /* all. */ | |
| /* -------------------------------------------------------------------- */ | |
| if (entry_count == (uint64_t)count && entry_type == (uint16_t)datatype) | |
| { | |
| if (!SeekOK(tif, entry_offset)) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, | |
| "%s: Seek error accessing TIFF directory", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| if (!WriteOK(tif, buf_to_write, count * TIFFDataWidth(datatype))) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, "Error writing directory link"); | |
| return (0); | |
| } | |
| _TIFFfreeExt(tif, buf_to_write); | |
| return 1; | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Otherwise, we write the new tag data at the end of the file. */ | |
| /* -------------------------------------------------------------------- */ | |
| if (!value_in_entry) | |
| { | |
| entry_offset = TIFFSeekFile(tif, 0, SEEK_END); | |
| if (!WriteOK(tif, buf_to_write, count * TIFFDataWidth(datatype))) | |
| { | |
| _TIFFfreeExt(tif, buf_to_write); | |
| TIFFErrorExtR(tif, module, "Error writing directory link"); | |
| return (0); | |
| } | |
| } | |
| else | |
| { | |
| if (count * TIFFDataWidth(datatype) == 4) | |
| { | |
| uint32_t value; | |
| memcpy(&value, buf_to_write, | |
| (size_t)count * (size_t)TIFFDataWidth(datatype)); | |
| entry_offset = value; | |
| } | |
| else | |
| { | |
| memcpy(&entry_offset, buf_to_write, | |
| (size_t)count * (size_t)TIFFDataWidth(datatype)); | |
| } | |
| } | |
| _TIFFfreeExt(tif, buf_to_write); | |
| buf_to_write = 0; | |
| /* -------------------------------------------------------------------- */ | |
| /* Adjust the directory entry. */ | |
| /* -------------------------------------------------------------------- */ | |
| entry_type = (uint16_t)datatype; | |
| entry_count = (uint64_t)count; | |
| memcpy(direntry_raw + 2, &entry_type, sizeof(uint16_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)(direntry_raw + 2)); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t value; | |
| value = (uint32_t)entry_count; | |
| memcpy(direntry_raw + 4, &value, sizeof(uint32_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)(direntry_raw + 4)); | |
| value = (uint32_t)entry_offset; | |
| memcpy(direntry_raw + 8, &value, sizeof(uint32_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)(direntry_raw + 8)); | |
| } | |
| else | |
| { | |
| memcpy(direntry_raw + 4, &entry_count, sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)(direntry_raw + 4)); | |
| memcpy(direntry_raw + 12, &entry_offset, sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)(direntry_raw + 12)); | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| /* Write the directory entry out to disk. */ | |
| /* -------------------------------------------------------------------- */ | |
| if (!SeekOK(tif, read_offset)) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Seek error accessing TIFF directory", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| if (!WriteOK(tif, direntry_raw, dirsize)) | |
| { | |
| TIFFErrorExtR(tif, module, "%s: Can not write TIFF directory entry.", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| return 1; | |
| } |