| /* | |
| * 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 Read Support Routines. | |
| */ | |
| /* Suggested pending improvements: | |
| * - add a field 'field_info' to the TIFFDirEntry structure, and set that with | |
| * the pointer to the appropriate TIFFField structure early on in | |
| * TIFFReadDirectory, so as to eliminate current possibly repetitive lookup. | |
| */ | |
| #include "tiffconf.h" | |
| #include "tiffiop.h" | |
| #include <float.h> | |
| #include <limits.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #define FAILED_FII ((uint32_t)-1) | |
| #ifdef HAVE_IEEEFP | |
| #define TIFFCvtIEEEFloatToNative(tif, n, fp) | |
| #define TIFFCvtIEEEDoubleToNative(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 TIFFCvtIEEEFloatToNative(TIFF *, uint32_t, float *); | |
| extern void TIFFCvtIEEEDoubleToNative(TIFF *, uint32_t, double *); | |
| #endif | |
| enum TIFFReadDirEntryErr | |
| { | |
| TIFFReadDirEntryErrOk = 0, | |
| TIFFReadDirEntryErrCount = 1, | |
| TIFFReadDirEntryErrType = 2, | |
| TIFFReadDirEntryErrIo = 3, | |
| TIFFReadDirEntryErrRange = 4, | |
| TIFFReadDirEntryErrPsdif = 5, | |
| TIFFReadDirEntryErrSizesan = 6, | |
| TIFFReadDirEntryErrAlloc = 7, | |
| }; | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryByte(TIFF *tif, TIFFDirEntry *direntry, uint8_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySbyte(TIFF *tif, TIFFDirEntry *direntry, int8_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryShort(TIFF *tif, TIFFDirEntry *direntry, uint16_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySshort(TIFF *tif, TIFFDirEntry *direntry, int16_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong(TIFF *tif, TIFFDirEntry *direntry, uint32_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong(TIFF *tif, TIFFDirEntry *direntry, int32_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong8(TIFF *tif, TIFFDirEntry *direntry, int64_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryFloat(TIFF *tif, TIFFDirEntry *direntry, float *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryDouble(TIFF *tif, TIFFDirEntry *direntry, double *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryIfd8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryArray(TIFF *tif, TIFFDirEntry *direntry, uint32_t *count, | |
| uint32_t desttypesize, void **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryByteArray(TIFF *tif, TIFFDirEntry *direntry, uint8_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySbyteArray(TIFF *tif, TIFFDirEntry *direntry, int8_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryShortArray(TIFF *tif, TIFFDirEntry *direntry, uint16_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySshortArray(TIFF *tif, TIFFDirEntry *direntry, int16_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLongArray(TIFF *tif, TIFFDirEntry *direntry, uint32_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlongArray(TIFF *tif, TIFFDirEntry *direntry, int32_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong8Array(TIFF *tif, TIFFDirEntry *direntry, uint64_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong8Array(TIFF *tif, TIFFDirEntry *direntry, int64_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryFloatArray(TIFF *tif, TIFFDirEntry *direntry, float **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryDoubleArray(TIFF *tif, TIFFDirEntry *direntry, double **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryIfd8Array(TIFF *tif, TIFFDirEntry *direntry, uint64_t **value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryPersampleShort(TIFF *tif, TIFFDirEntry *direntry, | |
| uint16_t *value); | |
| static void TIFFReadDirEntryCheckedByte(TIFF *tif, TIFFDirEntry *direntry, | |
| uint8_t *value); | |
| static void TIFFReadDirEntryCheckedSbyte(TIFF *tif, TIFFDirEntry *direntry, | |
| int8_t *value); | |
| static void TIFFReadDirEntryCheckedShort(TIFF *tif, TIFFDirEntry *direntry, | |
| uint16_t *value); | |
| static void TIFFReadDirEntryCheckedSshort(TIFF *tif, TIFFDirEntry *direntry, | |
| int16_t *value); | |
| static void TIFFReadDirEntryCheckedLong(TIFF *tif, TIFFDirEntry *direntry, | |
| uint32_t *value); | |
| static void TIFFReadDirEntryCheckedSlong(TIFF *tif, TIFFDirEntry *direntry, | |
| int32_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedLong8(TIFF *tif, TIFFDirEntry *direntry, | |
| uint64_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedSlong8(TIFF *tif, TIFFDirEntry *direntry, | |
| int64_t *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedRational(TIFF *tif, TIFFDirEntry *direntry, | |
| double *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedSrational(TIFF *tif, TIFFDirEntry *direntry, | |
| double *value); | |
| static void TIFFReadDirEntryCheckedFloat(TIFF *tif, TIFFDirEntry *direntry, | |
| float *value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedDouble(TIFF *tif, TIFFDirEntry *direntry, double *value); | |
| #if 0 | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedRationalDirect(TIFF *tif, TIFFDirEntry *direntry, | |
| TIFFRational_t *value); | |
| #endif | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSbyte(int8_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteShort(uint16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSshort(int16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteLong(uint32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSlong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSbyte(int8_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSshort(int16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortLong(uint32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSlong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortShort(uint16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortLong(uint32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortSlong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSbyte(int8_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSshort(int16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSlong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongLong(uint32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Slong(int32_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value); | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value); | |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF *tif, uint64_t offset, | |
| tmsize_t size, void *dest); | |
| static void TIFFReadDirEntryOutputErr(TIFF *tif, enum TIFFReadDirEntryErr err, | |
| const char *module, const char *tagname, | |
| int recover); | |
| static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount); | |
| static TIFFDirEntry *TIFFReadDirectoryFindEntry(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount, | |
| uint16_t tagid); | |
| static void TIFFReadDirectoryFindFieldInfo(TIFF *tif, uint16_t tagid, | |
| uint32_t *fii); | |
| static int EstimateStripByteCounts(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount); | |
| static void MissingRequired(TIFF *, const char *); | |
| static int CheckDirCount(TIFF *, TIFFDirEntry *, uint32_t); | |
| static uint16_t TIFFFetchDirectory(TIFF *tif, uint64_t diroff, | |
| TIFFDirEntry **pdir, uint64_t *nextdiroff); | |
| static int TIFFFetchNormalTag(TIFF *, TIFFDirEntry *, int recover); | |
| static int TIFFFetchStripThing(TIFF *tif, TIFFDirEntry *dir, uint32_t nstrips, | |
| uint64_t **lpp); | |
| static int TIFFFetchSubjectDistance(TIFF *, TIFFDirEntry *); | |
| static void ChopUpSingleUncompressedStrip(TIFF *); | |
| static void TryChopUpUncompressedBigTiff(TIFF *); | |
| static uint64_t TIFFReadUInt64(const uint8_t *value); | |
| static int _TIFFGetMaxColorChannels(uint16_t photometric); | |
| static int _TIFFFillStrilesInternal(TIFF *tif, int loadStripByteCount); | |
| typedef union _UInt64Aligned_t | |
| { | |
| double d; | |
| uint64_t l; | |
| uint32_t i[2]; | |
| uint16_t s[4]; | |
| uint8_t c[8]; | |
| } UInt64Aligned_t; | |
| /* | |
| Unaligned safe copy of a uint64_t value from an octet array. | |
| */ | |
| static uint64_t TIFFReadUInt64(const uint8_t *value) | |
| { | |
| UInt64Aligned_t result; | |
| result.c[0] = value[0]; | |
| result.c[1] = value[1]; | |
| result.c[2] = value[2]; | |
| result.c[3] = value[3]; | |
| result.c[4] = value[4]; | |
| result.c[5] = value[5]; | |
| result.c[6] = value[6]; | |
| result.c[7] = value[7]; | |
| return result.l; | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryByte(TIFF *tif, TIFFDirEntry *direntry, uint8_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_UNDEFINED: /* Support to read TIFF_UNDEFINED with | |
| field_readcount==1 */ | |
| TIFFReadDirEntryCheckedByte(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeByteSbyte(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeByteShort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeByteSshort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeByteLong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeByteSlong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeByteLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeByteSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySbyte(TIFF *tif, TIFFDirEntry *direntry, int8_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_UNDEFINED: /* Support to read TIFF_UNDEFINED with | |
| field_readcount==1 */ | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSbyteByte(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSbyteShort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSbyteSshort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSbyteLong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSbyteSlong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSbyteLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSbyteSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int8_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntrySbyte() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryShort(TIFF *tif, TIFFDirEntry *direntry, uint16_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeShortSbyte(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| TIFFReadDirEntryCheckedShort(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeShortSshort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeShortLong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeShortSlong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeShortLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeShortSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntryShort() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySshort(TIFF *tif, TIFFDirEntry *direntry, int16_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSshortShort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSshortLong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSshortSlong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSshortLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSshortSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int16_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntrySshort() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong(TIFF *tif, TIFFDirEntry *direntry, uint32_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLongSbyte(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLongSshort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| TIFFReadDirEntryCheckedLong(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLongSlong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeLongLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeLongSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntryLong() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong(TIFF *tif, TIFFDirEntry *direntry, int32_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeSlongLong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSlongLong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSlongSlong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int32_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntrySlong() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLong8Sbyte(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLong8Sshort(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| err = TIFFReadDirEntryCheckRangeLong8Slong(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, value); | |
| return (err); | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeLong8Slong8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntryLong8() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong8(TIFF *tif, TIFFDirEntry *direntry, int64_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| err = TIFFReadDirEntryCheckRangeSlong8Long8(m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (int64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, value); | |
| return (err); | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } /*-- TIFFReadDirEntrySlong8() --*/ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryFloat(TIFF *tif, TIFFDirEntry *direntry, float *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_RATIONAL: | |
| { | |
| double m; | |
| err = TIFFReadDirEntryCheckedRational(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SRATIONAL: | |
| { | |
| double m; | |
| err = TIFFReadDirEntryCheckedSrational(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_FLOAT: | |
| TIFFReadDirEntryCheckedFloat(tif, direntry, value); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_DOUBLE: | |
| { | |
| double m; | |
| err = TIFFReadDirEntryCheckedDouble(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| if ((m > (double)FLT_MAX) || (m < -(double)FLT_MAX)) | |
| return (TIFFReadDirEntryErrRange); | |
| *value = (float)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryDouble(TIFF *tif, TIFFDirEntry *direntry, double *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t m; | |
| TIFFReadDirEntryCheckedByte(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| { | |
| int8_t m; | |
| TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SHORT: | |
| { | |
| uint16_t m; | |
| TIFFReadDirEntryCheckedShort(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| { | |
| int16_t m; | |
| TIFFReadDirEntryCheckedSshort(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| { | |
| int32_t m; | |
| TIFFReadDirEntryCheckedSlong(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| { | |
| uint64_t m; | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| { | |
| int64_t m; | |
| err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_RATIONAL: | |
| err = TIFFReadDirEntryCheckedRational(tif, direntry, value); | |
| return (err); | |
| case TIFF_SRATIONAL: | |
| err = TIFFReadDirEntryCheckedSrational(tif, direntry, value); | |
| return (err); | |
| case TIFF_FLOAT: | |
| { | |
| float m; | |
| TIFFReadDirEntryCheckedFloat(tif, direntry, &m); | |
| *value = (double)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_DOUBLE: | |
| err = TIFFReadDirEntryCheckedDouble(tif, direntry, value); | |
| return (err); | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryIfd8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| { | |
| uint32_t m; | |
| TIFFReadDirEntryCheckedLong(tif, direntry, &m); | |
| *value = (uint64_t)m; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| err = TIFFReadDirEntryCheckedLong8(tif, direntry, value); | |
| return (err); | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| } | |
| #define INITIAL_THRESHOLD (1024 * 1024) | |
| #define THRESHOLD_MULTIPLIER 10 | |
| #define MAX_THRESHOLD \ | |
| (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * \ | |
| INITIAL_THRESHOLD) | |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryDataAndRealloc(TIFF *tif, | |
| uint64_t offset, | |
| tmsize_t size, | |
| void **pdest) | |
| { | |
| #if SIZEOF_SIZE_T == 8 | |
| tmsize_t threshold = INITIAL_THRESHOLD; | |
| #endif | |
| tmsize_t already_read = 0; | |
| assert(!isMapped(tif)); | |
| if (!SeekOK(tif, offset)) | |
| return (TIFFReadDirEntryErrIo); | |
| /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */ | |
| /* so as to avoid allocating too much memory in case the file is too */ | |
| /* short. We could ask for the file size, but this might be */ | |
| /* expensive with some I/O layers (think of reading a gzipped file) */ | |
| /* Restrict to 64 bit processes, so as to avoid reallocs() */ | |
| /* on 32 bit processes where virtual memory is scarce. */ | |
| while (already_read < size) | |
| { | |
| void *new_dest; | |
| tmsize_t bytes_read; | |
| tmsize_t to_read = size - already_read; | |
| #if SIZEOF_SIZE_T == 8 | |
| if (to_read >= threshold && threshold < MAX_THRESHOLD) | |
| { | |
| to_read = threshold; | |
| threshold *= THRESHOLD_MULTIPLIER; | |
| } | |
| #endif | |
| new_dest = | |
| (uint8_t *)_TIFFreallocExt(tif, *pdest, already_read + to_read); | |
| if (new_dest == NULL) | |
| { | |
| TIFFErrorExtR(tif, tif->tif_name, | |
| "Failed to allocate memory for %s " | |
| "(%" TIFF_SSIZE_FORMAT | |
| " elements of %" TIFF_SSIZE_FORMAT " bytes each)", | |
| "TIFFReadDirEntryArray", (tmsize_t)1, | |
| already_read + to_read); | |
| return TIFFReadDirEntryErrAlloc; | |
| } | |
| *pdest = new_dest; | |
| bytes_read = TIFFReadFile(tif, (char *)*pdest + already_read, to_read); | |
| if (bytes_read < 0) | |
| return TIFFReadDirEntryErrIo; | |
| already_read += bytes_read; | |
| if (bytes_read != to_read) | |
| { | |
| return TIFFReadDirEntryErrIo; | |
| } | |
| } | |
| return TIFFReadDirEntryErrOk; | |
| } | |
| /* Caution: if raising that value, make sure int32 / uint32 overflows can't | |
| * occur elsewhere */ | |
| #define MAX_SIZE_TAG_DATA 2147483647U | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryArrayWithLimit(TIFF *tif, TIFFDirEntry *direntry, | |
| uint32_t *count, uint32_t desttypesize, | |
| void **value, uint64_t maxcount) | |
| { | |
| int typesize; | |
| uint32_t datasize; | |
| void *data; | |
| uint64_t target_count64; | |
| int original_datasize_clamped; | |
| typesize = TIFFDataWidth((TIFFDataType)direntry->tdir_type); | |
| target_count64 = | |
| (direntry->tdir_count > maxcount) ? maxcount : direntry->tdir_count; | |
| if ((target_count64 == 0) || (typesize == 0)) | |
| { | |
| *value = 0; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| (void)desttypesize; | |
| /* We just want to know if the original tag size is more than 4 bytes | |
| * (classic TIFF) or 8 bytes (BigTIFF) | |
| */ | |
| original_datasize_clamped = | |
| ((direntry->tdir_count > 10) ? 10 : (int)direntry->tdir_count) * | |
| typesize; | |
| /* | |
| * As a sanity check, make sure we have no more than a 2GB tag array | |
| * in either the current data type or the dest data type. This also | |
| * avoids problems with overflow of tmsize_t on 32bit systems. | |
| */ | |
| if ((uint64_t)(MAX_SIZE_TAG_DATA / (unsigned int)typesize) < target_count64) | |
| return (TIFFReadDirEntryErrSizesan); | |
| if ((uint64_t)(MAX_SIZE_TAG_DATA / desttypesize) < target_count64) | |
| return (TIFFReadDirEntryErrSizesan); | |
| *count = (uint32_t)target_count64; | |
| datasize = (uint32_t)(*count) * (unsigned int)typesize; | |
| assert((tmsize_t)datasize > 0); | |
| if (datasize > 100 * 1024 * 1024) | |
| { | |
| /* Before allocating a huge amount of memory for corrupted files, check | |
| * if size of requested memory is not greater than file size. | |
| */ | |
| const uint64_t filesize = TIFFGetFileSize(tif); | |
| if (datasize > filesize) | |
| { | |
| TIFFWarningExtR(tif, "ReadDirEntryArray", | |
| "Requested memory size for tag %d (0x%x) %" PRIu32 | |
| " is greater than filesize %" PRIu64 | |
| ". Memory not allocated, tag not read", | |
| direntry->tdir_tag, direntry->tdir_tag, datasize, | |
| filesize); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| } | |
| if (isMapped(tif) && datasize > (uint64_t)tif->tif_size) | |
| return TIFFReadDirEntryErrIo; | |
| if (!isMapped(tif) && (((tif->tif_flags & TIFF_BIGTIFF) && datasize > 8) || | |
| (!(tif->tif_flags & TIFF_BIGTIFF) && datasize > 4))) | |
| { | |
| data = NULL; | |
| } | |
| else | |
| { | |
| data = _TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray"); | |
| if (data == 0) | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| /* Only the condition on original_datasize_clamped. The second | |
| * one is implied, but Coverity Scan cannot see it. */ | |
| if (original_datasize_clamped <= 4 && datasize <= 4) | |
| _TIFFmemcpy(data, &direntry->tdir_offset, datasize); | |
| else | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| if (isMapped(tif)) | |
| err = TIFFReadDirEntryData(tif, (uint64_t)offset, | |
| (tmsize_t)datasize, data); | |
| else | |
| err = TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, | |
| (tmsize_t)datasize, &data); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| /* See above comment for the Classic TIFF case */ | |
| if (original_datasize_clamped <= 8 && datasize <= 8) | |
| _TIFFmemcpy(data, &direntry->tdir_offset, datasize); | |
| else | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint64_t offset = direntry->tdir_offset.toff_long8; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&offset); | |
| if (isMapped(tif)) | |
| err = TIFFReadDirEntryData(tif, (uint64_t)offset, | |
| (tmsize_t)datasize, data); | |
| else | |
| err = TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, | |
| (tmsize_t)datasize, &data); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| } | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryArray(TIFF *tif, TIFFDirEntry *direntry, uint32_t *count, | |
| uint32_t desttypesize, void **value) | |
| { | |
| return TIFFReadDirEntryArrayWithLimit(tif, direntry, count, desttypesize, | |
| value, ~((uint64_t)0)); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryByteArray(TIFF *tif, TIFFDirEntry *direntry, uint8_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| uint8_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_ASCII: | |
| case TIFF_UNDEFINED: | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 1, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_ASCII: | |
| case TIFF_UNDEFINED: | |
| case TIFF_BYTE: | |
| *value = (uint8_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *m; | |
| uint32_t n; | |
| m = (int8_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| err = TIFFReadDirEntryCheckRangeByteSbyte(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (uint8_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| break; | |
| } | |
| data = (uint8_t *)_TIFFmallocExt(tif, count); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| err = TIFFReadDirEntryCheckRangeByteShort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeByteSshort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| err = TIFFReadDirEntryCheckRangeByteLong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeByteSlong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeByteLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| uint8_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeByteSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySbyteArray(TIFF *tif, TIFFDirEntry *direntry, int8_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| int8_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_UNDEFINED: | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 1, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_UNDEFINED: | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *m; | |
| uint32_t n; | |
| m = (uint8_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| err = TIFFReadDirEntryCheckRangeSbyteByte(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (int8_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SBYTE: | |
| *value = (int8_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (int8_t *)_TIFFmallocExt(tif, count); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteShort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteSshort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteLong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteSlong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| int8_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSbyteSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int8_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryShortArray(TIFF *tif, TIFFDirEntry *direntry, uint16_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| uint16_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 2, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| *value = (uint16_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfShort(*value, count); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *m; | |
| uint32_t n; | |
| m = (int16_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)m); | |
| err = TIFFReadDirEntryCheckRangeShortSshort(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (uint16_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| break; | |
| } | |
| data = (uint16_t *)_TIFFmallocExt(tif, count * 2); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| err = TIFFReadDirEntryCheckRangeShortSbyte(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| err = TIFFReadDirEntryCheckRangeShortLong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeShortSlong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeShortLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| uint16_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeShortSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySshortArray(TIFF *tif, TIFFDirEntry *direntry, int16_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| int16_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 2, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *m; | |
| uint32_t n; | |
| m = (uint16_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(m); | |
| err = TIFFReadDirEntryCheckRangeSshortShort(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (int16_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SSHORT: | |
| *value = (int16_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfShort((uint16_t *)(*value), count); | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (int16_t *)_TIFFmallocExt(tif, count * 2); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| err = TIFFReadDirEntryCheckRangeSshortLong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSshortSlong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeSshortLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| int16_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSshortSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int16_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLongArray(TIFF *tif, TIFFDirEntry *direntry, uint32_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| uint32_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| case TIFF_IFD: | |
| case TIFF_IFD8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 4, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| *value = (uint32_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(*value, count); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SLONG: | |
| { | |
| int32_t *m; | |
| uint32_t n; | |
| m = (int32_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)m); | |
| err = TIFFReadDirEntryCheckRangeLongSlong(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (uint32_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| break; | |
| } | |
| data = (uint32_t *)_TIFFmallocExt(tif, count * 4); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| err = TIFFReadDirEntryCheckRangeLongSbyte(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeLongSshort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| { | |
| uint64_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeLongLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| uint32_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeLongSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlongArray(TIFF *tif, TIFFDirEntry *direntry, int32_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| int32_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 4, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG: | |
| { | |
| uint32_t *m; | |
| uint32_t n; | |
| m = (uint32_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)m); | |
| err = TIFFReadDirEntryCheckRangeSlongLong(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (int32_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG: | |
| *value = (int32_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)(*value), count); | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (int32_t *)_TIFFmallocExt(tif, count * 4); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| err = TIFFReadDirEntryCheckRangeSlongLong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| int32_t *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeSlongSlong8(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (int32_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong8ArrayWithLimit(TIFF *tif, TIFFDirEntry *direntry, | |
| uint64_t **value, uint64_t maxcount) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| uint64_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| case TIFF_IFD: | |
| case TIFF_IFD8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArrayWithLimit(tif, direntry, &count, 8, &origdata, | |
| maxcount); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| *value = (uint64_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8(*value, count); | |
| return (TIFFReadDirEntryErrOk); | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *m; | |
| uint32_t n; | |
| m = (int64_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)m); | |
| err = TIFFReadDirEntryCheckRangeLong8Slong8(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (uint64_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| default: | |
| break; | |
| } | |
| data = (uint64_t *)_TIFFmallocExt(tif, count * 8); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| err = TIFFReadDirEntryCheckRangeLong8Sbyte(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeLong8Sshort(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| { | |
| uint32_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| err = TIFFReadDirEntryCheckRangeLong8Slong(*ma); | |
| if (err != TIFFReadDirEntryErrOk) | |
| break; | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (err); | |
| } | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryLong8Array(TIFF *tif, TIFFDirEntry *direntry, uint64_t **value) | |
| { | |
| return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, | |
| ~((uint64_t)0)); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntrySlong8Array(TIFF *tif, TIFFDirEntry *direntry, int64_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| int64_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 8, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *m; | |
| uint32_t n; | |
| m = (uint64_t *)origdata; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(m); | |
| err = TIFFReadDirEntryCheckRangeSlong8Long8(*m); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (err); | |
| } | |
| m++; | |
| } | |
| *value = (int64_t *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| case TIFF_SLONG8: | |
| *value = (int64_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8((uint64_t *)(*value), count); | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (int64_t *)_TIFFmallocExt(tif, count * 8); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| int64_t *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| *mb++ = (int64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryFloatArray(TIFF *tif, TIFFDirEntry *direntry, float **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| float *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| case TIFF_RATIONAL: | |
| case TIFF_SRATIONAL: | |
| case TIFF_FLOAT: | |
| case TIFF_DOUBLE: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 4, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_FLOAT: | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)origdata, count); | |
| TIFFCvtIEEEFloatToNative(tif, count, (float *)origdata); | |
| *value = (float *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = | |
| (float *)_TIFFmallocExt(tif, (tmsize_t)((size_t)count * sizeof(float))); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (float)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (float)(*ma++); | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| float *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| *mb++ = (float)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_RATIONAL: | |
| { | |
| uint32_t *ma; | |
| uint32_t maa; | |
| uint32_t mab; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| maa = *ma++; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| mab = *ma++; | |
| if (mab == 0) | |
| *mb++ = 0.0; | |
| else | |
| *mb++ = (float)maa / (float)mab; | |
| } | |
| } | |
| break; | |
| case TIFF_SRATIONAL: | |
| { | |
| uint32_t *ma; | |
| int32_t maa; | |
| uint32_t mab; | |
| float *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| maa = *(int32_t *)ma; | |
| ma++; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| mab = *ma++; | |
| if (mab == 0) | |
| *mb++ = 0.0; | |
| else | |
| *mb++ = (float)maa / (float)mab; | |
| } | |
| } | |
| break; | |
| case TIFF_DOUBLE: | |
| { | |
| double *ma; | |
| float *mb; | |
| uint32_t n; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8((uint64_t *)origdata, count); | |
| TIFFCvtIEEEDoubleToNative(tif, count, (double *)origdata); | |
| ma = (double *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| double val = *ma++; | |
| if (val > (double)FLT_MAX) | |
| val = (double)FLT_MAX; | |
| else if (val < -(double)FLT_MAX) | |
| val = -(double)FLT_MAX; | |
| *mb++ = (float)val; | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryDoubleArray(TIFF *tif, TIFFDirEntry *direntry, double **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| double *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| case TIFF_SBYTE: | |
| case TIFF_SHORT: | |
| case TIFF_SSHORT: | |
| case TIFF_LONG: | |
| case TIFF_SLONG: | |
| case TIFF_LONG8: | |
| case TIFF_SLONG8: | |
| case TIFF_RATIONAL: | |
| case TIFF_SRATIONAL: | |
| case TIFF_FLOAT: | |
| case TIFF_DOUBLE: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 8, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_DOUBLE: | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8((uint64_t *)origdata, count); | |
| TIFFCvtIEEEDoubleToNative(tif, count, (double *)origdata); | |
| *value = (double *)origdata; | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (double *)_TIFFmallocExt(tif, | |
| (tmsize_t)((size_t)count * sizeof(double))); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_BYTE: | |
| { | |
| uint8_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (double)(*ma++); | |
| } | |
| break; | |
| case TIFF_SBYTE: | |
| { | |
| int8_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (int8_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (double)(*ma++); | |
| } | |
| break; | |
| case TIFF_SHORT: | |
| { | |
| uint16_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SSHORT: | |
| { | |
| int16_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (int16_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG: | |
| { | |
| uint32_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG: | |
| { | |
| int32_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (int32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_LONG8: | |
| { | |
| uint64_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_SLONG8: | |
| { | |
| int64_t *ma; | |
| double *mb; | |
| uint32_t n; | |
| ma = (int64_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| *mb++ = (double)(*ma++); | |
| } | |
| } | |
| break; | |
| case TIFF_RATIONAL: | |
| { | |
| uint32_t *ma; | |
| uint32_t maa; | |
| uint32_t mab; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| maa = *ma++; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| mab = *ma++; | |
| if (mab == 0) | |
| *mb++ = 0.0; | |
| else | |
| *mb++ = (double)maa / (double)mab; | |
| } | |
| } | |
| break; | |
| case TIFF_SRATIONAL: | |
| { | |
| uint32_t *ma; | |
| int32_t maa; | |
| uint32_t mab; | |
| double *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| maa = *(int32_t *)ma; | |
| ma++; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| mab = *ma++; | |
| if (mab == 0) | |
| *mb++ = 0.0; | |
| else | |
| *mb++ = (double)maa / (double)mab; | |
| } | |
| } | |
| break; | |
| case TIFF_FLOAT: | |
| { | |
| float *ma; | |
| double *mb; | |
| uint32_t n; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)origdata, count); | |
| TIFFCvtIEEEFloatToNative(tif, count, (float *)origdata); | |
| ma = (float *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| *mb++ = (double)(*ma++); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryIfd8Array(TIFF *tif, TIFFDirEntry *direntry, uint64_t **value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t count; | |
| void *origdata; | |
| uint64_t *data; | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG: | |
| case TIFF_LONG8: | |
| case TIFF_IFD: | |
| case TIFF_IFD8: | |
| break; | |
| default: | |
| return (TIFFReadDirEntryErrType); | |
| } | |
| err = TIFFReadDirEntryArray(tif, direntry, &count, 8, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| *value = 0; | |
| return (err); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG8: | |
| case TIFF_IFD8: | |
| *value = (uint64_t *)origdata; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong8(*value, count); | |
| return (TIFFReadDirEntryErrOk); | |
| default: | |
| break; | |
| } | |
| data = (uint64_t *)_TIFFmallocExt(tif, count * 8); | |
| if (data == 0) | |
| { | |
| _TIFFfreeExt(tif, origdata); | |
| return (TIFFReadDirEntryErrAlloc); | |
| } | |
| switch (direntry->tdir_type) | |
| { | |
| case TIFF_LONG: | |
| case TIFF_IFD: | |
| { | |
| uint32_t *ma; | |
| uint64_t *mb; | |
| uint32_t n; | |
| ma = (uint32_t *)origdata; | |
| mb = data; | |
| for (n = 0; n < count; n++) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(ma); | |
| *mb++ = (uint64_t)(*ma++); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| _TIFFfreeExt(tif, origdata); | |
| *value = data; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryPersampleShort(TIFF *tif, TIFFDirEntry *direntry, | |
| uint16_t *value) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint16_t *m; | |
| uint16_t *na; | |
| uint16_t nb; | |
| if (direntry->tdir_count != (uint64_t)tif->tif_dir.td_samplesperpixel) | |
| { | |
| const TIFFField *fip = TIFFFieldWithTag(tif, direntry->tdir_tag); | |
| if (direntry->tdir_count == 0) | |
| { | |
| return TIFFReadDirEntryErrCount; | |
| } | |
| else if (direntry->tdir_count < | |
| (uint64_t)tif->tif_dir.td_samplesperpixel) | |
| { | |
| TIFFWarningExtR( | |
| tif, "TIFFReadDirEntryPersampleShort", | |
| "Tag %s entry count is %" PRIu64 | |
| " , whereas it should be SamplesPerPixel=%d. Assuming that " | |
| "missing entries are all at the value of the first one", | |
| fip ? fip->field_name : "unknown tagname", direntry->tdir_count, | |
| tif->tif_dir.td_samplesperpixel); | |
| } | |
| else | |
| { | |
| TIFFWarningExtR(tif, "TIFFReadDirEntryPersampleShort", | |
| "Tag %s entry count is %" PRIu64 | |
| " , whereas it should be SamplesPerPixel=%d. " | |
| "Ignoring extra entries", | |
| fip ? fip->field_name : "unknown tagname", | |
| direntry->tdir_count, | |
| tif->tif_dir.td_samplesperpixel); | |
| } | |
| } | |
| err = TIFFReadDirEntryShortArray(tif, direntry, &m); | |
| if (err != TIFFReadDirEntryErrOk || m == NULL) | |
| return (err); | |
| na = m; | |
| nb = tif->tif_dir.td_samplesperpixel; | |
| if (direntry->tdir_count < nb) | |
| nb = (uint16_t)direntry->tdir_count; | |
| *value = *na++; | |
| nb--; | |
| while (nb > 0) | |
| { | |
| if (*na++ != *value) | |
| { | |
| err = TIFFReadDirEntryErrPsdif; | |
| break; | |
| } | |
| nb--; | |
| } | |
| _TIFFfreeExt(tif, m); | |
| return (err); | |
| } | |
| static void TIFFReadDirEntryCheckedByte(TIFF *tif, TIFFDirEntry *direntry, | |
| uint8_t *value) | |
| { | |
| (void)tif; | |
| *value = *(uint8_t *)(&direntry->tdir_offset); | |
| } | |
| static void TIFFReadDirEntryCheckedSbyte(TIFF *tif, TIFFDirEntry *direntry, | |
| int8_t *value) | |
| { | |
| (void)tif; | |
| *value = *(int8_t *)(&direntry->tdir_offset); | |
| } | |
| static void TIFFReadDirEntryCheckedShort(TIFF *tif, TIFFDirEntry *direntry, | |
| uint16_t *value) | |
| { | |
| *value = direntry->tdir_offset.toff_short; | |
| /* *value=*(uint16_t*)(&direntry->tdir_offset); */ | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(value); | |
| } | |
| static void TIFFReadDirEntryCheckedSshort(TIFF *tif, TIFFDirEntry *direntry, | |
| int16_t *value) | |
| { | |
| *value = *(int16_t *)(&direntry->tdir_offset); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)value); | |
| } | |
| static void TIFFReadDirEntryCheckedLong(TIFF *tif, TIFFDirEntry *direntry, | |
| uint32_t *value) | |
| { | |
| *value = *(uint32_t *)(&direntry->tdir_offset); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(value); | |
| } | |
| static void TIFFReadDirEntryCheckedSlong(TIFF *tif, TIFFDirEntry *direntry, | |
| int32_t *value) | |
| { | |
| *value = *(int32_t *)(&direntry->tdir_offset); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)value); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedLong8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value) | |
| { | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, value); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| *value = direntry->tdir_offset.toff_long8; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(value); | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedSlong8(TIFF *tif, TIFFDirEntry *direntry, int64_t *value) | |
| { | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, value); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| *value = *(int64_t *)(&direntry->tdir_offset); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)value); | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedRational(TIFF *tif, TIFFDirEntry *direntry, | |
| double *value) | |
| { | |
| UInt64Aligned_t m; | |
| assert(sizeof(double) == 8); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(sizeof(uint32_t) == 4); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, m.i); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| m.l = direntry->tdir_offset.toff_long8; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m.i, 2); | |
| /* Not completely sure what we should do when m.i[1]==0, but some */ | |
| /* sanitizers do not like division by 0.0: */ | |
| /* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */ | |
| if (m.i[0] == 0 || m.i[1] == 0) | |
| *value = 0.0; | |
| else | |
| *value = (double)m.i[0] / (double)m.i[1]; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedSrational(TIFF *tif, TIFFDirEntry *direntry, | |
| double *value) | |
| { | |
| UInt64Aligned_t m; | |
| assert(sizeof(double) == 8); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(sizeof(int32_t) == 4); | |
| assert(sizeof(uint32_t) == 4); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, m.i); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| m.l = direntry->tdir_offset.toff_long8; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m.i, 2); | |
| /* Not completely sure what we should do when m.i[1]==0, but some */ | |
| /* sanitizers do not like division by 0.0: */ | |
| /* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */ | |
| if ((int32_t)m.i[0] == 0 || m.i[1] == 0) | |
| *value = 0.0; | |
| else | |
| *value = (double)((int32_t)m.i[0]) / (double)m.i[1]; | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| #if 0 | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedRationalDirect(TIFF *tif, TIFFDirEntry *direntry, | |
| TIFFRational_t *value) | |
| { /*--: SetGetRATIONAL_directly:_CustomTag: Read rational (and signed rationals) | |
| directly --*/ | |
| UInt64Aligned_t m; | |
| assert(sizeof(double) == 8); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(sizeof(uint32_t) == 4); | |
| if (direntry->tdir_count != 1) | |
| return (TIFFReadDirEntryErrCount); | |
| if (direntry->tdir_type != TIFF_RATIONAL && | |
| direntry->tdir_type != TIFF_SRATIONAL) | |
| return (TIFFReadDirEntryErrType); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, m.i); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| { | |
| m.l = direntry->tdir_offset.toff_long8; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m.i, 2); | |
| value->uNum = m.i[0]; | |
| value->uDenom = m.i[1]; | |
| return (TIFFReadDirEntryErrOk); | |
| } /*-- TIFFReadDirEntryCheckedRationalDirect() --*/ | |
| #endif | |
| static void TIFFReadDirEntryCheckedFloat(TIFF *tif, TIFFDirEntry *direntry, | |
| float *value) | |
| { | |
| union | |
| { | |
| float f; | |
| uint32_t i; | |
| } float_union; | |
| assert(sizeof(float) == 4); | |
| assert(sizeof(uint32_t) == 4); | |
| assert(sizeof(float_union) == 4); | |
| float_union.i = *(uint32_t *)(&direntry->tdir_offset); | |
| *value = float_union.f; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)value); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckedDouble(TIFF *tif, TIFFDirEntry *direntry, double *value) | |
| { | |
| assert(sizeof(double) == 8); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(sizeof(UInt64Aligned_t) == 8); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t offset = direntry->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, value); | |
| if (err != TIFFReadDirEntryErrOk) | |
| return (err); | |
| } | |
| else | |
| { | |
| UInt64Aligned_t uint64_union; | |
| uint64_union.l = direntry->tdir_offset.toff_long8; | |
| *value = uint64_union.d; | |
| } | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)value); | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSbyte(int8_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteShort(uint16_t value) | |
| { | |
| if (value > 0xFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSshort(int16_t value) | |
| { | |
| if ((value < 0) || (value > 0xFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteLong(uint32_t value) | |
| { | |
| if (value > 0xFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSlong(int32_t value) | |
| { | |
| if ((value < 0) || (value > 0xFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteLong8(uint64_t value) | |
| { | |
| if (value > 0xFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeByteSlong8(int64_t value) | |
| { | |
| if ((value < 0) || (value > 0xFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value) | |
| { | |
| if (value > 0x7F) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value) | |
| { | |
| if (value > 0x7F) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value) | |
| { | |
| if ((value < -0x80) || (value > 0x7F)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value) | |
| { | |
| if (value > 0x7F) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value) | |
| { | |
| if ((value < -0x80) || (value > 0x7F)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value) | |
| { | |
| if (value > 0x7F) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value) | |
| { | |
| if ((value < -0x80) || (value > 0x7F)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSbyte(int8_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSshort(int16_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortLong(uint32_t value) | |
| { | |
| if (value > 0xFFFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSlong(int32_t value) | |
| { | |
| if ((value < 0) || (value > 0xFFFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortLong8(uint64_t value) | |
| { | |
| if (value > 0xFFFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeShortSlong8(int64_t value) | |
| { | |
| if ((value < 0) || (value > 0xFFFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortShort(uint16_t value) | |
| { | |
| if (value > 0x7FFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortLong(uint32_t value) | |
| { | |
| if (value > 0x7FFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortSlong(int32_t value) | |
| { | |
| if ((value < -0x8000) || (value > 0x7FFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value) | |
| { | |
| if (value > 0x7FFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value) | |
| { | |
| if ((value < -0x8000) || (value > 0x7FFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSbyte(int8_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSshort(int16_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSlong(int32_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongLong8(uint64_t value) | |
| { | |
| if (value > UINT32_MAX) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLongSlong8(int64_t value) | |
| { | |
| if ((value < 0) || (value > (int64_t)UINT32_MAX)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongLong(uint32_t value) | |
| { | |
| if (value > 0x7FFFFFFFUL) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| /* Check that the 8-byte unsigned value can fit in a 4-byte unsigned range */ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value) | |
| { | |
| if (value > 0x7FFFFFFF) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| /* Check that the 8-byte signed value can fit in a 4-byte signed range */ | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value) | |
| { | |
| if ((value < 0 - ((int64_t)0x7FFFFFFF + 1)) || (value > 0x7FFFFFFF)) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Slong(int32_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value) | |
| { | |
| if (value < 0) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr | |
| TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value) | |
| { | |
| if (value > INT64_MAX) | |
| return (TIFFReadDirEntryErrRange); | |
| else | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF *tif, uint64_t offset, | |
| tmsize_t size, void *dest) | |
| { | |
| assert(size > 0); | |
| if (!isMapped(tif)) | |
| { | |
| if (!SeekOK(tif, offset)) | |
| return (TIFFReadDirEntryErrIo); | |
| if (!ReadOK(tif, dest, size)) | |
| return (TIFFReadDirEntryErrIo); | |
| } | |
| else | |
| { | |
| size_t ma, mb; | |
| ma = (size_t)offset; | |
| if ((uint64_t)ma != offset || ma > (~(size_t)0) - (size_t)size) | |
| { | |
| return TIFFReadDirEntryErrIo; | |
| } | |
| mb = (uint64_t)ma + (uint64_t)size; | |
| if (mb > (uint64_t)tif->tif_size) | |
| return (TIFFReadDirEntryErrIo); | |
| _TIFFmemcpy(dest, tif->tif_base + ma, size); | |
| } | |
| return (TIFFReadDirEntryErrOk); | |
| } | |
| static void TIFFReadDirEntryOutputErr(TIFF *tif, enum TIFFReadDirEntryErr err, | |
| const char *module, const char *tagname, | |
| int recover) | |
| { | |
| if (!recover) | |
| { | |
| switch (err) | |
| { | |
| case TIFFReadDirEntryErrCount: | |
| TIFFErrorExtR(tif, module, "Incorrect count for \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrType: | |
| TIFFErrorExtR(tif, module, "Incompatible type for \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrIo: | |
| TIFFErrorExtR(tif, module, "IO error during reading of \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrRange: | |
| TIFFErrorExtR(tif, module, "Incorrect value for \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrPsdif: | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Cannot handle different values per sample for \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrSizesan: | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on size of \"%s\" value failed", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrAlloc: | |
| TIFFErrorExtR(tif, module, "Out of memory reading of \"%s\"", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrOk: | |
| default: | |
| assert(0); /* we should never get here */ | |
| break; | |
| } | |
| } | |
| else | |
| { | |
| switch (err) | |
| { | |
| case TIFFReadDirEntryErrCount: | |
| TIFFWarningExtR(tif, module, | |
| "Incorrect count for \"%s\"; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrType: | |
| TIFFWarningExtR(tif, module, | |
| "Incompatible type for \"%s\"; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrIo: | |
| TIFFWarningExtR( | |
| tif, module, | |
| "IO error during reading of \"%s\"; tag ignored", tagname); | |
| break; | |
| case TIFFReadDirEntryErrRange: | |
| TIFFWarningExtR(tif, module, | |
| "Incorrect value for \"%s\"; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrPsdif: | |
| TIFFWarningExtR(tif, module, | |
| "Cannot handle different values per sample for " | |
| "\"%s\"; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrSizesan: | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Sanity check on size of \"%s\" value failed; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrAlloc: | |
| TIFFWarningExtR(tif, module, | |
| "Out of memory reading of \"%s\"; tag ignored", | |
| tagname); | |
| break; | |
| case TIFFReadDirEntryErrOk: | |
| default: | |
| assert(0); /* we should never get here */ | |
| break; | |
| } | |
| } | |
| } | |
| /* | |
| * Return the maximum number of color channels specified for a given photometric | |
| * type. 0 is returned if photometric type isn't supported or no default value | |
| * is defined by the specification. | |
| */ | |
| static int _TIFFGetMaxColorChannels(uint16_t photometric) | |
| { | |
| switch (photometric) | |
| { | |
| case PHOTOMETRIC_PALETTE: | |
| case PHOTOMETRIC_MINISWHITE: | |
| case PHOTOMETRIC_MINISBLACK: | |
| return 1; | |
| case PHOTOMETRIC_YCBCR: | |
| case PHOTOMETRIC_RGB: | |
| case PHOTOMETRIC_CIELAB: | |
| case PHOTOMETRIC_LOGLUV: | |
| case PHOTOMETRIC_ITULAB: | |
| case PHOTOMETRIC_ICCLAB: | |
| return 3; | |
| case PHOTOMETRIC_SEPARATED: | |
| case PHOTOMETRIC_MASK: | |
| return 4; | |
| case PHOTOMETRIC_LOGL: | |
| case PHOTOMETRIC_CFA: | |
| default: | |
| return 0; | |
| } | |
| } | |
| static int ByteCountLooksBad(TIFF *tif) | |
| { | |
| /* | |
| * Assume we have wrong StripByteCount value (in case | |
| * of single strip) in following cases: | |
| * - it is equal to zero along with StripOffset; | |
| * - it is larger than file itself (in case of uncompressed | |
| * image); | |
| * - it is smaller than the size of the bytes per row | |
| * multiplied on the number of rows. The last case should | |
| * not be checked in the case of writing new image, | |
| * because we may do not know the exact strip size | |
| * until the whole image will be written and directory | |
| * dumped out. | |
| */ | |
| uint64_t bytecount = TIFFGetStrileByteCount(tif, 0); | |
| uint64_t offset = TIFFGetStrileOffset(tif, 0); | |
| uint64_t filesize; | |
| if (offset == 0) | |
| return 0; | |
| if (bytecount == 0) | |
| return 1; | |
| if (tif->tif_dir.td_compression != COMPRESSION_NONE) | |
| return 0; | |
| filesize = TIFFGetFileSize(tif); | |
| if (offset <= filesize && bytecount > filesize - offset) | |
| return 1; | |
| if (tif->tif_mode == O_RDONLY) | |
| { | |
| uint64_t scanlinesize = TIFFScanlineSize64(tif); | |
| if (tif->tif_dir.td_imagelength > 0 && | |
| scanlinesize > UINT64_MAX / tif->tif_dir.td_imagelength) | |
| { | |
| return 1; | |
| } | |
| if (bytecount < scanlinesize * tif->tif_dir.td_imagelength) | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| /* | |
| * To evaluate the IFD data size when reading, save the offset and data size of | |
| * all data that does not fit into the IFD entries themselves. | |
| */ | |
| static bool EvaluateIFDdatasizeReading(TIFF *tif, TIFFDirEntry *dp) | |
| { | |
| const uint64_t data_width = | |
| (uint64_t)TIFFDataWidth((TIFFDataType)dp->tdir_type); | |
| if (data_width != 0 && dp->tdir_count > UINT64_MAX / data_width) | |
| { | |
| TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading", | |
| "Too large IFD data size"); | |
| return false; | |
| } | |
| const uint64_t datalength = dp->tdir_count * data_width; | |
| if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U)) | |
| { | |
| if (tif->tif_dir.td_dirdatasize_read > UINT64_MAX - datalength) | |
| { | |
| TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading", | |
| "Too large IFD data size"); | |
| return false; | |
| } | |
| tif->tif_dir.td_dirdatasize_read += datalength; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| /* The offset of TIFFDirEntry are not swapped when read in. That has | |
| * to be done when used. */ | |
| uint32_t offset = dp->tdir_offset.toff_long; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| tif->tif_dir | |
| .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] | |
| .offset = (uint64_t)offset; | |
| } | |
| else | |
| { | |
| tif->tif_dir | |
| .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] | |
| .offset = dp->tdir_offset.toff_long8; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8( | |
| &tif->tif_dir | |
| .td_dirdatasize_offsets[tif->tif_dir | |
| .td_dirdatasize_Noffsets] | |
| .offset); | |
| } | |
| tif->tif_dir | |
| .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] | |
| .length = datalength; | |
| tif->tif_dir.td_dirdatasize_Noffsets++; | |
| } | |
| return true; | |
| } | |
| /* | |
| * Compare function for qsort() sorting TIFFEntryOffsetAndLength array entries. | |
| */ | |
| static int cmpTIFFEntryOffsetAndLength(const void *a, const void *b) | |
| { | |
| const TIFFEntryOffsetAndLength *ta = (const TIFFEntryOffsetAndLength *)a; | |
| const TIFFEntryOffsetAndLength *tb = (const TIFFEntryOffsetAndLength *)b; | |
| /* Compare offsets */ | |
| if (ta->offset > tb->offset) | |
| return 1; | |
| else if (ta->offset < tb->offset) | |
| return -1; | |
| else | |
| return 0; | |
| } | |
| /* | |
| * Determine the IFD data size after reading an IFD from the file that can be | |
| * overwritten and saving it in tif_dir.td_dirdatasize_read. This data size | |
| * includes the IFD entries themselves as well as the data that does not fit | |
| * directly into the IFD entries but is located directly after the IFD entries | |
| * in the file. | |
| */ | |
| static void CalcFinalIFDdatasizeReading(TIFF *tif, uint16_t dircount) | |
| { | |
| /* IFD data size is only needed if file-writing is enabled. | |
| * This also avoids the seek() to EOF to determine the file size, which | |
| * causes the stdin-streaming-friendly mode of libtiff for GDAL to fail. */ | |
| if (tif->tif_mode == O_RDONLY) | |
| return; | |
| /* Sort TIFFEntryOffsetAndLength array in ascending order. */ | |
| qsort(tif->tif_dir.td_dirdatasize_offsets, | |
| tif->tif_dir.td_dirdatasize_Noffsets, | |
| sizeof(TIFFEntryOffsetAndLength), cmpTIFFEntryOffsetAndLength); | |
| /* Get offset of end of IFD entry space. */ | |
| uint64_t IFDendoffset; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| IFDendoffset = tif->tif_diroff + 2 + (uint64_t)dircount * 12 + 4; | |
| else | |
| IFDendoffset = tif->tif_diroff + 8 + (uint64_t)dircount * 20 + 8; | |
| /* Check which offsets are right behind IFD entries. However, LibTIFF | |
| * increments the writing address for every external data to an even offset. | |
| * Thus gaps of 1 byte can occur. */ | |
| uint64_t size = 0; | |
| uint64_t offset; | |
| uint32_t i; | |
| for (i = 0; i < tif->tif_dir.td_dirdatasize_Noffsets; i++) | |
| { | |
| offset = tif->tif_dir.td_dirdatasize_offsets[i].offset; | |
| if (offset == IFDendoffset) | |
| { | |
| size += tif->tif_dir.td_dirdatasize_offsets[i].length; | |
| IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length; | |
| } | |
| else if (offset == IFDendoffset + 1) | |
| { | |
| /* Add gap byte after previous IFD data set. */ | |
| size += tif->tif_dir.td_dirdatasize_offsets[i].length + 1; | |
| IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length; | |
| } | |
| else | |
| { | |
| /* Further data is no more continuously after IFD */ | |
| break; | |
| } | |
| } | |
| /* Check for gap byte of some easy cases. This should cover 90% of cases. | |
| * Otherwise, IFD will be re-written even it might be safely overwritten. */ | |
| if (tif->tif_nextdiroff != 0) | |
| { | |
| if (tif->tif_nextdiroff == IFDendoffset + 1) | |
| size++; | |
| } | |
| else | |
| { | |
| /* Check for IFD data ends at EOF. Then IFD can always be safely | |
| * overwritten. */ | |
| offset = TIFFSeekFile(tif, 0, SEEK_END); | |
| if (offset == IFDendoffset) | |
| { | |
| tif->tif_dir.td_dirdatasize_read = UINT64_MAX; | |
| return; | |
| } | |
| } | |
| /* Finally, add the size of the IFD tag entries themselves. */ | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| tif->tif_dir.td_dirdatasize_read = 2U + dircount * 12U + 4U + size; | |
| else | |
| tif->tif_dir.td_dirdatasize_read = 8U + dircount * 20U + 8U + size; | |
| } /*-- CalcFinalIFDdatasizeReading() --*/ | |
| /* | |
| * Read the next TIFF directory from a file and convert it to the internal | |
| * format. We read directories sequentially. | |
| */ | |
| int TIFFReadDirectory(TIFF *tif) | |
| { | |
| static const char module[] = "TIFFReadDirectory"; | |
| TIFFDirEntry *dir; | |
| uint16_t dircount; | |
| TIFFDirEntry *dp; | |
| uint16_t di; | |
| const TIFFField *fip; | |
| uint32_t fii = FAILED_FII; | |
| toff_t nextdiroff; | |
| int bitspersample_read = FALSE; | |
| int color_channels; | |
| if (tif->tif_nextdiroff == 0) | |
| { | |
| /* In this special case, tif_diroff needs also to be set to 0. | |
| * This is behind the last IFD, thus no checking or reading necessary. | |
| */ | |
| tif->tif_diroff = tif->tif_nextdiroff; | |
| return 0; | |
| } | |
| nextdiroff = tif->tif_nextdiroff; | |
| /* tif_curdir++ and tif_nextdiroff should only be updated after SUCCESSFUL | |
| * reading of the directory. Otherwise, invalid IFD offsets could corrupt | |
| * the IFD list. */ | |
| if (!_TIFFCheckDirNumberAndOffset(tif, | |
| tif->tif_curdir == | |
| TIFF_NON_EXISTENT_DIR_NUMBER | |
| ? 0 | |
| : tif->tif_curdir + 1, | |
| nextdiroff)) | |
| { | |
| return 0; /* bad offset (IFD looping or more than TIFF_MAX_DIR_COUNT | |
| IFDs) */ | |
| } | |
| dircount = TIFFFetchDirectory(tif, nextdiroff, &dir, &tif->tif_nextdiroff); | |
| if (!dircount) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Failed to read directory at offset %" PRIu64, | |
| nextdiroff); | |
| return 0; | |
| } | |
| /* Set global values after a valid directory has been fetched. | |
| * tif_diroff is already set to nextdiroff in TIFFFetchDirectory() in the | |
| * beginning. */ | |
| if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) | |
| tif->tif_curdir = 0; | |
| else | |
| tif->tif_curdir++; | |
| TIFFReadDirectoryCheckOrder(tif, dir, dircount); | |
| /* | |
| * Mark duplicates of any tag to be ignored (bugzilla 1994) | |
| * to avoid certain pathological problems. | |
| */ | |
| { | |
| TIFFDirEntry *ma; | |
| uint16_t mb; | |
| for (ma = dir, mb = 0; mb < dircount; ma++, mb++) | |
| { | |
| TIFFDirEntry *na; | |
| uint16_t nb; | |
| for (na = ma + 1, nb = (uint16_t)(mb + 1); nb < dircount; | |
| na++, nb++) | |
| { | |
| if (ma->tdir_tag == na->tdir_tag) | |
| { | |
| na->tdir_ignore = TRUE; | |
| } | |
| } | |
| } | |
| } | |
| tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ | |
| tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */ | |
| tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS; | |
| /* When changing directory, in deferred strile loading mode, we must also | |
| * unset the TIFF_LAZYSTRILELOAD_DONE bit if it was initially set, | |
| * to make sure the strile offset/bytecount are read again (when they fit | |
| * in the tag data area). | |
| */ | |
| tif->tif_flags &= ~TIFF_LAZYSTRILELOAD_DONE; | |
| /* Free any old stuff and reinit i/o and other parameters within | |
| * TIFFDefaultDirectory() since we are starting on a new directory. */ | |
| TIFFFreeDirectory(tif); | |
| TIFFDefaultDirectory(tif); | |
| /* After setup a fresh directory indicate that now active IFD is also | |
| * present on file, even if its entries could not be read successfully | |
| * below. */ | |
| tif->tif_dir.td_iswrittentofile = TRUE; | |
| /* Allocate arrays for offset values outside IFD entry for IFD data size | |
| * checking. Note: Counter are reset within TIFFFreeDirectory(). */ | |
| tif->tif_dir.td_dirdatasize_offsets = | |
| (TIFFEntryOffsetAndLength *)_TIFFmallocExt( | |
| tif, | |
| (tmsize_t)((size_t)dircount * sizeof(TIFFEntryOffsetAndLength))); | |
| if (tif->tif_dir.td_dirdatasize_offsets == NULL) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Failed to allocate memory for counting IFD data size at reading"); | |
| goto bad; | |
| } | |
| /* | |
| * Electronic Arts writes gray-scale TIFF files | |
| * without a PlanarConfiguration directory entry. | |
| * Thus we setup a default value here, even though | |
| * the TIFF spec says there is no default value. | |
| * After PlanarConfiguration is preset in TIFFDefaultDirectory() | |
| * the following setting is not needed, but does not harm either. | |
| */ | |
| TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); | |
| /* | |
| * Setup default value and then make a pass over | |
| * the fields to check type and tag information, | |
| * and to extract info required to size data | |
| * structures. A second pass is made afterwards | |
| * to read in everything not taken in the first pass. | |
| * But we must process the Compression tag first | |
| * in order to merge in codec-private tag definitions (otherwise | |
| * we may get complaints about unknown tags). However, the | |
| * Compression tag may be dependent on the SamplesPerPixel | |
| * tag value because older TIFF specs permitted Compression | |
| * to be written as a SamplesPerPixel-count tag entry. | |
| * Thus if we don't first figure out the correct SamplesPerPixel | |
| * tag value then we may end up ignoring the Compression tag | |
| * value because it has an incorrect count value (if the | |
| * true value of SamplesPerPixel is not 1). | |
| */ | |
| dp = | |
| TIFFReadDirectoryFindEntry(tif, dir, dircount, TIFFTAG_SAMPLESPERPIXEL); | |
| if (dp) | |
| { | |
| if (!TIFFFetchNormalTag(tif, dp, 0)) | |
| goto bad; | |
| dp->tdir_ignore = TRUE; | |
| } | |
| dp = TIFFReadDirectoryFindEntry(tif, dir, dircount, TIFFTAG_COMPRESSION); | |
| if (dp) | |
| { | |
| /* | |
| * The 5.0 spec says the Compression tag has one value, while | |
| * earlier specs say it has one value per sample. Because of | |
| * this, we accept the tag if one value is supplied with either | |
| * count. | |
| */ | |
| uint16_t value; | |
| enum TIFFReadDirEntryErr err; | |
| err = TIFFReadDirEntryShort(tif, dp, &value); | |
| if (err == TIFFReadDirEntryErrCount) | |
| err = TIFFReadDirEntryPersampleShort(tif, dp, &value); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| TIFFReadDirEntryOutputErr(tif, err, module, "Compression", 0); | |
| goto bad; | |
| } | |
| if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, value)) | |
| goto bad; | |
| dp->tdir_ignore = TRUE; | |
| } | |
| else | |
| { | |
| if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE)) | |
| goto bad; | |
| } | |
| /* | |
| * First real pass over the directory. | |
| */ | |
| for (di = 0, dp = dir; di < dircount; di++, dp++) | |
| { | |
| if (!dp->tdir_ignore) | |
| { | |
| TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); | |
| if (fii == FAILED_FII) | |
| { | |
| if (tif->tif_warn_about_unknown_tags) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Unknown field with tag %" PRIu16 | |
| " (0x%" PRIx16 ") encountered", | |
| dp->tdir_tag, dp->tdir_tag); | |
| } | |
| /* the following knowingly leaks the | |
| anonymous field structure */ | |
| const TIFFField *fld = _TIFFCreateAnonField( | |
| tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type); | |
| if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Registering anonymous field with tag %" PRIu16 | |
| " (0x%" PRIx16 ") failed", | |
| dp->tdir_tag, dp->tdir_tag); | |
| dp->tdir_ignore = TRUE; | |
| } | |
| else | |
| { | |
| TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); | |
| assert(fii != FAILED_FII); | |
| } | |
| } | |
| } | |
| if (!dp->tdir_ignore) | |
| { | |
| fip = tif->tif_fields[fii]; | |
| if (fip->field_bit == FIELD_IGNORE) | |
| dp->tdir_ignore = TRUE; | |
| else | |
| { | |
| switch (dp->tdir_tag) | |
| { | |
| case TIFFTAG_STRIPOFFSETS: | |
| case TIFFTAG_STRIPBYTECOUNTS: | |
| case TIFFTAG_TILEOFFSETS: | |
| case TIFFTAG_TILEBYTECOUNTS: | |
| TIFFSetFieldBit(tif, fip->field_bit); | |
| break; | |
| case TIFFTAG_IMAGEWIDTH: | |
| case TIFFTAG_IMAGELENGTH: | |
| case TIFFTAG_IMAGEDEPTH: | |
| case TIFFTAG_TILELENGTH: | |
| case TIFFTAG_TILEWIDTH: | |
| case TIFFTAG_TILEDEPTH: | |
| case TIFFTAG_PLANARCONFIG: | |
| case TIFFTAG_ROWSPERSTRIP: | |
| case TIFFTAG_EXTRASAMPLES: | |
| if (!TIFFFetchNormalTag(tif, dp, 0)) | |
| goto bad; | |
| dp->tdir_ignore = TRUE; | |
| break; | |
| default: | |
| if (!_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag)) | |
| dp->tdir_ignore = TRUE; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /* | |
| * XXX: OJPEG hack. | |
| * If a) compression is OJPEG, b) planarconfig tag says it's separate, | |
| * c) strip offsets/bytecounts tag are both present and | |
| * d) both contain exactly one value, then we consistently find | |
| * that the buggy implementation of the buggy compression scheme | |
| * matches contig planarconfig best. So we 'fix-up' the tag here | |
| */ | |
| if ((tif->tif_dir.td_compression == COMPRESSION_OJPEG) && | |
| (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)) | |
| { | |
| if (!_TIFFFillStriles(tif)) | |
| goto bad; | |
| dp = TIFFReadDirectoryFindEntry(tif, dir, dircount, | |
| TIFFTAG_STRIPOFFSETS); | |
| if ((dp != 0) && (dp->tdir_count == 1)) | |
| { | |
| dp = TIFFReadDirectoryFindEntry(tif, dir, dircount, | |
| TIFFTAG_STRIPBYTECOUNTS); | |
| if ((dp != 0) && (dp->tdir_count == 1)) | |
| { | |
| tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG; | |
| TIFFWarningExtR(tif, module, | |
| "Planarconfig tag value assumed incorrect, " | |
| "assuming data is contig instead of chunky"); | |
| } | |
| } | |
| } | |
| /* | |
| * Allocate directory structure and setup defaults. | |
| */ | |
| if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) | |
| { | |
| MissingRequired(tif, "ImageLength"); | |
| goto bad; | |
| } | |
| /* | |
| * Second pass: extract other information. | |
| */ | |
| for (di = 0, dp = dir; di < dircount; di++, dp++) | |
| { | |
| if (!dp->tdir_ignore) | |
| { | |
| switch (dp->tdir_tag) | |
| { | |
| case TIFFTAG_MINSAMPLEVALUE: | |
| case TIFFTAG_MAXSAMPLEVALUE: | |
| case TIFFTAG_BITSPERSAMPLE: | |
| case TIFFTAG_DATATYPE: | |
| case TIFFTAG_SAMPLEFORMAT: | |
| /* | |
| * The MinSampleValue, MaxSampleValue, BitsPerSample | |
| * DataType and SampleFormat tags are supposed to be | |
| * written as one value/sample, but some vendors | |
| * incorrectly write one value only -- so we accept | |
| * that as well (yuck). Other vendors write correct | |
| * value for NumberOfSamples, but incorrect one for | |
| * BitsPerSample and friends, and we will read this | |
| * too. | |
| */ | |
| { | |
| uint16_t value; | |
| enum TIFFReadDirEntryErr err; | |
| err = TIFFReadDirEntryShort(tif, dp, &value); | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| goto bad; | |
| if (err == TIFFReadDirEntryErrCount) | |
| err = | |
| TIFFReadDirEntryPersampleShort(tif, dp, &value); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFReadDirEntryOutputErr( | |
| tif, err, module, | |
| fip ? fip->field_name : "unknown tagname", 0); | |
| goto bad; | |
| } | |
| if (!TIFFSetField(tif, dp->tdir_tag, value)) | |
| goto bad; | |
| if (dp->tdir_tag == TIFFTAG_BITSPERSAMPLE) | |
| bitspersample_read = TRUE; | |
| } | |
| break; | |
| case TIFFTAG_SMINSAMPLEVALUE: | |
| case TIFFTAG_SMAXSAMPLEVALUE: | |
| { | |
| double *data = NULL; | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t saved_flags; | |
| int m; | |
| if (dp->tdir_count != | |
| (uint64_t)tif->tif_dir.td_samplesperpixel) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| err = TIFFReadDirEntryDoubleArray(tif, dp, &data); | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| goto bad; | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFReadDirEntryOutputErr( | |
| tif, err, module, | |
| fip ? fip->field_name : "unknown tagname", 0); | |
| goto bad; | |
| } | |
| saved_flags = tif->tif_flags; | |
| tif->tif_flags |= TIFF_PERSAMPLE; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| tif->tif_flags = saved_flags; | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| goto bad; | |
| } | |
| break; | |
| case TIFFTAG_STRIPOFFSETS: | |
| case TIFFTAG_TILEOFFSETS: | |
| { | |
| switch (dp->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| case TIFF_LONG: | |
| case TIFF_LONG8: | |
| break; | |
| default: | |
| /* Warn except if directory typically created with | |
| * TIFFDeferStrileArrayWriting() */ | |
| if (!(tif->tif_mode == O_RDWR && | |
| dp->tdir_count == 0 && dp->tdir_type == 0 && | |
| dp->tdir_offset.toff_long8 == 0)) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFWarningExtR( | |
| tif, module, "Invalid data type for tag %s", | |
| fip ? fip->field_name : "unknown tagname"); | |
| } | |
| break; | |
| } | |
| _TIFFmemcpy(&(tif->tif_dir.td_stripoffset_entry), dp, | |
| sizeof(TIFFDirEntry)); | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFFTAG_STRIPBYTECOUNTS: | |
| case TIFFTAG_TILEBYTECOUNTS: | |
| { | |
| switch (dp->tdir_type) | |
| { | |
| case TIFF_SHORT: | |
| case TIFF_LONG: | |
| case TIFF_LONG8: | |
| break; | |
| default: | |
| /* Warn except if directory typically created with | |
| * TIFFDeferStrileArrayWriting() */ | |
| if (!(tif->tif_mode == O_RDWR && | |
| dp->tdir_count == 0 && dp->tdir_type == 0 && | |
| dp->tdir_offset.toff_long8 == 0)) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFWarningExtR( | |
| tif, module, "Invalid data type for tag %s", | |
| fip ? fip->field_name : "unknown tagname"); | |
| } | |
| break; | |
| } | |
| _TIFFmemcpy(&(tif->tif_dir.td_stripbytecount_entry), dp, | |
| sizeof(TIFFDirEntry)); | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| goto bad; | |
| } | |
| break; | |
| case TIFFTAG_COLORMAP: | |
| case TIFFTAG_TRANSFERFUNCTION: | |
| { | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t countpersample; | |
| uint32_t countrequired; | |
| uint32_t incrementpersample; | |
| uint16_t *value = NULL; | |
| /* It would be dangerous to instantiate those tag values */ | |
| /* since if td_bitspersample has not yet been read (due to | |
| */ | |
| /* unordered tags), it could be read afterwards with a */ | |
| /* values greater than the default one (1), which may cause | |
| */ | |
| /* crashes in user code */ | |
| if (!bitspersample_read) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Ignoring %s since BitsPerSample tag not found", | |
| fip ? fip->field_name : "unknown tagname"); | |
| continue; | |
| } | |
| /* ColorMap or TransferFunction for high bit */ | |
| /* depths do not make much sense and could be */ | |
| /* used as a denial of service vector */ | |
| if (tif->tif_dir.td_bitspersample > 24) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Ignoring %s because BitsPerSample=%" PRIu16 ">24", | |
| fip ? fip->field_name : "unknown tagname", | |
| tif->tif_dir.td_bitspersample); | |
| continue; | |
| } | |
| countpersample = (1U << tif->tif_dir.td_bitspersample); | |
| if ((dp->tdir_tag == TIFFTAG_TRANSFERFUNCTION) && | |
| (dp->tdir_count == (uint64_t)countpersample)) | |
| { | |
| countrequired = countpersample; | |
| incrementpersample = 0; | |
| } | |
| else | |
| { | |
| countrequired = 3 * countpersample; | |
| incrementpersample = countpersample; | |
| } | |
| if (dp->tdir_count != (uint64_t)countrequired) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| err = TIFFReadDirEntryShortArray(tif, dp, &value); | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| goto bad; | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFReadDirEntryOutputErr( | |
| tif, err, module, | |
| fip ? fip->field_name : "unknown tagname", 1); | |
| } | |
| else | |
| { | |
| TIFFSetField(tif, dp->tdir_tag, value, | |
| value + incrementpersample, | |
| value + 2 * incrementpersample); | |
| _TIFFfreeExt(tif, value); | |
| } | |
| } | |
| break; | |
| /* BEGIN REV 4.0 COMPATIBILITY */ | |
| case TIFFTAG_OSUBFILETYPE: | |
| { | |
| uint16_t valueo; | |
| uint32_t value; | |
| if (TIFFReadDirEntryShort(tif, dp, &valueo) == | |
| TIFFReadDirEntryErrOk) | |
| { | |
| switch (valueo) | |
| { | |
| case OFILETYPE_REDUCEDIMAGE: | |
| value = FILETYPE_REDUCEDIMAGE; | |
| break; | |
| case OFILETYPE_PAGE: | |
| value = FILETYPE_PAGE; | |
| break; | |
| default: | |
| value = 0; | |
| break; | |
| } | |
| if (value != 0) | |
| TIFFSetField(tif, TIFFTAG_SUBFILETYPE, value); | |
| } | |
| } | |
| break; | |
| /* END REV 4.0 COMPATIBILITY */ | |
| #if 0 | |
| case TIFFTAG_EP_BATTERYLEVEL: | |
| /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. | |
| * LibTiff defines it as ASCII and converts RATIONAL to an | |
| * ASCII string. */ | |
| switch (dp->tdir_type) | |
| { | |
| case TIFF_RATIONAL: | |
| { | |
| /* Read rational and convert to ASCII*/ | |
| enum TIFFReadDirEntryErr err; | |
| TIFFRational_t rValue; | |
| err = TIFFReadDirEntryCheckedRationalDirect( | |
| tif, dp, &rValue); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFReadDirEntryOutputErr( | |
| tif, err, module, | |
| fip ? fip->field_name : "unknown tagname", | |
| 1); | |
| } | |
| else | |
| { | |
| char szAux[32]; | |
| snprintf(szAux, sizeof(szAux) - 1, "%d/%d", | |
| rValue.uNum, rValue.uDenom); | |
| TIFFSetField(tif, dp->tdir_tag, szAux); | |
| } | |
| } | |
| break; | |
| case TIFF_ASCII: | |
| (void)TIFFFetchNormalTag(tif, dp, TRUE); | |
| break; | |
| default: | |
| fip = TIFFFieldWithTag(tif, dp->tdir_tag); | |
| TIFFWarningExtR(tif, module, | |
| "Invalid data type for tag %s. " | |
| "ASCII or RATIONAL expected", | |
| fip ? fip->field_name | |
| : "unknown tagname"); | |
| break; | |
| } | |
| break; | |
| #endif | |
| default: | |
| (void)TIFFFetchNormalTag(tif, dp, TRUE); | |
| break; | |
| } /* -- switch (dp->tdir_tag) -- */ | |
| } /* -- if (!dp->tdir_ignore) */ | |
| } /* -- for-loop -- */ | |
| /* Evaluate final IFD data size. */ | |
| CalcFinalIFDdatasizeReading(tif, dircount); | |
| /* | |
| * OJPEG hack: | |
| * - If a) compression is OJPEG, and b) photometric tag is missing, | |
| * then we consistently find that photometric should be YCbCr | |
| * - If a) compression is OJPEG, and b) photometric tag says it's RGB, | |
| * then we consistently find that the buggy implementation of the | |
| * buggy compression scheme matches photometric YCbCr instead. | |
| * - If a) compression is OJPEG, and b) bitspersample tag is missing, | |
| * then we consistently find bitspersample should be 8. | |
| * - If a) compression is OJPEG, b) samplesperpixel tag is missing, | |
| * and c) photometric is RGB or YCbCr, then we consistently find | |
| * samplesperpixel should be 3 | |
| * - If a) compression is OJPEG, b) samplesperpixel tag is missing, | |
| * and c) photometric is MINISWHITE or MINISBLACK, then we consistently | |
| * find samplesperpixel should be 3 | |
| */ | |
| if (tif->tif_dir.td_compression == COMPRESSION_OJPEG) | |
| { | |
| if (!TIFFFieldSet(tif, FIELD_PHOTOMETRIC)) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Photometric tag is missing, assuming data is YCbCr"); | |
| if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR)) | |
| goto bad; | |
| } | |
| else if (tif->tif_dir.td_photometric == PHOTOMETRIC_RGB) | |
| { | |
| tif->tif_dir.td_photometric = PHOTOMETRIC_YCBCR; | |
| TIFFWarningExtR(tif, module, | |
| "Photometric tag value assumed incorrect, " | |
| "assuming data is YCbCr instead of RGB"); | |
| } | |
| if (!TIFFFieldSet(tif, FIELD_BITSPERSAMPLE)) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "BitsPerSample tag is missing, assuming 8 bits per sample"); | |
| if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8)) | |
| goto bad; | |
| } | |
| if (!TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) | |
| { | |
| if (tif->tif_dir.td_photometric == PHOTOMETRIC_RGB) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "SamplesPerPixel tag is missing, " | |
| "assuming correct SamplesPerPixel value is 3"); | |
| if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3)) | |
| goto bad; | |
| } | |
| if (tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "SamplesPerPixel tag is missing, " | |
| "applying correct SamplesPerPixel value of 3"); | |
| if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3)) | |
| goto bad; | |
| } | |
| else if ((tif->tif_dir.td_photometric == PHOTOMETRIC_MINISWHITE) || | |
| (tif->tif_dir.td_photometric == PHOTOMETRIC_MINISBLACK)) | |
| { | |
| /* | |
| * SamplesPerPixel tag is missing, but is not required | |
| * by spec. Assume correct SamplesPerPixel value of 1. | |
| */ | |
| if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1)) | |
| goto bad; | |
| } | |
| } | |
| } | |
| /* | |
| * Setup appropriate structures (by strip or by tile) | |
| * We do that only after the above OJPEG hack which alters SamplesPerPixel | |
| * and thus influences the number of strips in the separate planarconfig. | |
| */ | |
| if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) | |
| { | |
| tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif); | |
| tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth; | |
| tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip; | |
| tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth; | |
| tif->tif_flags &= ~TIFF_ISTILED; | |
| } | |
| else | |
| { | |
| tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif); | |
| tif->tif_flags |= TIFF_ISTILED; | |
| } | |
| if (!tif->tif_dir.td_nstrips) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot handle zero number of %s", | |
| isTiled(tif) ? "tiles" : "strips"); | |
| goto bad; | |
| } | |
| if (tif->tif_dir.td_nstrips > INT_MAX) | |
| { | |
| TIFFErrorExt(tif->tif_clientdata, module, | |
| "Cannot handle %u number of %s", | |
| tif->tif_dir.td_nstrips, | |
| isTiled(tif) ? "tiles" : "strips"); | |
| goto bad; | |
| } | |
| tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; | |
| if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) | |
| tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; | |
| if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) | |
| { | |
| #ifdef OJPEG_SUPPORT | |
| if ((tif->tif_dir.td_compression == COMPRESSION_OJPEG) && | |
| (isTiled(tif) == 0) && (tif->tif_dir.td_nstrips == 1)) | |
| { | |
| /* | |
| * 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. | |
| */ | |
| TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); | |
| } | |
| else | |
| #endif | |
| { | |
| MissingRequired(tif, isTiled(tif) ? "TileOffsets" : "StripOffsets"); | |
| goto bad; | |
| } | |
| } | |
| if (tif->tif_mode == O_RDWR && | |
| tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && | |
| 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_stripbytecount_entry.tdir_tag != 0 && | |
| 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) | |
| { | |
| /* Directory typically created with TIFFDeferStrileArrayWriting() */ | |
| TIFFSetupStrips(tif); | |
| } | |
| else if (!(tif->tif_flags & TIFF_DEFERSTRILELOAD)) | |
| { | |
| if (tif->tif_dir.td_stripoffset_entry.tdir_tag != 0) | |
| { | |
| if (!TIFFFetchStripThing(tif, &(tif->tif_dir.td_stripoffset_entry), | |
| tif->tif_dir.td_nstrips, | |
| &tif->tif_dir.td_stripoffset_p)) | |
| { | |
| goto bad; | |
| } | |
| } | |
| if (tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0) | |
| { | |
| if (!TIFFFetchStripThing( | |
| tif, &(tif->tif_dir.td_stripbytecount_entry), | |
| tif->tif_dir.td_nstrips, &tif->tif_dir.td_stripbytecount_p)) | |
| { | |
| goto bad; | |
| } | |
| } | |
| } | |
| /* | |
| * Make sure all non-color channels are extrasamples. | |
| * If it's not the case, define them as such. | |
| */ | |
| color_channels = _TIFFGetMaxColorChannels(tif->tif_dir.td_photometric); | |
| if (color_channels && | |
| tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples > | |
| color_channels) | |
| { | |
| uint16_t old_extrasamples; | |
| uint16_t *new_sampleinfo; | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Sum of Photometric type-related " | |
| "color channels and ExtraSamples doesn't match SamplesPerPixel. " | |
| "Defining non-color channels as ExtraSamples."); | |
| old_extrasamples = tif->tif_dir.td_extrasamples; | |
| tif->tif_dir.td_extrasamples = | |
| (uint16_t)(tif->tif_dir.td_samplesperpixel - color_channels); | |
| // sampleinfo should contain information relative to these new extra | |
| // samples | |
| new_sampleinfo = (uint16_t *)_TIFFcallocExt( | |
| tif, tif->tif_dir.td_extrasamples, sizeof(uint16_t)); | |
| if (!new_sampleinfo) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Failed to allocate memory for " | |
| "temporary new sampleinfo array " | |
| "(%" PRIu16 " 16 bit elements)", | |
| tif->tif_dir.td_extrasamples); | |
| goto bad; | |
| } | |
| if (old_extrasamples > 0) | |
| memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, | |
| old_extrasamples * sizeof(uint16_t)); | |
| _TIFFsetShortArrayExt(tif, &tif->tif_dir.td_sampleinfo, new_sampleinfo, | |
| tif->tif_dir.td_extrasamples); | |
| _TIFFfreeExt(tif, new_sampleinfo); | |
| } | |
| /* | |
| * Verify Palette image has a Colormap. | |
| */ | |
| if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE && | |
| !TIFFFieldSet(tif, FIELD_COLORMAP)) | |
| { | |
| if (tif->tif_dir.td_bitspersample >= 8 && | |
| tif->tif_dir.td_samplesperpixel == 3) | |
| tif->tif_dir.td_photometric = PHOTOMETRIC_RGB; | |
| else if (tif->tif_dir.td_bitspersample >= 8) | |
| tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK; | |
| else | |
| { | |
| MissingRequired(tif, "Colormap"); | |
| goto bad; | |
| } | |
| } | |
| /* | |
| * OJPEG hack: | |
| * We do no further messing with strip/tile offsets/bytecounts in OJPEG | |
| * TIFFs | |
| */ | |
| if (tif->tif_dir.td_compression != COMPRESSION_OJPEG) | |
| { | |
| /* | |
| * Attempt to deal with a missing StripByteCounts tag. | |
| */ | |
| if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) | |
| { | |
| /* | |
| * Some manufacturers violate the spec by not giving | |
| * the size of the strips. In this case, assume there | |
| * is one uncompressed strip of data. | |
| */ | |
| if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && | |
| tif->tif_dir.td_nstrips > 1) || | |
| (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE && | |
| tif->tif_dir.td_nstrips != | |
| (uint32_t)tif->tif_dir.td_samplesperpixel)) | |
| { | |
| MissingRequired(tif, "StripByteCounts"); | |
| goto bad; | |
| } | |
| TIFFWarningExtR( | |
| tif, module, | |
| "TIFF directory is missing required " | |
| "\"StripByteCounts\" field, calculating from imagelength"); | |
| if (EstimateStripByteCounts(tif, dir, dircount) < 0) | |
| goto bad; | |
| } | |
| else if (tif->tif_dir.td_nstrips == 1 && | |
| !(tif->tif_flags & TIFF_ISTILED) && ByteCountLooksBad(tif)) | |
| { | |
| /* | |
| * XXX: Plexus (and others) sometimes give a value of | |
| * zero for a tag when they don't know what the | |
| * correct value is! Try and handle the simple case | |
| * of estimating the size of a one strip image. | |
| */ | |
| TIFFWarningExtR(tif, module, | |
| "Bogus \"StripByteCounts\" field, ignoring and " | |
| "calculating from imagelength"); | |
| if (EstimateStripByteCounts(tif, dir, dircount) < 0) | |
| goto bad; | |
| } | |
| else if (!(tif->tif_flags & TIFF_DEFERSTRILELOAD) && | |
| tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && | |
| tif->tif_dir.td_nstrips > 2 && | |
| tif->tif_dir.td_compression == COMPRESSION_NONE && | |
| TIFFGetStrileByteCount(tif, 0) != | |
| TIFFGetStrileByteCount(tif, 1) && | |
| TIFFGetStrileByteCount(tif, 0) != 0 && | |
| TIFFGetStrileByteCount(tif, 1) != 0) | |
| { | |
| /* | |
| * XXX: Some vendors fill StripByteCount array with | |
| * absolutely wrong values (it can be equal to | |
| * StripOffset array, for example). Catch this case | |
| * here. | |
| * | |
| * We avoid this check if deferring strile loading | |
| * as it would always force us to load the strip/tile | |
| * information. | |
| */ | |
| TIFFWarningExtR(tif, module, | |
| "Wrong \"StripByteCounts\" field, ignoring and " | |
| "calculating from imagelength"); | |
| if (EstimateStripByteCounts(tif, dir, dircount) < 0) | |
| goto bad; | |
| } | |
| } | |
| if (dir) | |
| { | |
| _TIFFfreeExt(tif, dir); | |
| dir = NULL; | |
| } | |
| if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) | |
| { | |
| if (tif->tif_dir.td_bitspersample >= 16) | |
| tif->tif_dir.td_maxsamplevalue = 0xFFFF; | |
| else | |
| tif->tif_dir.td_maxsamplevalue = | |
| (uint16_t)((1 << tif->tif_dir.td_bitspersample) - 1); | |
| } | |
| #ifdef STRIPBYTECOUNTSORTED_UNUSED | |
| /* | |
| * XXX: We can optimize checking for the strip bounds using the sorted | |
| * bytecounts array. See also comments for TIFFAppendToStrip() | |
| * function in tif_write.c. | |
| */ | |
| if (!(tif->tif_flags & TIFF_DEFERSTRILELOAD) && tif->tif_dir.td_nstrips > 1) | |
| { | |
| uint32_t strip; | |
| tif->tif_dir.td_stripbytecountsorted = 1; | |
| for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) | |
| { | |
| if (TIFFGetStrileOffset(tif, strip - 1) > | |
| TIFFGetStrileOffset(tif, strip)) | |
| { | |
| tif->tif_dir.td_stripbytecountsorted = 0; | |
| break; | |
| } | |
| } | |
| } | |
| #endif | |
| /* | |
| * An opportunity for compression mode dependent tag fixup | |
| */ | |
| (*tif->tif_fixuptags)(tif); | |
| /* | |
| * Some manufacturers make life difficult by writing | |
| * large amounts of uncompressed data as a single strip. | |
| * This is contrary to the recommendations of the spec. | |
| * The following makes an attempt at breaking such images | |
| * into strips closer to the recommended 8k bytes. A | |
| * side effect, however, is that the RowsPerStrip tag | |
| * value may be changed. | |
| */ | |
| if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) && | |
| (tif->tif_dir.td_nstrips == 1) && | |
| (tif->tif_dir.td_compression == COMPRESSION_NONE) && | |
| ((tif->tif_flags & (TIFF_STRIPCHOP | TIFF_ISTILED)) == TIFF_STRIPCHOP)) | |
| { | |
| ChopUpSingleUncompressedStrip(tif); | |
| } | |
| /* There are also uncompressed striped files with strips larger than */ | |
| /* 2 GB, which make them unfriendly with a lot of code. If possible, */ | |
| /* try to expose smaller "virtual" strips. */ | |
| if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && | |
| tif->tif_dir.td_compression == COMPRESSION_NONE && | |
| (tif->tif_flags & (TIFF_STRIPCHOP | TIFF_ISTILED)) == TIFF_STRIPCHOP && | |
| TIFFStripSize64(tif) > 0x7FFFFFFFUL) | |
| { | |
| TryChopUpUncompressedBigTiff(tif); | |
| } | |
| /* | |
| * Clear the dirty directory flag. | |
| */ | |
| tif->tif_flags &= ~TIFF_DIRTYDIRECT; | |
| tif->tif_flags &= ~TIFF_DIRTYSTRIP; | |
| /* | |
| * Reinitialize some further i/o since we are starting on a new directory. | |
| */ | |
| tif->tif_dir.td_scanlinesize = TIFFScanlineSize(tif); | |
| if (!tif->tif_dir.td_scanlinesize) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot handle zero scanline size"); | |
| return (0); | |
| } | |
| if (isTiled(tif)) | |
| { | |
| tif->tif_dir.td_tilesize = TIFFTileSize(tif); | |
| if (!tif->tif_dir.td_tilesize) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot handle zero tile size"); | |
| return (0); | |
| } | |
| } | |
| else | |
| { | |
| if (!TIFFStripSize(tif)) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot handle zero strip size"); | |
| return (0); | |
| } | |
| } | |
| return (1); | |
| bad: | |
| if (dir) | |
| _TIFFfreeExt(tif, dir); | |
| return (0); | |
| } /*-- TIFFReadDirectory() --*/ | |
| static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount) | |
| { | |
| static const char module[] = "TIFFReadDirectoryCheckOrder"; | |
| uint32_t m; | |
| uint16_t n; | |
| TIFFDirEntry *o; | |
| m = 0; | |
| for (n = 0, o = dir; n < dircount; n++, o++) | |
| { | |
| if (o->tdir_tag < m) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Invalid TIFF directory; tags are not sorted in " | |
| "ascending order"); | |
| break; | |
| } | |
| m = o->tdir_tag + 1U; | |
| } | |
| } | |
| static TIFFDirEntry *TIFFReadDirectoryFindEntry(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount, | |
| uint16_t tagid) | |
| { | |
| TIFFDirEntry *m; | |
| uint16_t n; | |
| (void)tif; | |
| for (m = dir, n = 0; n < dircount; m++, n++) | |
| { | |
| if (m->tdir_tag == tagid) | |
| return (m); | |
| } | |
| return (0); | |
| } | |
| static void TIFFReadDirectoryFindFieldInfo(TIFF *tif, uint16_t tagid, | |
| uint32_t *fii) | |
| { | |
| int32_t ma, mb, mc; | |
| ma = -1; | |
| mc = (int32_t)tif->tif_nfields; | |
| while (1) | |
| { | |
| if (ma + 1 == mc) | |
| { | |
| *fii = FAILED_FII; | |
| return; | |
| } | |
| mb = (ma + mc) / 2; | |
| if (tif->tif_fields[mb]->field_tag == (uint32_t)tagid) | |
| break; | |
| if (tif->tif_fields[mb]->field_tag < (uint32_t)tagid) | |
| ma = mb; | |
| else | |
| mc = mb; | |
| } | |
| while (1) | |
| { | |
| if (mb == 0) | |
| break; | |
| if (tif->tif_fields[mb - 1]->field_tag != (uint32_t)tagid) | |
| break; | |
| mb--; | |
| } | |
| *fii = (uint32_t)mb; | |
| } | |
| /* | |
| * Read custom directory from the arbitrary offset. | |
| * The code is very similar to TIFFReadDirectory(). | |
| */ | |
| int TIFFReadCustomDirectory(TIFF *tif, toff_t diroff, | |
| const TIFFFieldArray *infoarray) | |
| { | |
| static const char module[] = "TIFFReadCustomDirectory"; | |
| TIFFDirEntry *dir; | |
| uint16_t dircount; | |
| TIFFDirEntry *dp; | |
| uint16_t di; | |
| const TIFFField *fip; | |
| uint32_t fii; | |
| assert(infoarray != NULL); | |
| dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); | |
| if (!dircount) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Failed to read custom directory at offset %" PRIu64, | |
| diroff); | |
| return 0; | |
| } | |
| TIFFReadDirectoryCheckOrder(tif, dir, dircount); | |
| /* | |
| * Mark duplicates of any tag to be ignored (bugzilla 1994) | |
| * to avoid certain pathological problems. | |
| */ | |
| { | |
| TIFFDirEntry *ma; | |
| uint16_t mb; | |
| for (ma = dir, mb = 0; mb < dircount; ma++, mb++) | |
| { | |
| TIFFDirEntry *na; | |
| uint16_t nb; | |
| for (na = ma + 1, nb = (uint16_t)(mb + 1); nb < dircount; | |
| na++, nb++) | |
| { | |
| if (ma->tdir_tag == na->tdir_tag) | |
| { | |
| na->tdir_ignore = TRUE; | |
| } | |
| } | |
| } | |
| } | |
| /* Free any old stuff and reinit. */ | |
| TIFFFreeDirectory(tif); | |
| /* Even if custom directories do not need the default settings of a standard | |
| * IFD, the pointer to the TIFFSetField() and TIFFGetField() (i.e. | |
| * tif->tif_tagmethods.vsetfield and tif->tif_tagmethods.vgetfield) need to | |
| * be initialized, which is done in TIFFDefaultDirectory(). | |
| * After that, the field array for the custom tags needs to be setup again. | |
| */ | |
| TIFFDefaultDirectory(tif); | |
| _TIFFSetupFields(tif, infoarray); | |
| /* Allocate arrays for offset values outside IFD entry for IFD data size | |
| * checking. Note: Counter are reset within TIFFFreeDirectory(). */ | |
| tif->tif_dir.td_dirdatasize_offsets = | |
| (TIFFEntryOffsetAndLength *)_TIFFmallocExt( | |
| tif, | |
| (tmsize_t)((size_t)dircount * sizeof(TIFFEntryOffsetAndLength))); | |
| if (tif->tif_dir.td_dirdatasize_offsets == NULL) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Failed to allocate memory for counting IFD data size at reading"); | |
| if (dir) | |
| _TIFFfreeExt(tif, dir); | |
| return 0; | |
| } | |
| for (di = 0, dp = dir; di < dircount; di++, dp++) | |
| { | |
| TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); | |
| if (fii == FAILED_FII) | |
| { | |
| if (tif->tif_warn_about_unknown_tags) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Unknown field with tag %" PRIu16 " (0x%" PRIx16 | |
| ") encountered", | |
| dp->tdir_tag, dp->tdir_tag); | |
| } | |
| const TIFFField *fld = _TIFFCreateAnonField( | |
| tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type); | |
| if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) | |
| { | |
| if (tif->tif_warn_about_unknown_tags) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Registering anonymous field with tag %" PRIu16 | |
| " (0x%" PRIx16 ") failed", | |
| dp->tdir_tag, dp->tdir_tag); | |
| } | |
| dp->tdir_ignore = TRUE; | |
| } | |
| else | |
| { | |
| TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); | |
| assert(fii != FAILED_FII); | |
| } | |
| } | |
| if (!dp->tdir_ignore) | |
| { | |
| fip = tif->tif_fields[fii]; | |
| if (fip->field_bit == FIELD_IGNORE) | |
| dp->tdir_ignore = TRUE; | |
| else | |
| { | |
| /* check data type */ | |
| while ((fip->field_type != TIFF_ANY) && | |
| (fip->field_type != dp->tdir_type)) | |
| { | |
| fii++; | |
| if ((fii == tif->tif_nfields) || | |
| (tif->tif_fields[fii]->field_tag != | |
| (uint32_t)dp->tdir_tag)) | |
| { | |
| fii = 0xFFFF; | |
| break; | |
| } | |
| fip = tif->tif_fields[fii]; | |
| } | |
| if (fii == 0xFFFF) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "Wrong data type %" PRIu16 | |
| " for \"%s\"; tag ignored", | |
| dp->tdir_type, fip->field_name); | |
| dp->tdir_ignore = TRUE; | |
| } | |
| else | |
| { | |
| /* check count if known in advance */ | |
| if ((fip->field_readcount != TIFF_VARIABLE) && | |
| (fip->field_readcount != TIFF_VARIABLE2)) | |
| { | |
| uint32_t expected; | |
| if (fip->field_readcount == TIFF_SPP) | |
| expected = | |
| (uint32_t)tif->tif_dir.td_samplesperpixel; | |
| else | |
| expected = (uint32_t)fip->field_readcount; | |
| if (!CheckDirCount(tif, dp, expected)) | |
| dp->tdir_ignore = TRUE; | |
| } | |
| } | |
| } | |
| if (!dp->tdir_ignore) | |
| { | |
| switch (dp->tdir_tag) | |
| { | |
| case EXIFTAG_SUBJECTDISTANCE: | |
| if (!TIFFFieldIsAnonymous(fip)) | |
| { | |
| /* should only be called on a Exif directory */ | |
| /* when exifFields[] is active */ | |
| (void)TIFFFetchSubjectDistance(tif, dp); | |
| } | |
| else | |
| { | |
| (void)TIFFFetchNormalTag(tif, dp, TRUE); | |
| } | |
| break; | |
| default: | |
| (void)TIFFFetchNormalTag(tif, dp, TRUE); | |
| break; | |
| } | |
| } /*-- if (!dp->tdir_ignore) */ | |
| } | |
| } | |
| /* Evaluate final IFD data size. */ | |
| CalcFinalIFDdatasizeReading(tif, dircount); | |
| /* To be able to return from SubIFD or custom-IFD to main-IFD */ | |
| tif->tif_setdirectory_force_absolute = TRUE; | |
| if (dir) | |
| _TIFFfreeExt(tif, dir); | |
| return 1; | |
| } | |
| /* | |
| * EXIF is important special case of custom IFD, so we have a special | |
| * function to read it. | |
| */ | |
| int TIFFReadEXIFDirectory(TIFF *tif, toff_t diroff) | |
| { | |
| return TIFFReadCustomDirectory(tif, diroff, _TIFFGetExifFields()); | |
| } | |
| /* | |
| *--: EXIF-GPS custom directory reading as another special case of custom IFD. | |
| */ | |
| int TIFFReadGPSDirectory(TIFF *tif, toff_t diroff) | |
| { | |
| return TIFFReadCustomDirectory(tif, diroff, _TIFFGetGpsFields()); | |
| } | |
| static int EstimateStripByteCounts(TIFF *tif, TIFFDirEntry *dir, | |
| uint16_t dircount) | |
| { | |
| static const char module[] = "EstimateStripByteCounts"; | |
| TIFFDirEntry *dp; | |
| TIFFDirectory *td = &tif->tif_dir; | |
| uint32_t strip; | |
| /* Do not try to load stripbytecount as we will compute it */ | |
| if (!_TIFFFillStrilesInternal(tif, 0)) | |
| return -1; | |
| const uint64_t allocsize = (uint64_t)td->td_nstrips * sizeof(uint64_t); | |
| uint64_t filesize = 0; | |
| if (allocsize > 100 * 1024 * 1024) | |
| { | |
| /* Before allocating a huge amount of memory for corrupted files, check | |
| * if size of requested memory is not greater than file size. */ | |
| filesize = TIFFGetFileSize(tif); | |
| if (allocsize > filesize) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Requested memory size for StripByteCounts of %" PRIu64 | |
| " is greater than filesize %" PRIu64 ". Memory not allocated", | |
| allocsize, filesize); | |
| return -1; | |
| } | |
| } | |
| if (td->td_stripbytecount_p) | |
| _TIFFfreeExt(tif, td->td_stripbytecount_p); | |
| td->td_stripbytecount_p = (uint64_t *)_TIFFCheckMalloc( | |
| tif, td->td_nstrips, sizeof(uint64_t), "for \"StripByteCounts\" array"); | |
| if (td->td_stripbytecount_p == NULL) | |
| return -1; | |
| if (td->td_compression != COMPRESSION_NONE) | |
| { | |
| uint64_t space; | |
| uint16_t n; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| space = sizeof(TIFFHeaderClassic) + 2 + | |
| (unsigned long)dircount * 12 + 4; | |
| else | |
| space = | |
| sizeof(TIFFHeaderBig) + 8 + (unsigned long)dircount * 20 + 8; | |
| /* calculate amount of space used by indirect values */ | |
| for (dp = dir, n = dircount; n > 0; n--, dp++) | |
| { | |
| uint32_t typewidth; | |
| uint64_t datasize; | |
| typewidth = (uint32_t)TIFFDataWidth((TIFFDataType)dp->tdir_type); | |
| if (typewidth == 0) | |
| { | |
| TIFFErrorExtR( | |
| tif, module, | |
| "Cannot determine size of unknown tag type %" PRIu16, | |
| dp->tdir_type); | |
| return -1; | |
| } | |
| if (dp->tdir_count > UINT64_MAX / typewidth) | |
| return -1; | |
| datasize = (uint64_t)typewidth * dp->tdir_count; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (datasize <= 4) | |
| datasize = 0; | |
| } | |
| else | |
| { | |
| if (datasize <= 8) | |
| datasize = 0; | |
| } | |
| if (space > UINT64_MAX - datasize) | |
| return -1; | |
| space += datasize; | |
| } | |
| if (filesize == 0) | |
| filesize = TIFFGetFileSize(tif); | |
| if (filesize < space) | |
| /* we should perhaps return in error ? */ | |
| space = filesize; | |
| else | |
| space = filesize - space; | |
| if (td->td_planarconfig == PLANARCONFIG_SEPARATE) | |
| space /= td->td_samplesperpixel; | |
| for (strip = 0; strip < td->td_nstrips; strip++) | |
| td->td_stripbytecount_p[strip] = space; | |
| /* | |
| * This gross hack handles the case were the offset to | |
| * the last strip is past the place where we think the strip | |
| * should begin. Since a strip of data must be contiguous, | |
| * it's safe to assume that we've overestimated the amount | |
| * of data in the strip and trim this number back accordingly. | |
| */ | |
| strip--; | |
| if (td->td_stripoffset_p[strip] > | |
| UINT64_MAX - td->td_stripbytecount_p[strip]) | |
| return -1; | |
| if (td->td_stripoffset_p[strip] + td->td_stripbytecount_p[strip] > | |
| filesize) | |
| { | |
| if (td->td_stripoffset_p[strip] >= filesize) | |
| { | |
| /* Not sure what we should in that case... */ | |
| td->td_stripbytecount_p[strip] = 0; | |
| } | |
| else | |
| { | |
| td->td_stripbytecount_p[strip] = | |
| filesize - td->td_stripoffset_p[strip]; | |
| } | |
| } | |
| } | |
| else if (isTiled(tif)) | |
| { | |
| uint64_t bytespertile = TIFFTileSize64(tif); | |
| for (strip = 0; strip < td->td_nstrips; strip++) | |
| td->td_stripbytecount_p[strip] = bytespertile; | |
| } | |
| else | |
| { | |
| uint64_t rowbytes = TIFFScanlineSize64(tif); | |
| uint32_t rowsperstrip = td->td_imagelength / td->td_stripsperimage; | |
| for (strip = 0; strip < td->td_nstrips; strip++) | |
| { | |
| if (rowbytes > 0 && rowsperstrip > UINT64_MAX / rowbytes) | |
| return -1; | |
| td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip; | |
| } | |
| } | |
| TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); | |
| if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) | |
| td->td_rowsperstrip = td->td_imagelength; | |
| return 1; | |
| } | |
| static void MissingRequired(TIFF *tif, const char *tagname) | |
| { | |
| static const char module[] = "MissingRequired"; | |
| TIFFErrorExtR(tif, module, | |
| "TIFF directory is missing required \"%s\" field", tagname); | |
| } | |
| static unsigned long hashFuncOffsetToNumber(const void *elt) | |
| { | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber = | |
| (const TIFFOffsetAndDirNumber *)elt; | |
| const uint32_t hash = (uint32_t)(offsetAndDirNumber->offset >> 32) ^ | |
| ((uint32_t)offsetAndDirNumber->offset & 0xFFFFFFFFU); | |
| return hash; | |
| } | |
| static bool equalFuncOffsetToNumber(const void *elt1, const void *elt2) | |
| { | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber1 = | |
| (const TIFFOffsetAndDirNumber *)elt1; | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber2 = | |
| (const TIFFOffsetAndDirNumber *)elt2; | |
| return offsetAndDirNumber1->offset == offsetAndDirNumber2->offset; | |
| } | |
| static unsigned long hashFuncNumberToOffset(const void *elt) | |
| { | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber = | |
| (const TIFFOffsetAndDirNumber *)elt; | |
| return offsetAndDirNumber->dirNumber; | |
| } | |
| static bool equalFuncNumberToOffset(const void *elt1, const void *elt2) | |
| { | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber1 = | |
| (const TIFFOffsetAndDirNumber *)elt1; | |
| const TIFFOffsetAndDirNumber *offsetAndDirNumber2 = | |
| (const TIFFOffsetAndDirNumber *)elt2; | |
| return offsetAndDirNumber1->dirNumber == offsetAndDirNumber2->dirNumber; | |
| } | |
| /* | |
| * Check the directory number and offset against the list of already seen | |
| * directory numbers and offsets. This is a trick to prevent IFD looping. | |
| * The one can create TIFF file with looped directory pointers. We will | |
| * maintain a list of already seen directories and check every IFD offset | |
| * and its IFD number against that list. However, the offset of an IFD number | |
| * can change - e.g. when writing updates to file. | |
| * Returns 1 if all is ok; 0 if last directory or IFD loop is encountered, | |
| * or an error has occurred. | |
| */ | |
| int _TIFFCheckDirNumberAndOffset(TIFF *tif, tdir_t dirn, uint64_t diroff) | |
| { | |
| if (diroff == 0) /* no more directories */ | |
| return 0; | |
| if (tif->tif_map_dir_offset_to_number == NULL) | |
| { | |
| tif->tif_map_dir_offset_to_number = TIFFHashSetNew( | |
| hashFuncOffsetToNumber, equalFuncOffsetToNumber, free); | |
| if (tif->tif_map_dir_offset_to_number == NULL) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "Not enough memory"); | |
| return 1; | |
| } | |
| } | |
| if (tif->tif_map_dir_number_to_offset == NULL) | |
| { | |
| /* No free callback for this map, as it shares the same items as | |
| * tif->tif_map_dir_offset_to_number. */ | |
| tif->tif_map_dir_number_to_offset = TIFFHashSetNew( | |
| hashFuncNumberToOffset, equalFuncNumberToOffset, NULL); | |
| if (tif->tif_map_dir_number_to_offset == NULL) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "Not enough memory"); | |
| return 1; | |
| } | |
| } | |
| /* Check if offset is already in the list: | |
| * - yes: check, if offset is at the same IFD number - if not, it is an IFD | |
| * loop | |
| * - no: add to list or update offset at that IFD number | |
| */ | |
| TIFFOffsetAndDirNumber entry; | |
| entry.offset = diroff; | |
| entry.dirNumber = dirn; | |
| TIFFOffsetAndDirNumber *foundEntry = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_offset_to_number, &entry); | |
| if (foundEntry) | |
| { | |
| if (foundEntry->dirNumber == dirn) | |
| { | |
| return 1; | |
| } | |
| else | |
| { | |
| TIFFWarningExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "TIFF directory %d has IFD looping to directory %u " | |
| "at offset 0x%" PRIx64 " (%" PRIu64 ")", | |
| (int)dirn - 1, foundEntry->dirNumber, diroff, | |
| diroff); | |
| return 0; | |
| } | |
| } | |
| /* Check if offset of an IFD has been changed and update offset of that IFD | |
| * number. */ | |
| foundEntry = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_number_to_offset, &entry); | |
| if (foundEntry) | |
| { | |
| if (foundEntry->offset != diroff) | |
| { | |
| TIFFOffsetAndDirNumber entryOld; | |
| entryOld.offset = foundEntry->offset; | |
| entryOld.dirNumber = dirn; | |
| /* We must remove first from tif_map_dir_number_to_offset as the */ | |
| /* entry is owned (and thus freed) by */ | |
| /* tif_map_dir_offset_to_number */ | |
| TIFFOffsetAndDirNumber *foundEntryOld = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_number_to_offset, &entryOld); | |
| if (foundEntryOld) | |
| { | |
| TIFFHashSetRemove(tif->tif_map_dir_number_to_offset, | |
| foundEntryOld); | |
| } | |
| foundEntryOld = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_offset_to_number, &entryOld); | |
| if (foundEntryOld) | |
| { | |
| TIFFHashSetRemove(tif->tif_map_dir_offset_to_number, | |
| foundEntryOld); | |
| } | |
| TIFFOffsetAndDirNumber *entryPtr = (TIFFOffsetAndDirNumber *)malloc( | |
| sizeof(TIFFOffsetAndDirNumber)); | |
| if (entryPtr == NULL) | |
| { | |
| return 0; | |
| } | |
| /* Add IFD offset and dirn to IFD directory list */ | |
| *entryPtr = entry; | |
| if (!TIFFHashSetInsert(tif->tif_map_dir_offset_to_number, entryPtr)) | |
| { | |
| TIFFErrorExtR( | |
| tif, "_TIFFCheckDirNumberAndOffset", | |
| "Insertion in tif_map_dir_offset_to_number failed"); | |
| return 0; | |
| } | |
| if (!TIFFHashSetInsert(tif->tif_map_dir_number_to_offset, entryPtr)) | |
| { | |
| TIFFErrorExtR( | |
| tif, "_TIFFCheckDirNumberAndOffset", | |
| "Insertion in tif_map_dir_number_to_offset failed"); | |
| return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| /* Arbitrary (hopefully big enough) limit */ | |
| if (TIFFHashSetSize(tif->tif_map_dir_offset_to_number) >= | |
| TIFF_MAX_DIR_COUNT) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "Cannot handle more than %u TIFF directories", | |
| (unsigned)TIFF_MAX_DIR_COUNT); | |
| return 0; | |
| } | |
| TIFFOffsetAndDirNumber *entryPtr = | |
| (TIFFOffsetAndDirNumber *)malloc(sizeof(TIFFOffsetAndDirNumber)); | |
| if (entryPtr == NULL) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "malloc(sizeof(TIFFOffsetAndDirNumber)) failed"); | |
| return 0; | |
| } | |
| /* Add IFD offset and dirn to IFD directory list */ | |
| *entryPtr = entry; | |
| if (!TIFFHashSetInsert(tif->tif_map_dir_offset_to_number, entryPtr)) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "Insertion in tif_map_dir_offset_to_number failed"); | |
| return 0; | |
| } | |
| if (!TIFFHashSetInsert(tif->tif_map_dir_number_to_offset, entryPtr)) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", | |
| "Insertion in tif_map_dir_number_to_offset failed"); | |
| return 0; | |
| } | |
| return 1; | |
| } /* --- _TIFFCheckDirNumberAndOffset() ---*/ | |
| /* | |
| * Retrieve the matching IFD directory number of a given IFD offset | |
| * from the list of directories already seen. | |
| * Returns 1 if the offset was in the list and the directory number | |
| * can be returned. | |
| * Otherwise returns 0 or if an error occurred. | |
| */ | |
| int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, tdir_t *dirn) | |
| { | |
| if (diroff == 0) /* no more directories */ | |
| return 0; | |
| /* Check if offset is already in the list and return matching directory | |
| * number. Otherwise update IFD list using TIFFNumberOfDirectories() and | |
| * search again in IFD list. | |
| */ | |
| if (tif->tif_map_dir_offset_to_number == NULL) | |
| return 0; | |
| TIFFOffsetAndDirNumber entry; | |
| entry.offset = diroff; | |
| entry.dirNumber = 0; /* not used */ | |
| TIFFOffsetAndDirNumber *foundEntry = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_offset_to_number, &entry); | |
| if (foundEntry) | |
| { | |
| *dirn = foundEntry->dirNumber; | |
| return 1; | |
| } | |
| /* This updates the directory list for all main-IFDs in the file. */ | |
| TIFFNumberOfDirectories(tif); | |
| foundEntry = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_offset_to_number, &entry); | |
| if (foundEntry) | |
| { | |
| *dirn = foundEntry->dirNumber; | |
| return 1; | |
| } | |
| return 0; | |
| } /*--- _TIFFGetDirNumberFromOffset() ---*/ | |
| /* | |
| * Retrieve the matching IFD directory offset of a given IFD number | |
| * from the list of directories already seen. | |
| * Returns 1 if the offset was in the list of already seen IFDs and the | |
| * directory offset can be returned. The directory list is not updated. | |
| * Otherwise returns 0 or if an error occurred. | |
| */ | |
| int _TIFFGetOffsetFromDirNumber(TIFF *tif, tdir_t dirn, uint64_t *diroff) | |
| { | |
| if (tif->tif_map_dir_number_to_offset == NULL) | |
| return 0; | |
| TIFFOffsetAndDirNumber entry; | |
| entry.offset = 0; /* not used */ | |
| entry.dirNumber = dirn; | |
| TIFFOffsetAndDirNumber *foundEntry = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_number_to_offset, &entry); | |
| if (foundEntry) | |
| { | |
| *diroff = foundEntry->offset; | |
| return 1; | |
| } | |
| return 0; | |
| } /*--- _TIFFGetOffsetFromDirNumber() ---*/ | |
| /* | |
| * Remove an entry from the directory list of already seen directories | |
| * by directory offset. | |
| * If an entry is to be removed from the list, it is also okay if the entry | |
| * is not in the list or the list does not exist. | |
| */ | |
| int _TIFFRemoveEntryFromDirectoryListByOffset(TIFF *tif, uint64_t diroff) | |
| { | |
| if (tif->tif_map_dir_offset_to_number == NULL) | |
| return 1; | |
| TIFFOffsetAndDirNumber entryOld; | |
| entryOld.offset = diroff; | |
| entryOld.dirNumber = 0; | |
| /* We must remove first from tif_map_dir_number_to_offset as the | |
| * entry is owned (and thus freed) by tif_map_dir_offset_to_number. | |
| * However, we need firstly to find the directory number from offset. */ | |
| TIFFOffsetAndDirNumber *foundEntryOldOff = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_offset_to_number, &entryOld); | |
| if (foundEntryOldOff) | |
| { | |
| entryOld.dirNumber = foundEntryOldOff->dirNumber; | |
| if (tif->tif_map_dir_number_to_offset != NULL) | |
| { | |
| TIFFOffsetAndDirNumber *foundEntryOldDir = | |
| (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( | |
| tif->tif_map_dir_number_to_offset, &entryOld); | |
| if (foundEntryOldDir) | |
| { | |
| TIFFHashSetRemove(tif->tif_map_dir_number_to_offset, | |
| foundEntryOldDir); | |
| TIFFHashSetRemove(tif->tif_map_dir_offset_to_number, | |
| foundEntryOldOff); | |
| return 1; | |
| } | |
| } | |
| else | |
| { | |
| TIFFErrorExtR(tif, "_TIFFRemoveEntryFromDirectoryListByOffset", | |
| "Unexpectedly tif_map_dir_number_to_offset is " | |
| "missing but tif_map_dir_offset_to_number exists."); | |
| return 0; | |
| } | |
| } | |
| return 1; | |
| } /*--- _TIFFRemoveEntryFromDirectoryListByOffset() ---*/ | |
| /* | |
| * Check the count field of a directory entry against a known value. The | |
| * caller is expected to skip/ignore the tag if there is a mismatch. | |
| */ | |
| static int CheckDirCount(TIFF *tif, TIFFDirEntry *dir, uint32_t count) | |
| { | |
| if ((uint64_t)count > dir->tdir_count) | |
| { | |
| const TIFFField *fip = TIFFFieldWithTag(tif, dir->tdir_tag); | |
| TIFFWarningExtR(tif, tif->tif_name, | |
| "incorrect count for field \"%s\" (%" PRIu64 | |
| ", expecting %" PRIu32 "); tag ignored", | |
| fip ? fip->field_name : "unknown tagname", | |
| dir->tdir_count, count); | |
| return (0); | |
| } | |
| else if ((uint64_t)count < dir->tdir_count) | |
| { | |
| const TIFFField *fip = TIFFFieldWithTag(tif, dir->tdir_tag); | |
| TIFFWarningExtR(tif, tif->tif_name, | |
| "incorrect count for field \"%s\" (%" PRIu64 | |
| ", expecting %" PRIu32 "); tag trimmed", | |
| fip ? fip->field_name : "unknown tagname", | |
| dir->tdir_count, count); | |
| dir->tdir_count = count; | |
| return (1); | |
| } | |
| return (1); | |
| } | |
| /* | |
| * Read IFD structure from the specified offset. If the pointer to | |
| * nextdiroff variable has been specified, read it too. Function returns a | |
| * number of fields in the directory or 0 if failed. | |
| */ | |
| static uint16_t TIFFFetchDirectory(TIFF *tif, uint64_t diroff, | |
| TIFFDirEntry **pdir, uint64_t *nextdiroff) | |
| { | |
| static const char module[] = "TIFFFetchDirectory"; | |
| void *origdir; | |
| uint16_t dircount16; | |
| uint32_t dirsize; | |
| TIFFDirEntry *dir; | |
| uint8_t *ma; | |
| TIFFDirEntry *mb; | |
| uint16_t n; | |
| assert(pdir); | |
| tif->tif_diroff = diroff; | |
| if (nextdiroff) | |
| *nextdiroff = 0; | |
| if (!isMapped(tif)) | |
| { | |
| if (!SeekOK(tif, tif->tif_diroff)) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "%s: Seek error accessing TIFF directory", | |
| tif->tif_name); | |
| return 0; | |
| } | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (!ReadOK(tif, &dircount16, 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(&dircount16); | |
| if (dircount16 > 4096) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on directory count failed, this is " | |
| "probably not a valid IFD offset"); | |
| return 0; | |
| } | |
| dirsize = 12; | |
| } | |
| 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); | |
| if (dircount64 > 4096) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on directory count failed, this is " | |
| "probably not a valid IFD offset"); | |
| return 0; | |
| } | |
| dircount16 = (uint16_t)dircount64; | |
| dirsize = 20; | |
| } | |
| origdir = _TIFFCheckMalloc(tif, dircount16, dirsize, | |
| "to read TIFF directory"); | |
| if (origdir == NULL) | |
| return 0; | |
| if (!ReadOK(tif, origdir, (tmsize_t)dircount16 * dirsize)) | |
| { | |
| TIFFErrorExtR(tif, module, "%.100s: Can not read TIFF directory", | |
| tif->tif_name); | |
| _TIFFfreeExt(tif, origdir); | |
| return 0; | |
| } | |
| /* | |
| * Read offset to next directory for sequential scans if | |
| * needed. | |
| */ | |
| if (nextdiroff) | |
| { | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t nextdiroff32; | |
| if (!ReadOK(tif, &nextdiroff32, sizeof(uint32_t))) | |
| nextdiroff32 = 0; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&nextdiroff32); | |
| *nextdiroff = nextdiroff32; | |
| } | |
| else | |
| { | |
| if (!ReadOK(tif, nextdiroff, sizeof(uint64_t))) | |
| *nextdiroff = 0; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(nextdiroff); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| tmsize_t m; | |
| tmsize_t off; | |
| if (tif->tif_diroff > (uint64_t)INT64_MAX) | |
| { | |
| TIFFErrorExtR(tif, module, "Can not read TIFF directory count"); | |
| return (0); | |
| } | |
| off = (tmsize_t)tif->tif_diroff; | |
| /* | |
| * Check for integer overflow when validating the dir_off, | |
| * otherwise a very high offset may cause an OOB read and | |
| * crash the client. Make two comparisons instead of | |
| * | |
| * off + sizeof(uint16_t) > tif->tif_size | |
| * | |
| * to avoid overflow. | |
| */ | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| m = (tmsize_t)((uint64_t)off + sizeof(uint16_t)); | |
| if ((m < off) || ((uint64_t)m < sizeof(uint16_t)) || | |
| ((uint64_t)m > (uint64_t)tif->tif_size)) | |
| { | |
| TIFFErrorExtR(tif, module, "Can not read TIFF directory count"); | |
| return 0; | |
| } | |
| else | |
| { | |
| _TIFFmemcpy(&dircount16, tif->tif_base + off, sizeof(uint16_t)); | |
| } | |
| off = (tmsize_t)((uint64_t)off + sizeof(uint16_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort(&dircount16); | |
| if (dircount16 > 4096) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on directory count failed, this is " | |
| "probably not a valid IFD offset"); | |
| return 0; | |
| } | |
| dirsize = 12; | |
| } | |
| else | |
| { | |
| uint64_t dircount64; | |
| m = (tmsize_t)((uint64_t)off + sizeof(uint64_t)); | |
| if ((m < off) || ((uint64_t)m < sizeof(uint64_t)) || | |
| ((uint64_t)m > (uint64_t)tif->tif_size)) | |
| { | |
| TIFFErrorExtR(tif, module, "Can not read TIFF directory count"); | |
| return 0; | |
| } | |
| else | |
| { | |
| _TIFFmemcpy(&dircount64, tif->tif_base + off, sizeof(uint64_t)); | |
| } | |
| off = (tmsize_t)((uint64_t)off + sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(&dircount64); | |
| if (dircount64 > 4096) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on directory count failed, this is " | |
| "probably not a valid IFD offset"); | |
| return 0; | |
| } | |
| dircount16 = (uint16_t)dircount64; | |
| dirsize = 20; | |
| } | |
| if (dircount16 == 0) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Sanity check on directory count failed, zero tag " | |
| "directories not supported"); | |
| return 0; | |
| } | |
| /* Before allocating a huge amount of memory for corrupted files, check | |
| * if size of requested memory is not greater than file size. */ | |
| uint64_t filesize = TIFFGetFileSize(tif); | |
| uint64_t allocsize = (uint64_t)dircount16 * dirsize; | |
| if (allocsize > filesize) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Requested memory size for TIFF directory of %" PRIu64 | |
| " is greater than filesize %" PRIu64 | |
| ". Memory not allocated, TIFF directory not read", | |
| allocsize, filesize); | |
| return 0; | |
| } | |
| origdir = _TIFFCheckMalloc(tif, dircount16, dirsize, | |
| "to read TIFF directory"); | |
| if (origdir == NULL) | |
| return 0; | |
| m = off + dircount16 * dirsize; | |
| if ((m < off) || (m < (tmsize_t)dircount16 * (tmsize_t)dirsize) || | |
| (m > tif->tif_size)) | |
| { | |
| TIFFErrorExtR(tif, module, "Can not read TIFF directory"); | |
| _TIFFfreeExt(tif, origdir); | |
| return 0; | |
| } | |
| else | |
| { | |
| _TIFFmemcpy(origdir, tif->tif_base + off, | |
| (tmsize_t)dircount16 * dirsize); | |
| } | |
| if (nextdiroff) | |
| { | |
| off += dircount16 * dirsize; | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t nextdiroff32; | |
| m = (tmsize_t)((uint64_t)off + sizeof(uint32_t)); | |
| if ((m < off) || ((uint64_t)m < sizeof(uint32_t)) || | |
| ((uint64_t)m > (uint64_t)tif->tif_size)) | |
| nextdiroff32 = 0; | |
| else | |
| _TIFFmemcpy(&nextdiroff32, tif->tif_base + off, | |
| sizeof(uint32_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&nextdiroff32); | |
| *nextdiroff = nextdiroff32; | |
| } | |
| else | |
| { | |
| m = (tmsize_t)((uint64_t)off + sizeof(uint64_t)); | |
| if ((m < off) || ((uint64_t)m < sizeof(uint64_t)) || | |
| ((uint64_t)m > (uint64_t)tif->tif_size)) | |
| *nextdiroff = 0; | |
| else | |
| _TIFFmemcpy(nextdiroff, tif->tif_base + off, | |
| sizeof(uint64_t)); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8(nextdiroff); | |
| } | |
| } | |
| } | |
| /* No check against filesize needed here because "dir" should have same size | |
| * than "origdir" checked above. */ | |
| dir = (TIFFDirEntry *)_TIFFCheckMalloc( | |
| tif, dircount16, sizeof(TIFFDirEntry), "to read TIFF directory"); | |
| if (dir == 0) | |
| { | |
| _TIFFfreeExt(tif, origdir); | |
| return 0; | |
| } | |
| ma = (uint8_t *)origdir; | |
| mb = dir; | |
| for (n = 0; n < dircount16; n++) | |
| { | |
| mb->tdir_ignore = FALSE; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| mb->tdir_tag = *(uint16_t *)ma; | |
| ma += sizeof(uint16_t); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabShort((uint16_t *)ma); | |
| mb->tdir_type = *(uint16_t *)ma; | |
| ma += sizeof(uint16_t); | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong((uint32_t *)ma); | |
| mb->tdir_count = (uint64_t)(*(uint32_t *)ma); | |
| ma += sizeof(uint32_t); | |
| mb->tdir_offset.toff_long8 = 0; | |
| *(uint32_t *)(&mb->tdir_offset) = *(uint32_t *)ma; | |
| ma += sizeof(uint32_t); | |
| } | |
| else | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong8((uint64_t *)ma); | |
| mb->tdir_count = TIFFReadUInt64(ma); | |
| ma += sizeof(uint64_t); | |
| mb->tdir_offset.toff_long8 = TIFFReadUInt64(ma); | |
| ma += sizeof(uint64_t); | |
| } | |
| mb++; | |
| } | |
| _TIFFfreeExt(tif, origdir); | |
| *pdir = dir; | |
| return dircount16; | |
| } | |
| /* | |
| * Fetch a tag that is not handled by special case code. | |
| */ | |
| static int TIFFFetchNormalTag(TIFF *tif, TIFFDirEntry *dp, int recover) | |
| { | |
| static const char module[] = "TIFFFetchNormalTag"; | |
| enum TIFFReadDirEntryErr err; | |
| uint32_t fii; | |
| const TIFFField *fip = NULL; | |
| TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); | |
| if (fii == FAILED_FII) | |
| { | |
| TIFFErrorExtR(tif, "TIFFFetchNormalTag", | |
| "No definition found for tag %" PRIu16, dp->tdir_tag); | |
| return 0; | |
| } | |
| fip = tif->tif_fields[fii]; | |
| assert(fip != NULL); /* should not happen */ | |
| assert(fip->set_get_field_type != | |
| TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with | |
| this in specialized code */ | |
| assert(fip->set_get_field_type != | |
| TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only | |
| the case for pseudo-tags */ | |
| err = TIFFReadDirEntryErrOk; | |
| switch (fip->set_get_field_type) | |
| { | |
| case TIFF_SETGET_UNDEFINED: | |
| TIFFErrorExtR( | |
| tif, "TIFFFetchNormalTag", | |
| "Defined set_get_field_type of custom tag %u (%s) is " | |
| "TIFF_SETGET_UNDEFINED and thus tag is not read from file", | |
| fip->field_tag, fip->field_name); | |
| break; | |
| case TIFF_SETGET_ASCII: | |
| { | |
| uint8_t *data; | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| size_t mb = 0; | |
| int n; | |
| if (data != NULL) | |
| { | |
| if (dp->tdir_count > 0 && data[dp->tdir_count - 1] == 0) | |
| { | |
| /* optimization: if data is known to be 0 terminated, we | |
| * can use strlen() */ | |
| mb = strlen((const char *)data); | |
| } | |
| else | |
| { | |
| /* general case. equivalent to non-portable */ | |
| /* mb = strnlen((const char*)data, | |
| * (uint32_t)dp->tdir_count); */ | |
| uint8_t *ma = data; | |
| while (mb < (uint32_t)dp->tdir_count) | |
| { | |
| if (*ma == 0) | |
| break; | |
| ma++; | |
| mb++; | |
| } | |
| } | |
| } | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != NULL) | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| if (mb + 1 < (uint32_t)dp->tdir_count) | |
| TIFFWarningExtR( | |
| tif, module, | |
| "ASCII value for tag \"%s\" contains null byte in " | |
| "value; value incorrectly truncated during reading due " | |
| "to implementation limitations", | |
| fip->field_name); | |
| else if (mb + 1 > (uint32_t)dp->tdir_count) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "ASCII value for tag \"%s\" does not end " | |
| "in null byte. Forcing it to be null", | |
| fip->field_name); | |
| /* TIFFReadDirEntryArrayWithLimit() ensures this can't be | |
| * larger than MAX_SIZE_TAG_DATA */ | |
| assert((uint32_t)dp->tdir_count + 1 == dp->tdir_count + 1); | |
| uint8_t *o = (uint8_t *)_TIFFmallocExt( | |
| tif, (uint32_t)dp->tdir_count + 1); | |
| if (o == NULL) | |
| { | |
| if (data != NULL) | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| if (dp->tdir_count > 0) | |
| { | |
| _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); | |
| } | |
| o[(uint32_t)dp->tdir_count] = 0; | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| data = o; | |
| } | |
| n = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!n) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_UINT8: | |
| { | |
| uint8_t data = 0; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryByte(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_SINT8: | |
| { | |
| int8_t data = 0; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntrySbyte(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_UINT16: | |
| { | |
| uint16_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryShort(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_SINT16: | |
| { | |
| int16_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntrySshort(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_UINT32: | |
| { | |
| uint32_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryLong(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_SINT32: | |
| { | |
| int32_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntrySlong(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_UINT64: | |
| { | |
| uint64_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryLong8(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| return 0; | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_SINT64: | |
| { | |
| int64_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntrySlong8(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| return 0; | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_FLOAT: | |
| { | |
| float data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryFloat(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| return 0; | |
| if (!TIFFSetField(tif, dp->tdir_tag, (double)data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_DOUBLE: | |
| { | |
| double data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryDouble(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| return 0; | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_IFD8: | |
| { | |
| uint64_t data; | |
| assert(fip->field_readcount == 1); | |
| assert(fip->field_passcount == 0); | |
| err = TIFFReadDirEntryIfd8(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| return 0; | |
| if (!TIFFSetField(tif, dp->tdir_tag, data)) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_UINT16_PAIR: | |
| { | |
| uint16_t *data; | |
| assert(fip->field_readcount == 2); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != 2) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected 2, " | |
| "got %" PRIu64, | |
| fip->field_name, dp->tdir_count); | |
| return (0); | |
| } | |
| err = TIFFReadDirEntryShortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| int m; | |
| assert(data); /* avoid CLang static Analyzer false positive */ | |
| m = TIFFSetField(tif, dp->tdir_tag, data[0], data[1]); | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_UINT8: | |
| { | |
| uint8_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_SINT8: | |
| { | |
| int8_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntrySbyteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_UINT16: | |
| { | |
| uint16_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryShortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_SINT16: | |
| { | |
| int16_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntrySshortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_UINT32: | |
| { | |
| uint32_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryLongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_SINT32: | |
| { | |
| int32_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntrySlongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_UINT64: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryLong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_SINT64: | |
| { | |
| int64_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntrySlong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_FLOAT: | |
| { | |
| float *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryFloatArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| /*--: Rational2Double: Extend for Double Arrays and Rational-Arrays read | |
| * into Double-Arrays. */ | |
| case TIFF_SETGET_C0_DOUBLE: | |
| { | |
| double *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryDoubleArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C0_IFD8: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount >= 1); | |
| assert(fip->field_passcount == 0); | |
| if (dp->tdir_count != (uint64_t)fip->field_readcount) | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "incorrect count for field \"%s\", expected " | |
| "%d, got %" PRIu64, | |
| fip->field_name, (int)fip->field_readcount, | |
| dp->tdir_count); | |
| return (0); | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryIfd8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_ASCII: | |
| { | |
| uint8_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| if (data != 0 && dp->tdir_count > 0 && | |
| data[dp->tdir_count - 1] != '\0') | |
| { | |
| TIFFWarningExtR(tif, module, | |
| "ASCII value for ASCII array tag " | |
| "\"%s\" does not end in null " | |
| "byte. Forcing it to be null", | |
| fip->field_name); | |
| /* Enlarge buffer and add terminating null. */ | |
| uint8_t *o = (uint8_t *)_TIFFmallocExt( | |
| tif, (uint32_t)dp->tdir_count + 1); | |
| if (o == NULL) | |
| { | |
| if (data != NULL) | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| if (dp->tdir_count > 0) | |
| { | |
| _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); | |
| } | |
| o[(uint32_t)dp->tdir_count] = 0; | |
| dp->tdir_count++; /* Increment for added null. */ | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| data = o; | |
| } | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_UINT8: | |
| { | |
| uint8_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_SINT8: | |
| { | |
| int8_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntrySbyteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_UINT16: | |
| { | |
| uint16_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryShortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_SINT16: | |
| { | |
| int16_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntrySshortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_UINT32: | |
| { | |
| uint32_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryLongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_SINT32: | |
| { | |
| int32_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntrySlongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_UINT64: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryLong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_SINT64: | |
| { | |
| int64_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntrySlong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_FLOAT: | |
| { | |
| float *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryFloatArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_DOUBLE: | |
| { | |
| double *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryDoubleArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C16_IFD8: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE); | |
| assert(fip->field_passcount == 1); | |
| if (dp->tdir_count > 0xFFFF) | |
| err = TIFFReadDirEntryErrCount; | |
| else | |
| { | |
| err = TIFFReadDirEntryIfd8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, | |
| (uint16_t)(dp->tdir_count), data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_ASCII: | |
| { | |
| uint8_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| if (data != 0 && dp->tdir_count > 0 && | |
| data[dp->tdir_count - 1] != '\0') | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "ASCII value for ASCII array tag \"%s\" does not end " | |
| "in null byte. Forcing it to be null", | |
| fip->field_name); | |
| /* Enlarge buffer and add terminating null. */ | |
| uint8_t *o = (uint8_t *)_TIFFmallocExt( | |
| tif, (uint32_t)dp->tdir_count + 1); | |
| if (o == NULL) | |
| { | |
| if (data != NULL) | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| if (dp->tdir_count > 0) | |
| { | |
| _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); | |
| } | |
| o[(uint32_t)dp->tdir_count] = 0; | |
| dp->tdir_count++; /* Increment for added null. */ | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| data = o; | |
| } | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_UINT8: | |
| { | |
| uint8_t *data; | |
| uint32_t count = 0; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| if (fip->field_tag == TIFFTAG_RICHTIFFIPTC && | |
| dp->tdir_type == TIFF_LONG) | |
| { | |
| /* Adobe's software (wrongly) writes RichTIFFIPTC tag with | |
| * data type LONG instead of UNDEFINED. Work around this | |
| * frequently found issue */ | |
| void *origdata; | |
| err = TIFFReadDirEntryArray(tif, dp, &count, 4, &origdata); | |
| if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) | |
| { | |
| data = NULL; | |
| } | |
| else | |
| { | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong((uint32_t *)origdata, count); | |
| data = (uint8_t *)origdata; | |
| count = (uint32_t)(count * 4); | |
| } | |
| } | |
| else | |
| { | |
| err = TIFFReadDirEntryByteArray(tif, dp, &data); | |
| count = (uint32_t)(dp->tdir_count); | |
| } | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, count, data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_SINT8: | |
| { | |
| int8_t *data = NULL; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntrySbyteArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_UINT16: | |
| { | |
| uint16_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryShortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_SINT16: | |
| { | |
| int16_t *data = NULL; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntrySshortArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_UINT32: | |
| { | |
| uint32_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryLongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_SINT32: | |
| { | |
| int32_t *data = NULL; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntrySlongArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_UINT64: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryLong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_SINT64: | |
| { | |
| int64_t *data = NULL; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntrySlong8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_FLOAT: | |
| { | |
| float *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryFloatArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_DOUBLE: | |
| { | |
| double *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryDoubleArray(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_C32_IFD8: | |
| { | |
| uint64_t *data; | |
| assert(fip->field_readcount == TIFF_VARIABLE2); | |
| assert(fip->field_passcount == 1); | |
| err = TIFFReadDirEntryIfd8Array(tif, dp, &data); | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| if (!EvaluateIFDdatasizeReading(tif, dp)) | |
| { | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| return 0; | |
| } | |
| int m; | |
| m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), | |
| data); | |
| if (data != 0) | |
| _TIFFfreeExt(tif, data); | |
| if (!m) | |
| return (0); | |
| } | |
| } | |
| break; | |
| case TIFF_SETGET_INT: | |
| case TIFF_SETGET_C0_ASCII: | |
| case TIFF_SETGET_OTHER: | |
| assert(0); /* these should not arrive here */ | |
| break; | |
| default: | |
| assert(0); /* we should never get here */ | |
| break; | |
| } | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| TIFFReadDirEntryOutputErr(tif, err, module, fip->field_name, recover); | |
| return (0); | |
| } | |
| return (1); | |
| } | |
| /* | |
| * Fetch a set of offsets or lengths. | |
| * While this routine says "strips", in fact it's also used for tiles. | |
| */ | |
| static int TIFFFetchStripThing(TIFF *tif, TIFFDirEntry *dir, uint32_t nstrips, | |
| uint64_t **lpp) | |
| { | |
| static const char module[] = "TIFFFetchStripThing"; | |
| enum TIFFReadDirEntryErr err; | |
| uint64_t *data; | |
| err = TIFFReadDirEntryLong8ArrayWithLimit(tif, dir, &data, nstrips); | |
| if (err != TIFFReadDirEntryErrOk) | |
| { | |
| const TIFFField *fip = TIFFFieldWithTag(tif, dir->tdir_tag); | |
| TIFFReadDirEntryOutputErr(tif, err, module, | |
| fip ? fip->field_name : "unknown tagname", 0); | |
| return (0); | |
| } | |
| if (dir->tdir_count < (uint64_t)nstrips) | |
| { | |
| uint64_t *resizeddata; | |
| const TIFFField *fip = TIFFFieldWithTag(tif, dir->tdir_tag); | |
| const char *pszMax = getenv("LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT"); | |
| uint32_t max_nstrips = 1000000; | |
| if (pszMax) | |
| max_nstrips = (uint32_t)atoi(pszMax); | |
| TIFFReadDirEntryOutputErr(tif, TIFFReadDirEntryErrCount, module, | |
| fip ? fip->field_name : "unknown tagname", | |
| (nstrips <= max_nstrips)); | |
| if (nstrips > max_nstrips) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t); | |
| if (allocsize > 100 * 1024 * 1024) | |
| { | |
| /* Before allocating a huge amount of memory for corrupted files, | |
| * check if size of requested memory is not greater than file size. | |
| */ | |
| const uint64_t filesize = TIFFGetFileSize(tif); | |
| if (allocsize > filesize) | |
| { | |
| TIFFWarningExtR( | |
| tif, module, | |
| "Requested memory size for StripArray of %" PRIu64 | |
| " is greater than filesize %" PRIu64 | |
| ". Memory not allocated", | |
| allocsize, filesize); | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| } | |
| resizeddata = (uint64_t *)_TIFFCheckMalloc( | |
| tif, nstrips, sizeof(uint64_t), "for strip array"); | |
| if (resizeddata == 0) | |
| { | |
| _TIFFfreeExt(tif, data); | |
| return (0); | |
| } | |
| if (dir->tdir_count) | |
| _TIFFmemcpy(resizeddata, data, | |
| (tmsize_t)((size_t)dir->tdir_count * sizeof(uint64_t))); | |
| _TIFFmemset(resizeddata + (uint32_t)dir->tdir_count, 0, | |
| (tmsize_t)((size_t)(nstrips - (uint32_t)dir->tdir_count) * | |
| sizeof(uint64_t))); | |
| _TIFFfreeExt(tif, data); | |
| data = resizeddata; | |
| } | |
| *lpp = data; | |
| return (1); | |
| } | |
| /* | |
| * Fetch and set the SubjectDistance EXIF tag. | |
| */ | |
| static int TIFFFetchSubjectDistance(TIFF *tif, TIFFDirEntry *dir) | |
| { | |
| static const char module[] = "TIFFFetchSubjectDistance"; | |
| enum TIFFReadDirEntryErr err; | |
| UInt64Aligned_t m; | |
| m.l = 0; | |
| assert(sizeof(double) == 8); | |
| assert(sizeof(uint64_t) == 8); | |
| assert(sizeof(uint32_t) == 4); | |
| if (dir->tdir_count != 1) | |
| err = TIFFReadDirEntryErrCount; | |
| else if (dir->tdir_type != TIFF_RATIONAL) | |
| err = TIFFReadDirEntryErrType; | |
| else | |
| { | |
| if (!(tif->tif_flags & TIFF_BIGTIFF)) | |
| { | |
| uint32_t offset; | |
| offset = *(uint32_t *)(&dir->tdir_offset); | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabLong(&offset); | |
| err = TIFFReadDirEntryData(tif, offset, 8, m.i); | |
| } | |
| else | |
| { | |
| m.l = dir->tdir_offset.toff_long8; | |
| err = TIFFReadDirEntryErrOk; | |
| } | |
| } | |
| if (err == TIFFReadDirEntryErrOk) | |
| { | |
| double n; | |
| if (tif->tif_flags & TIFF_SWAB) | |
| TIFFSwabArrayOfLong(m.i, 2); | |
| if (m.i[0] == 0) | |
| n = 0.0; | |
| else if (m.i[0] == 0xFFFFFFFF || m.i[1] == 0) | |
| /* | |
| * XXX: Numerator 0xFFFFFFFF means that we have infinite | |
| * distance. Indicate that with a negative floating point | |
| * SubjectDistance value. | |
| */ | |
| n = -1.0; | |
| else | |
| n = (double)m.i[0] / (double)m.i[1]; | |
| return (TIFFSetField(tif, dir->tdir_tag, n)); | |
| } | |
| else | |
| { | |
| TIFFReadDirEntryOutputErr(tif, err, module, "SubjectDistance", TRUE); | |
| return (0); | |
| } | |
| } | |
| static void allocChoppedUpStripArrays(TIFF *tif, uint32_t nstrips, | |
| uint64_t stripbytes, | |
| uint32_t rowsperstrip) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| uint64_t bytecount; | |
| uint64_t offset; | |
| uint64_t last_offset; | |
| uint64_t last_bytecount; | |
| uint32_t i; | |
| uint64_t *newcounts; | |
| uint64_t *newoffsets; | |
| offset = TIFFGetStrileOffset(tif, 0); | |
| last_offset = TIFFGetStrileOffset(tif, td->td_nstrips - 1); | |
| last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips - 1); | |
| if (last_offset > UINT64_MAX - last_bytecount || | |
| last_offset + last_bytecount < offset) | |
| { | |
| return; | |
| } | |
| bytecount = last_offset + last_bytecount - offset; | |
| /* Before allocating a huge amount of memory for corrupted files, check if | |
| * size of StripByteCount and StripOffset tags is not greater than | |
| * file size. | |
| */ | |
| const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t) * 2; | |
| if (allocsize > 100 * 1024 * 1024) | |
| { | |
| const uint64_t filesize = TIFFGetFileSize(tif); | |
| if (allocsize > filesize) | |
| { | |
| TIFFWarningExtR(tif, "allocChoppedUpStripArrays", | |
| "Requested memory size for StripByteCount and " | |
| "StripOffsets %" PRIu64 | |
| " is greater than filesize %" PRIu64 | |
| ". Memory not allocated", | |
| allocsize, filesize); | |
| return; | |
| } | |
| } | |
| newcounts = | |
| (uint64_t *)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t), | |
| "for chopped \"StripByteCounts\" array"); | |
| newoffsets = (uint64_t *)_TIFFCheckMalloc( | |
| tif, nstrips, sizeof(uint64_t), "for chopped \"StripOffsets\" array"); | |
| if (newcounts == NULL || newoffsets == NULL) | |
| { | |
| /* | |
| * Unable to allocate new strip information, give up and use | |
| * the original one strip information. | |
| */ | |
| if (newcounts != NULL) | |
| _TIFFfreeExt(tif, newcounts); | |
| if (newoffsets != NULL) | |
| _TIFFfreeExt(tif, newoffsets); | |
| return; | |
| } | |
| /* | |
| * Fill the strip information arrays with new bytecounts and offsets | |
| * that reflect the broken-up format. | |
| */ | |
| for (i = 0; i < nstrips; i++) | |
| { | |
| if (stripbytes > bytecount) | |
| stripbytes = bytecount; | |
| newcounts[i] = stripbytes; | |
| newoffsets[i] = stripbytes ? offset : 0; | |
| offset += stripbytes; | |
| bytecount -= stripbytes; | |
| } | |
| /* | |
| * Replace old single strip info with multi-strip info. | |
| */ | |
| td->td_stripsperimage = td->td_nstrips = nstrips; | |
| TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); | |
| _TIFFfreeExt(tif, td->td_stripbytecount_p); | |
| _TIFFfreeExt(tif, td->td_stripoffset_p); | |
| td->td_stripbytecount_p = newcounts; | |
| td->td_stripoffset_p = newoffsets; | |
| #ifdef STRIPBYTECOUNTSORTED_UNUSED | |
| td->td_stripbytecountsorted = 1; | |
| #endif | |
| tif->tif_flags |= TIFF_CHOPPEDUPARRAYS; | |
| } | |
| /* | |
| * Replace a single strip (tile) of uncompressed data by multiple strips | |
| * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for | |
| * dealing with large images or for dealing with machines with a limited | |
| * amount memory. | |
| */ | |
| static void ChopUpSingleUncompressedStrip(TIFF *tif) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| uint64_t bytecount; | |
| uint64_t offset; | |
| uint32_t rowblock; | |
| uint64_t rowblockbytes; | |
| uint64_t stripbytes; | |
| uint32_t nstrips; | |
| uint32_t rowsperstrip; | |
| bytecount = TIFFGetStrileByteCount(tif, 0); | |
| /* On a newly created file, just re-opened to be filled, we */ | |
| /* don't want strip chop to trigger as it is going to cause issues */ | |
| /* later ( StripOffsets and StripByteCounts improperly filled) . */ | |
| if (bytecount == 0 && tif->tif_mode != O_RDONLY) | |
| return; | |
| offset = TIFFGetStrileOffset(tif, 0); | |
| assert(td->td_planarconfig == PLANARCONFIG_CONTIG); | |
| if ((td->td_photometric == PHOTOMETRIC_YCBCR) && (!isUpSampled(tif))) | |
| rowblock = td->td_ycbcrsubsampling[1]; | |
| else | |
| rowblock = 1; | |
| rowblockbytes = TIFFVTileSize64(tif, rowblock); | |
| /* | |
| * Make the rows hold at least one scanline, but fill specified amount | |
| * of data if possible. | |
| */ | |
| if (rowblockbytes > STRIP_SIZE_DEFAULT) | |
| { | |
| stripbytes = rowblockbytes; | |
| rowsperstrip = rowblock; | |
| } | |
| else if (rowblockbytes > 0) | |
| { | |
| uint32_t rowblocksperstrip; | |
| rowblocksperstrip = (uint32_t)(STRIP_SIZE_DEFAULT / rowblockbytes); | |
| rowsperstrip = rowblocksperstrip * rowblock; | |
| stripbytes = rowblocksperstrip * rowblockbytes; | |
| } | |
| else | |
| return; | |
| /* | |
| * never increase the number of rows per strip | |
| */ | |
| if (rowsperstrip >= td->td_rowsperstrip || rowsperstrip == 0) | |
| return; | |
| nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); | |
| if (nstrips == 0) | |
| return; | |
| /* If we are going to allocate a lot of memory, make sure that the */ | |
| /* file is as big as needed */ | |
| if (tif->tif_mode == O_RDONLY && nstrips > 1000000 && | |
| (offset >= TIFFGetFileSize(tif) || | |
| stripbytes > (TIFFGetFileSize(tif) - offset) / (nstrips - 1))) | |
| { | |
| return; | |
| } | |
| allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); | |
| } | |
| /* | |
| * Replace a file with contiguous strips > 2 GB of uncompressed data by | |
| * multiple smaller strips. This is useful for | |
| * dealing with large images or for dealing with machines with a limited | |
| * amount memory. | |
| */ | |
| static void TryChopUpUncompressedBigTiff(TIFF *tif) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| uint32_t rowblock; | |
| uint64_t rowblockbytes; | |
| uint32_t i; | |
| uint64_t stripsize; | |
| uint32_t rowblocksperstrip; | |
| uint32_t rowsperstrip; | |
| uint64_t stripbytes; | |
| uint32_t nstrips; | |
| stripsize = TIFFStripSize64(tif); | |
| assert(tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG); | |
| assert(tif->tif_dir.td_compression == COMPRESSION_NONE); | |
| assert((tif->tif_flags & (TIFF_STRIPCHOP | TIFF_ISTILED)) == | |
| TIFF_STRIPCHOP); | |
| assert(stripsize > 0x7FFFFFFFUL); | |
| /* On a newly created file, just re-opened to be filled, we */ | |
| /* don't want strip chop to trigger as it is going to cause issues */ | |
| /* later ( StripOffsets and StripByteCounts improperly filled) . */ | |
| if (TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY) | |
| return; | |
| if ((td->td_photometric == PHOTOMETRIC_YCBCR) && (!isUpSampled(tif))) | |
| rowblock = td->td_ycbcrsubsampling[1]; | |
| else | |
| rowblock = 1; | |
| rowblockbytes = TIFFVStripSize64(tif, rowblock); | |
| if (rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL) | |
| { | |
| /* In case of file with gigantic width */ | |
| return; | |
| } | |
| /* Check that the strips are contiguous and of the expected size */ | |
| for (i = 0; i < td->td_nstrips; i++) | |
| { | |
| if (i == td->td_nstrips - 1) | |
| { | |
| if (TIFFGetStrileByteCount(tif, i) < | |
| TIFFVStripSize64(tif, | |
| td->td_imagelength - i * td->td_rowsperstrip)) | |
| { | |
| return; | |
| } | |
| } | |
| else | |
| { | |
| if (TIFFGetStrileByteCount(tif, i) != stripsize) | |
| { | |
| return; | |
| } | |
| if (i > 0 && TIFFGetStrileOffset(tif, i) != | |
| TIFFGetStrileOffset(tif, i - 1) + | |
| TIFFGetStrileByteCount(tif, i - 1)) | |
| { | |
| return; | |
| } | |
| } | |
| } | |
| /* Aim for 512 MB strips (that will still be manageable by 32 bit builds */ | |
| rowblocksperstrip = (uint32_t)(512 * 1024 * 1024 / rowblockbytes); | |
| if (rowblocksperstrip == 0) | |
| rowblocksperstrip = 1; | |
| rowsperstrip = rowblocksperstrip * rowblock; | |
| stripbytes = rowblocksperstrip * rowblockbytes; | |
| assert(stripbytes <= 0x7FFFFFFFUL); | |
| if (rowsperstrip == 0) | |
| return; | |
| nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); | |
| if (nstrips == 0) | |
| return; | |
| /* If we are going to allocate a lot of memory, make sure that the */ | |
| /* file is as big as needed */ | |
| if (tif->tif_mode == O_RDONLY && nstrips > 1000000) | |
| { | |
| uint64_t last_offset = TIFFGetStrileOffset(tif, td->td_nstrips - 1); | |
| uint64_t filesize = TIFFGetFileSize(tif); | |
| uint64_t last_bytecount = | |
| TIFFGetStrileByteCount(tif, td->td_nstrips - 1); | |
| if (last_offset > filesize || last_bytecount > filesize - last_offset) | |
| { | |
| return; | |
| } | |
| } | |
| allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); | |
| } | |
| TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW | |
| static uint64_t _TIFFUnsanitizedAddUInt64AndInt(uint64_t a, int b) | |
| { | |
| return a + (uint64_t)b; | |
| } | |
| /* Read the value of [Strip|Tile]Offset or [Strip|Tile]ByteCount around | |
| * strip/tile of number strile. Also fetch the neighbouring values using a | |
| * 4096 byte page size. | |
| */ | |
| static int _TIFFPartialReadStripArray(TIFF *tif, TIFFDirEntry *dirent, | |
| int strile, uint64_t *panVals) | |
| { | |
| static const char module[] = "_TIFFPartialReadStripArray"; | |
| #define IO_CACHE_PAGE_SIZE 4096 | |
| size_t sizeofval; | |
| const int bSwab = (tif->tif_flags & TIFF_SWAB) != 0; | |
| int sizeofvalint; | |
| uint64_t nBaseOffset; | |
| uint64_t nOffset; | |
| uint64_t nOffsetStartPage; | |
| uint64_t nOffsetEndPage; | |
| tmsize_t nToRead; | |
| tmsize_t nRead; | |
| uint64_t nLastStripOffset; | |
| int iStartBefore; | |
| int i; | |
| const uint32_t arraySize = tif->tif_dir.td_stripoffsetbyteallocsize; | |
| unsigned char buffer[2 * IO_CACHE_PAGE_SIZE]; | |
| assert(dirent->tdir_count > 4); | |
| if (dirent->tdir_type == TIFF_SHORT) | |
| { | |
| sizeofval = sizeof(uint16_t); | |
| } | |
| else if (dirent->tdir_type == TIFF_LONG) | |
| { | |
| sizeofval = sizeof(uint32_t); | |
| } | |
| else if (dirent->tdir_type == TIFF_LONG8) | |
| { | |
| sizeofval = sizeof(uint64_t); | |
| } | |
| else if (dirent->tdir_type == TIFF_SLONG8) | |
| { | |
| /* Non conformant but used by some images as in */ | |
| /* https://github.com/OSGeo/gdal/issues/2165 */ | |
| sizeofval = sizeof(int64_t); | |
| } | |
| else | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Invalid type for [Strip|Tile][Offset/ByteCount] tag"); | |
| panVals[strile] = 0; | |
| return 0; | |
| } | |
| sizeofvalint = (int)(sizeofval); | |
| if (tif->tif_flags & TIFF_BIGTIFF) | |
| { | |
| uint64_t offset = dirent->tdir_offset.toff_long8; | |
| if (bSwab) | |
| TIFFSwabLong8(&offset); | |
| nBaseOffset = offset; | |
| } | |
| else | |
| { | |
| uint32_t offset = dirent->tdir_offset.toff_long; | |
| if (bSwab) | |
| TIFFSwabLong(&offset); | |
| nBaseOffset = offset; | |
| } | |
| /* To avoid later unsigned integer overflows */ | |
| if (nBaseOffset > (uint64_t)INT64_MAX) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot read offset/size for strile %d", | |
| strile); | |
| panVals[strile] = 0; | |
| return 0; | |
| } | |
| nOffset = nBaseOffset + (uint64_t)sizeofval * (uint64_t)strile; | |
| nOffsetStartPage = (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE; | |
| nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE; | |
| if (nOffset + sizeofval > nOffsetEndPage) | |
| nOffsetEndPage += IO_CACHE_PAGE_SIZE; | |
| #undef IO_CACHE_PAGE_SIZE | |
| nLastStripOffset = nBaseOffset + (uint64_t)arraySize * sizeofval; | |
| if (nLastStripOffset < nOffsetEndPage) | |
| nOffsetEndPage = nLastStripOffset; | |
| if (nOffsetStartPage >= nOffsetEndPage) | |
| { | |
| TIFFErrorExtR(tif, module, "Cannot read offset/size for strile %d", | |
| strile); | |
| panVals[strile] = 0; | |
| return 0; | |
| } | |
| if (!SeekOK(tif, nOffsetStartPage)) | |
| { | |
| panVals[strile] = 0; | |
| return 0; | |
| } | |
| nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage); | |
| nRead = TIFFReadFile(tif, buffer, nToRead); | |
| if (nRead < nToRead) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Cannot read offset/size for strile around ~%d", strile); | |
| return 0; | |
| } | |
| iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval); | |
| if (strile + iStartBefore < 0) | |
| iStartBefore = -strile; | |
| for (i = iStartBefore; | |
| (uint32_t)(strile + i) < arraySize && | |
| _TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= | |
| nOffsetEndPage; | |
| ++i) | |
| { | |
| if (dirent->tdir_type == TIFF_SHORT) | |
| { | |
| uint16_t val; | |
| memcpy(&val, | |
| buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, | |
| sizeof(val)); | |
| if (bSwab) | |
| TIFFSwabShort(&val); | |
| panVals[strile + i] = val; | |
| } | |
| else if (dirent->tdir_type == TIFF_LONG) | |
| { | |
| uint32_t val; | |
| memcpy(&val, | |
| buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, | |
| sizeof(val)); | |
| if (bSwab) | |
| TIFFSwabLong(&val); | |
| panVals[strile + i] = val; | |
| } | |
| else if (dirent->tdir_type == TIFF_LONG8) | |
| { | |
| uint64_t val; | |
| memcpy(&val, | |
| buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, | |
| sizeof(val)); | |
| if (bSwab) | |
| TIFFSwabLong8(&val); | |
| panVals[strile + i] = val; | |
| } | |
| else /* if( dirent->tdir_type == TIFF_SLONG8 ) */ | |
| { | |
| /* Non conformant data type */ | |
| int64_t val; | |
| memcpy(&val, | |
| buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, | |
| sizeof(val)); | |
| if (bSwab) | |
| TIFFSwabLong8((uint64_t *)&val); | |
| panVals[strile + i] = (uint64_t)val; | |
| } | |
| } | |
| return 1; | |
| } | |
| static int _TIFFFetchStrileValue(TIFF *tif, uint32_t strile, | |
| TIFFDirEntry *dirent, uint64_t **parray) | |
| { | |
| static const char module[] = "_TIFFFetchStrileValue"; | |
| TIFFDirectory *td = &tif->tif_dir; | |
| if (strile >= dirent->tdir_count) | |
| { | |
| return 0; | |
| } | |
| if (strile >= td->td_stripoffsetbyteallocsize) | |
| { | |
| uint32_t nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize; | |
| uint32_t nStripArrayAllocNew; | |
| uint64_t nArraySize64; | |
| size_t nArraySize; | |
| uint64_t *offsetArray; | |
| uint64_t *bytecountArray; | |
| if (strile > 1000000) | |
| { | |
| uint64_t filesize = TIFFGetFileSize(tif); | |
| /* Avoid excessive memory allocation attempt */ | |
| /* For such a big blockid we need at least a TIFF_LONG per strile */ | |
| /* for the offset array. */ | |
| if (strile > filesize / sizeof(uint32_t)) | |
| { | |
| TIFFErrorExtR(tif, module, "File too short"); | |
| return 0; | |
| } | |
| } | |
| if (td->td_stripoffsetbyteallocsize == 0 && | |
| td->td_nstrips < 1024 * 1024) | |
| { | |
| nStripArrayAllocNew = td->td_nstrips; | |
| } | |
| else | |
| { | |
| #define TIFF_MAX(a, b) (((a) > (b)) ? (a) : (b)) | |
| #define TIFF_MIN(a, b) (((a) < (b)) ? (a) : (b)) | |
| nStripArrayAllocNew = TIFF_MAX(strile + 1, 1024U * 512U); | |
| if (nStripArrayAllocNew < 0xFFFFFFFFU / 2) | |
| nStripArrayAllocNew *= 2; | |
| nStripArrayAllocNew = TIFF_MIN(nStripArrayAllocNew, td->td_nstrips); | |
| } | |
| assert(strile < nStripArrayAllocNew); | |
| nArraySize64 = (uint64_t)sizeof(uint64_t) * nStripArrayAllocNew; | |
| nArraySize = (size_t)(nArraySize64); | |
| #if SIZEOF_SIZE_T == 4 | |
| if (nArraySize != nArraySize64) | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Cannot allocate strip offset and bytecount arrays"); | |
| return 0; | |
| } | |
| #endif | |
| offsetArray = (uint64_t *)(_TIFFreallocExt(tif, td->td_stripoffset_p, | |
| (tmsize_t)nArraySize)); | |
| bytecountArray = (uint64_t *)(_TIFFreallocExt( | |
| tif, td->td_stripbytecount_p, (tmsize_t)nArraySize)); | |
| if (offsetArray) | |
| td->td_stripoffset_p = offsetArray; | |
| if (bytecountArray) | |
| td->td_stripbytecount_p = bytecountArray; | |
| if (offsetArray && bytecountArray) | |
| { | |
| td->td_stripoffsetbyteallocsize = nStripArrayAllocNew; | |
| /* Initialize new entries to ~0 / -1 */ | |
| /* coverity[overrun-buffer-arg] */ | |
| memset(td->td_stripoffset_p + nStripArrayAllocBefore, 0xFF, | |
| (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * | |
| sizeof(uint64_t)); | |
| /* coverity[overrun-buffer-arg] */ | |
| memset(td->td_stripbytecount_p + nStripArrayAllocBefore, 0xFF, | |
| (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * | |
| sizeof(uint64_t)); | |
| } | |
| else | |
| { | |
| TIFFErrorExtR(tif, module, | |
| "Cannot allocate strip offset and bytecount arrays"); | |
| _TIFFfreeExt(tif, td->td_stripoffset_p); | |
| td->td_stripoffset_p = NULL; | |
| _TIFFfreeExt(tif, td->td_stripbytecount_p); | |
| td->td_stripbytecount_p = NULL; | |
| td->td_stripoffsetbyteallocsize = 0; | |
| } | |
| } | |
| if (*parray == NULL || strile >= td->td_stripoffsetbyteallocsize) | |
| return 0; | |
| if (~((*parray)[strile]) == 0) | |
| { | |
| if (!_TIFFPartialReadStripArray(tif, dirent, (int)strile, *parray)) | |
| { | |
| (*parray)[strile] = 0; | |
| return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| static uint64_t _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32_t strile, | |
| TIFFDirEntry *dirent, | |
| uint64_t **parray, | |
| int *pbErr) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| if (pbErr) | |
| *pbErr = 0; | |
| /* Avoid the "dirent->tdir_count <= 4" code path for one of | |
| * StripOffsets/StripByteCounts, and the other code path for the other one, | |
| * which will lead to inconsistencies and potential out-of-bounds reads. | |
| */ | |
| if ((td->td_stripoffset_entry.tdir_count <= 4) != | |
| (td->td_stripbytecount_entry.tdir_count <= 4)) | |
| { | |
| TIFFErrorExtR(tif, "_TIFFGetStrileOffsetOrByteCountValue", | |
| "Inconsistent directory count between StripOffsets and " | |
| "StripByteCounts"); | |
| if (pbErr) | |
| *pbErr = 1; | |
| return 0; | |
| } | |
| if ((tif->tif_flags & TIFF_DEFERSTRILELOAD) && | |
| !(tif->tif_flags & TIFF_CHOPPEDUPARRAYS)) | |
| { | |
| if (!(tif->tif_flags & TIFF_LAZYSTRILELOAD_ASKED) || | |
| /* If the values may fit in the toff_long/toff_long8 member */ | |
| /* then use _TIFFFillStriles to simplify _TIFFFetchStrileValue */ | |
| dirent->tdir_count <= 4) | |
| { | |
| if (!_TIFFFillStriles(tif)) | |
| { | |
| if (pbErr) | |
| *pbErr = 1; | |
| /* Do not return, as we want this function to always */ | |
| /* return the same value if called several times with */ | |
| /* the same arguments */ | |
| } | |
| } | |
| else | |
| { | |
| if (!_TIFFFetchStrileValue(tif, strile, dirent, parray)) | |
| { | |
| if (pbErr) | |
| *pbErr = 1; | |
| return 0; | |
| } | |
| } | |
| } | |
| if (*parray == NULL || strile >= td->td_nstrips) | |
| { | |
| if (pbErr) | |
| *pbErr = 1; | |
| return 0; | |
| } | |
| return (*parray)[strile]; | |
| } | |
| /* Return the value of the TileOffsets/StripOffsets array for the specified | |
| * tile/strile */ | |
| uint64_t TIFFGetStrileOffset(TIFF *tif, uint32_t strile) | |
| { | |
| return TIFFGetStrileOffsetWithErr(tif, strile, NULL); | |
| } | |
| /* Return the value of the TileOffsets/StripOffsets array for the specified | |
| * tile/strile */ | |
| uint64_t TIFFGetStrileOffsetWithErr(TIFF *tif, uint32_t strile, int *pbErr) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| return _TIFFGetStrileOffsetOrByteCountValue(tif, strile, | |
| &(td->td_stripoffset_entry), | |
| &(td->td_stripoffset_p), pbErr); | |
| } | |
| /* Return the value of the TileByteCounts/StripByteCounts array for the | |
| * specified tile/strile */ | |
| uint64_t TIFFGetStrileByteCount(TIFF *tif, uint32_t strile) | |
| { | |
| return TIFFGetStrileByteCountWithErr(tif, strile, NULL); | |
| } | |
| /* Return the value of the TileByteCounts/StripByteCounts array for the | |
| * specified tile/strile */ | |
| uint64_t TIFFGetStrileByteCountWithErr(TIFF *tif, uint32_t strile, int *pbErr) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| return _TIFFGetStrileOffsetOrByteCountValue( | |
| tif, strile, &(td->td_stripbytecount_entry), &(td->td_stripbytecount_p), | |
| pbErr); | |
| } | |
| int _TIFFFillStriles(TIFF *tif) { return _TIFFFillStrilesInternal(tif, 1); } | |
| static int _TIFFFillStrilesInternal(TIFF *tif, int loadStripByteCount) | |
| { | |
| TIFFDirectory *td = &tif->tif_dir; | |
| int return_value = 1; | |
| /* Do not do anything if TIFF_DEFERSTRILELOAD is not set */ | |
| if (!(tif->tif_flags & TIFF_DEFERSTRILELOAD) || | |
| (tif->tif_flags & TIFF_CHOPPEDUPARRAYS) != 0) | |
| return 1; | |
| if ((tif->tif_flags & TIFF_LAZYSTRILELOAD_ASKED) && | |
| !(tif->tif_flags & TIFF_LAZYSTRILELOAD_DONE)) | |
| { | |
| /* In case of lazy loading, reload completely the arrays */ | |
| _TIFFfreeExt(tif, td->td_stripoffset_p); | |
| _TIFFfreeExt(tif, td->td_stripbytecount_p); | |
| td->td_stripoffset_p = NULL; | |
| td->td_stripbytecount_p = NULL; | |
| td->td_stripoffsetbyteallocsize = 0; | |
| tif->tif_flags |= TIFF_LAZYSTRILELOAD_DONE; | |
| } | |
| /* If stripoffset array is already loaded, exit with success */ | |
| if (td->td_stripoffset_p != NULL) | |
| return 1; | |
| /* If tdir_count was canceled, then we already got there, but in error */ | |
| if (td->td_stripoffset_entry.tdir_count == 0) | |
| return 0; | |
| if (!TIFFFetchStripThing(tif, &(td->td_stripoffset_entry), td->td_nstrips, | |
| &td->td_stripoffset_p)) | |
| { | |
| return_value = 0; | |
| } | |
| if (loadStripByteCount && | |
| !TIFFFetchStripThing(tif, &(td->td_stripbytecount_entry), | |
| td->td_nstrips, &td->td_stripbytecount_p)) | |
| { | |
| return_value = 0; | |
| } | |
| _TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); | |
| _TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); | |
| #ifdef STRIPBYTECOUNTSORTED_UNUSED | |
| if (tif->tif_dir.td_nstrips > 1 && return_value == 1) | |
| { | |
| uint32_t strip; | |
| tif->tif_dir.td_stripbytecountsorted = 1; | |
| for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) | |
| { | |
| if (tif->tif_dir.td_stripoffset_p[strip - 1] > | |
| tif->tif_dir.td_stripoffset_p[strip]) | |
| { | |
| tif->tif_dir.td_stripbytecountsorted = 0; | |
| break; | |
| } | |
| } | |
| } | |
| #endif | |
| return return_value; | |
| } |