/* * 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 #include #include #include #define FAILED_FII ((uint32_t)-1) #ifdef HAVE_IEEEFP #define TIFFCvtIEEEFloatToNative(tif, n, fp) #define TIFFCvtIEEEDoubleToNative(tif, n, dp) #else 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 = (uint16_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: 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: { 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: { 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: 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); #if defined(__WIN32__) && (_MSC_VER < 1500) /* * XXX: MSVC 6.0 does not support conversion * of 64-bit integers into floating point * values. */ *value = _TIFFUInt64ToFloat(m); #else *value = (float)m; #endif 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 > FLT_MAX) || (m < -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); #if defined(__WIN32__) && (_MSC_VER < 1500) /* * XXX: MSVC 6.0 does not support conversion * of 64-bit integers into floating point * values. */ *value = _TIFFUInt64ToDouble(m); #else *value = (double)m; #endif 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); 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(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 / typesize) < target_count64) return (TIFFReadDirEntryErrSizesan); if ((uint64_t)(MAX_SIZE_TAG_DATA / desttypesize) < target_count64) return (TIFFReadDirEntryErrSizesan); *count = (uint32_t)target_count64; datasize = (*count) * typesize; assert((tmsize_t)datasize > 0); 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); } } 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; } _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); } 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; } _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); } } 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; } _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); } 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; } _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: 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: *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); } } 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: { 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; } _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); } 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; } _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: 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: *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); } } 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: { 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; } _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); } 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; } _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); TIFFCvtIEEEDoubleToNative(tif, count, (float *)origdata); *value = (float *)origdata; return (TIFFReadDirEntryErrOk); } data = (float *)_TIFFmallocExt(tif, 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); #if defined(__WIN32__) && (_MSC_VER < 1500) /* * XXX: MSVC 6.0 does not support * conversion of 64-bit integers into * floating point values. */ *mb++ = _TIFFUInt64ToFloat(*ma++); #else *mb++ = (float)(*ma++); #endif } } 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 > FLT_MAX) val = FLT_MAX; else if (val < -FLT_MAX) val = -FLT_MAX; *mb++ = (float)val; } } 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); } data = (double *)_TIFFmallocExt(tif, 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); #if defined(__WIN32__) && (_MSC_VER < 1500) /* * XXX: MSVC 6.0 does not support * conversion of 64-bit integers into * floating point values. */ *mb++ = _TIFFUInt64ToDouble(*ma++); #else *mb++ = (double)(*ma++); #endif } } 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; } _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); } 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; } _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) return (TIFFReadDirEntryErrCount); err = TIFFReadDirEntryShortArray(tif, direntry, &m); if (err != TIFFReadDirEntryErrOk || m == NULL) return (err); na = m; nb = tif->tif_dir.td_samplesperpixel; *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 = ma + 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; 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; 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; } /* * 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++; (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ 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 = 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; /* free any old stuff and reinit */ TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); /* * 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) { 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 */ if (!_TIFFMergeFields( tif, _TIFFCreateAnonField(tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type), 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)) { TIFFWarningExtR(tif, module, "TIFF directory is missing required ImageLength field"); } /* * 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 (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 (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)); 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)); 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 (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; } } /* -- if (!dp->tdir_ignore) */ } /* -- for-loop -- */ /* * 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; } 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)((1L << 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 i/o since we are starting on a new directory. */ tif->tif_row = (uint32_t)-1; tif->tif_curstrip = (uint32_t)-1; tif->tif_col = (uint32_t)-1; tif->tif_curtile = (uint32_t)-1; tif->tif_tilesize = (tmsize_t)-1; tif->tif_scanlinesize = TIFFScanlineSize(tif); if (!tif->tif_scanlinesize) { TIFFWarningExtR(tif, module, "Cannot handle zero scanline size"); } if (isTiled(tif)) { tif->tif_tilesize = TIFFTileSize(tif); if (!tif->tif_tilesize) { TIFFWarningExtR(tif, module, "Cannot handle zero tile size"); } } else { if (!TIFFStripSize(tif)) { TIFFWarningExt(tif, module, "Cannot handle zero strip size"); } } return (1); bad: if (dir) _TIFFfreeExt(tif, dir); return (0); } 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 + 1; } } 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 = 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; (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ _TIFFSetupFields(tif, infoarray); dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); if (!dircount) { TIFFWarningExtR(tif, module, "Failed to read custom directory at offset %" PRIu64, diroff); return 0; } TIFFFreeDirectory(tif); _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); TIFFReadDirectoryCheckOrder(tif, dir, dircount); for (di = 0, dp = dir; di < dircount; di++, dp++) { TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); if (fii == FAILED_FII) { TIFFWarningExtR(tif, module, "Unknown field with tag %" PRIu16 " (0x%" PRIx16 ") encountered", dp->tdir_tag, dp->tdir_tag); if (!_TIFFMergeFields( tif, _TIFFCreateAnonField(tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type), 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 { /* 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) */ } } /* 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) { const TIFFFieldArray *exifFieldArray; exifFieldArray = _TIFFGetExifFields(); return TIFFReadCustomDirectory(tif, diroff, exifFieldArray); } /* *--: EXIF-GPS custom directory reading as another special case of custom IFD. */ int TIFFReadGPSDirectory(TIFF *tif, toff_t diroff) { const TIFFFieldArray *gpsFieldArray; gpsFieldArray = _TIFFGetGpsFields(); return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray); } 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; 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; uint64_t filesize; uint16_t n; filesize = TIFFGetFileSize(tif); if (!(tif->tif_flags & TIFF_BIGTIFF)) space = sizeof(TIFFHeaderClassic) + 2 + dircount * 12 + 4; else space = sizeof(TIFFHeaderBig) + 8 + 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 = 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 < 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"; TIFFWarningExtR(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", 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 = off + sizeof(uint16_t); if ((m < off) || (m < (tmsize_t)sizeof(uint16_t)) || (m > 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 += 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 = off + sizeof(uint64_t); if ((m < off) || (m < (tmsize_t)sizeof(uint64_t)) || (m > 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 += 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) { TIFFWarningExtR(tif, module, "Sanity check on directory count failed, zero tag " "directories not supported"); 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 * 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, dircount16 * dirsize); } if (nextdiroff) { off += dircount16 * dirsize; if (!(tif->tif_flags & TIFF_BIGTIFF)) { uint32_t nextdiroff32; m = off + sizeof(uint32_t); if ((m < off) || (m < (tmsize_t)sizeof(uint32_t)) || (m > 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 = off + sizeof(uint64_t); if ((m < off) || (m < (tmsize_t)sizeof(uint64_t)) || (m > tif->tif_size)) *nextdiroff = 0; else _TIFFmemcpy(nextdiroff, tif->tif_base + off, sizeof(uint64_t)); if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(nextdiroff); } } } 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_field_type != TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */ assert(fip->set_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_field_type) { case TIFF_SETGET_UNDEFINED: TIFFErrorExtR( tif, "TIFFFetchNormalTag", "Defined set_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 (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) { uint8_t *o; TIFFWarningExtR( tif, module, "ASCII value for tag \"%s\" does not end in null byte", 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); o = _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 (!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 (!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 (!TIFFSetField(tif, dp->tdir_tag, 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 (!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 (!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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { int m; if (data != 0 && dp->tdir_count > 0 && data[dp->tdir_count - 1] != '\0') { TIFFWarningExtR( tif, module, "ASCII value for tag \"%s\" does not end in null " "byte. Forcing it to be null", fip->field_name); data[dp->tdir_count - 1] = '\0'; } 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { int m; if (data != 0 && dp->tdir_count > 0 && data[dp->tdir_count - 1] != '\0') { TIFFWarningExtR(tif, module, "ASCII value for tag \"%s\" does not end " "in null byte. Forcing it to be null", fip->field_name); data[dp->tdir_count - 1] = '\0'; } 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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; 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); } 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, (uint32_t)dir->tdir_count * sizeof(uint64_t)); _TIFFmemset(resizeddata + (uint32_t)dir->tdir_count, 0, (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; 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) { register 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 = TIFFGetStrileByteCount(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) 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); 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 + 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 + sizeofval * 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 + 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, nArraySize)); bytecountArray = (uint64_t *)(_TIFFreallocExt( tif, td->td_stripbytecount_p, 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, 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; if ((tif->tif_flags & TIFF_DEFERSTRILELOAD) && !(tif->tif_flags & TIFF_CHOPPEDUPARRAYS)) { if (!(tif->tif_flags & TIFF_LAZYSTRILELOAD) || /* 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) { register 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) { /* 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; } /* 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; }