| /* $Id: tif_dirread.c,v 1.218 2017-09-09 21:44:42 erouault Exp $ */ |
| |
| /* |
| * 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 'ignore' to the TIFFDirEntry structure, to flag status, |
| * eliminating current use of the IGNORE value, and therefore eliminating |
| * current irrational behaviour on tags with tag id code 0 |
| * - 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 "tiffiop.h" |
| #include <float.h> |
| #include <limits.h> |
| #include <stdlib.h> |
| |
| #define IGNORE 0 /* tag placeholder used below */ |
| #define FAILED_FII ((uint32) -1) |
| |
| #ifdef HAVE_IEEEFP |
| # define TIFFCvtIEEEFloatToNative(tif, n, fp) |
| # define TIFFCvtIEEEDoubleToNative(tif, n, dp) |
| #else |
| extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*); |
| extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, 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* value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* 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* value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** 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** value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); |
| #if 0 |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); |
| #endif |
| |
| static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value); |
| static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value); |
| static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); |
| static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value); |
| static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value); |
| static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* 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); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32 value); |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value); |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64 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 dircount); |
| static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid); |
| static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii); |
| |
| static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount); |
| static void MissingRequired(TIFF*, const char*); |
| static int TIFFCheckDirOffset(TIFF* tif, uint64 diroff); |
| static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32); |
| static uint16 TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, uint64* nextdiroff); |
| static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover); |
| static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp); |
| static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*); |
| static void ChopUpSingleUncompressedStrip(TIFF*); |
| static uint64 TIFFReadUInt64(const uint8 *value); |
| |
| static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ); |
| |
| typedef union _UInt64Aligned_t |
| { |
| double d; |
| uint64 l; |
| uint32 i[2]; |
| uint16 s[4]; |
| uint8 c[8]; |
| } UInt64Aligned_t; |
| |
| /* |
| Unaligned safe copy of a uint64 value from an octet array. |
| */ |
| static uint64 TIFFReadUInt64(const uint8 *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* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| if (direntry->tdir_count!=1) |
| return(TIFFReadDirEntryErrCount); |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| TIFFReadDirEntryCheckedByte(tif,direntry,value); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeByteSbyte(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| { |
| uint16 m; |
| TIFFReadDirEntryCheckedShort(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeByteShort(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeByteSshort(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeByteLong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeByteSlong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| { |
| uint64 m; |
| err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeByteLong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG8: |
| { |
| int64 m; |
| err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeByteSlong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint8)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| default: |
| return(TIFFReadDirEntryErrType); |
| } |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| if (direntry->tdir_count!=1) |
| return(TIFFReadDirEntryErrCount); |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8 m; |
| TIFFReadDirEntryCheckedByte(tif,direntry,&m); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeShortSbyte(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| TIFFReadDirEntryCheckedShort(tif,direntry,value); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeShortSshort(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeShortLong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeShortSlong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| { |
| uint64 m; |
| err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeShortLong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG8: |
| { |
| int64 m; |
| err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeShortSlong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint16)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| default: |
| return(TIFFReadDirEntryErrType); |
| } |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| if (direntry->tdir_count!=1) |
| return(TIFFReadDirEntryErrCount); |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8 m; |
| TIFFReadDirEntryCheckedByte(tif,direntry,&m); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLongSbyte(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| { |
| uint16 m; |
| TIFFReadDirEntryCheckedShort(tif,direntry,&m); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLongSshort(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| TIFFReadDirEntryCheckedLong(tif,direntry,value); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLongSlong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| { |
| uint64 m; |
| err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeLongLong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG8: |
| { |
| int64 m; |
| err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeLongSlong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint32)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| default: |
| return(TIFFReadDirEntryErrType); |
| } |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| if (direntry->tdir_count!=1) |
| return(TIFFReadDirEntryErrCount); |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8 m; |
| TIFFReadDirEntryCheckedByte(tif,direntry,&m); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLong8Sbyte(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| { |
| uint16 m; |
| TIFFReadDirEntryCheckedShort(tif,direntry,&m); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLong8Sshort(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| err=TIFFReadDirEntryCheckRangeLong8Slong(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| err=TIFFReadDirEntryCheckedLong8(tif,direntry,value); |
| return(err); |
| case TIFF_SLONG8: |
| { |
| int64 m; |
| err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| err=TIFFReadDirEntryCheckRangeLong8Slong8(m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| *value=(uint64)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| default: |
| return(TIFFReadDirEntryErrType); |
| } |
| } |
| |
| 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 m; |
| TIFFReadDirEntryCheckedByte(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| { |
| uint16 m; |
| TIFFReadDirEntryCheckedShort(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| *value=(float)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| { |
| uint64 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 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_MIN)) |
| 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 m; |
| TIFFReadDirEntryCheckedByte(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| { |
| int8 m; |
| TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SHORT: |
| { |
| uint16 m; |
| TIFFReadDirEntryCheckedShort(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| { |
| int16 m; |
| TIFFReadDirEntryCheckedSshort(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| { |
| int32 m; |
| TIFFReadDirEntryCheckedSlong(tif,direntry,&m); |
| *value=(double)m; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_LONG8: |
| { |
| uint64 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 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* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| if (direntry->tdir_count!=1) |
| return(TIFFReadDirEntryErrCount); |
| switch (direntry->tdir_type) |
| { |
| case TIFF_LONG: |
| case TIFF_IFD: |
| { |
| uint32 m; |
| TIFFReadDirEntryCheckedLong(tif,direntry,&m); |
| *value=(uint64)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 offset, tmsize_t size, void** pdest) |
| { |
| #if SIZEOF_VOIDP == 8 || 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_VOIDP == 8 || SIZEOF_SIZE_T == 8 |
| if( to_read >= threshold && threshold < MAX_THRESHOLD ) |
| { |
| to_read = threshold; |
| threshold *= THRESHOLD_MULTIPLIER; |
| } |
| #endif |
| |
| new_dest = (uint8*) _TIFFrealloc( |
| *pdest, already_read + to_read); |
| if( new_dest == NULL ) |
| { |
| TIFFErrorExt(tif->tif_clientdata, tif->tif_name, |
| "Failed to allocate memory for %s " |
| "(%ld elements of %ld bytes each)", |
| "TIFFReadDirEntryArray", |
| (long) 1, (long) (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; |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryArrayWithLimit( |
| TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, |
| void** value, uint64 maxcount) |
| { |
| int typesize; |
| uint32 datasize; |
| void* data; |
| uint64 target_count64; |
| 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; |
| |
| /* |
| * 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)(2147483647/typesize)<target_count64) |
| return(TIFFReadDirEntryErrSizesan); |
| if ((uint64)(2147483647/desttypesize)<target_count64) |
| return(TIFFReadDirEntryErrSizesan); |
| |
| *count=(uint32)target_count64; |
| datasize=(*count)*typesize; |
| assert((tmsize_t)datasize>0); |
| |
| if( isMapped(tif) && datasize > (uint32)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)) |
| { |
| if (datasize<=4) |
| _TIFFmemcpy(data,&direntry->tdir_offset,datasize); |
| else |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 offset = direntry->tdir_offset.toff_long; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(&offset); |
| if( isMapped(tif) ) |
| err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data); |
| else |
| err=TIFFReadDirEntryDataAndRealloc(tif,(uint64)offset,(tmsize_t)datasize,&data); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| } |
| } |
| else |
| { |
| if (datasize<=8) |
| _TIFFmemcpy(data,&direntry->tdir_offset,datasize); |
| else |
| { |
| enum TIFFReadDirEntryErr err; |
| uint64 offset = direntry->tdir_offset.toff_long8; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8(&offset); |
| if( isMapped(tif) ) |
| err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data); |
| else |
| err=TIFFReadDirEntryDataAndRealloc(tif,(uint64)offset,(tmsize_t)datasize,&data); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| } |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value) |
| { |
| return TIFFReadDirEntryArrayWithLimit(tif, direntry, count, |
| desttypesize, value, ~((uint64)0)); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| uint8* 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*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SBYTE: |
| { |
| int8* m; |
| uint32 n; |
| m=(int8*)origdata; |
| for (n=0; n<count; n++) |
| { |
| err=TIFFReadDirEntryCheckRangeByteSbyte(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(uint8*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| } |
| data=(uint8*)_TIFFmalloc(count); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(uint16*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| err=TIFFReadDirEntryCheckRangeByteSshort(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint8)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(uint32*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| err=TIFFReadDirEntryCheckRangeByteSlong(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint8)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| uint8* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeByteSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint8)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| int8* 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* m; |
| uint32 n; |
| m=(uint8*)origdata; |
| for (n=0; n<count; n++) |
| { |
| err=TIFFReadDirEntryCheckRangeSbyteByte(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(int8*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SBYTE: |
| *value=(int8*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(int8*)_TIFFmalloc(count); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| int8* mb; |
| uint32 n; |
| ma=(uint16*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| int8* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int8)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| int8* mb; |
| uint32 n; |
| ma=(uint32*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| int8* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int8)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| int8* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| int8* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int8)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| uint16* 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*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfShort(*value,count); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SSHORT: |
| { |
| int16* m; |
| uint32 n; |
| m=(int16*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)m); |
| err=TIFFReadDirEntryCheckRangeShortSshort(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(uint16*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| } |
| data=(uint16*)_TIFFmalloc(count*2); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(uint16)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| err=TIFFReadDirEntryCheckRangeShortSbyte(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint16)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(uint32*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| err=TIFFReadDirEntryCheckRangeShortSlong(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint16)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| uint16* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeShortSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint16)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| int16* 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* m; |
| uint32 n; |
| m=(uint16*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(m); |
| err=TIFFReadDirEntryCheckRangeSshortShort(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(int16*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SSHORT: |
| *value=(int16*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfShort((uint16*)(*value),count); |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(int16*)_TIFFmalloc(count*2); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| int16* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int16)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| int16* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int16)(*ma++); |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| int16* mb; |
| uint32 n; |
| ma=(uint32*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| int16* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| err=TIFFReadDirEntryCheckRangeSshortSlong(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int16)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| int16* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| int16* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int16)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| uint32* 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*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong(*value,count); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SLONG: |
| { |
| int32* m; |
| uint32 n; |
| m=(int32*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)m); |
| err=TIFFReadDirEntryCheckRangeLongSlong(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(uint32*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| } |
| data=(uint32*)_TIFFmalloc(count*4); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(uint32)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| err=TIFFReadDirEntryCheckRangeLongSbyte(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint32)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(uint16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(ma); |
| *mb++=(uint32)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| err=TIFFReadDirEntryCheckRangeLongSshort(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint32)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| uint32* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeLongSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint32)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| int32* 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* m; |
| uint32 n; |
| m=(uint32*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)m); |
| err=TIFFReadDirEntryCheckRangeSlongLong(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(int32*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG: |
| *value=(int32*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong((uint32*)(*value),count); |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(int32*)_TIFFmalloc(count*4); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| int32* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int32)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| int32* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int32)(*ma++); |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| int32* mb; |
| uint32 n; |
| ma=(uint16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(ma); |
| *mb++=(int32)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| int32* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| *mb++=(int32)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| int32* mb; |
| uint32 n; |
| ma=(uint64*)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)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG8: |
| { |
| int64* ma; |
| int32* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(int32)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8ArrayWithLimit( |
| TIFF* tif, TIFFDirEntry* direntry, uint64** value, uint64 maxcount) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| uint64* 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*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong8(*value,count); |
| return(TIFFReadDirEntryErrOk); |
| case TIFF_SLONG8: |
| { |
| int64* m; |
| uint32 n; |
| m=(int64*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)m); |
| err=TIFFReadDirEntryCheckRangeLong8Slong8(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(uint64*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| } |
| data=(uint64*)_TIFFmalloc(count*8); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(uint64)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| err=TIFFReadDirEntryCheckRangeLong8Sbyte(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(uint16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(ma); |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(uint32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(ma); |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| err=TIFFReadDirEntryCheckRangeLong8Slong(*ma); |
| if (err!=TIFFReadDirEntryErrOk) |
| break; |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(data); |
| return(err); |
| } |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value) |
| { |
| return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, ~((uint64)0)); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| int64* 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* m; |
| uint32 n; |
| m=(uint64*)origdata; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8(m); |
| err=TIFFReadDirEntryCheckRangeSlong8Long8(*m); |
| if (err!=TIFFReadDirEntryErrOk) |
| { |
| _TIFFfree(origdata); |
| return(err); |
| } |
| m++; |
| } |
| *value=(int64*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| case TIFF_SLONG8: |
| *value=(int64*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong8((uint64*)(*value),count); |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(int64*)_TIFFmalloc(count*8); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| int64* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int64)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| int64* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(int64)(*ma++); |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| int64* mb; |
| uint32 n; |
| ma=(uint16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(ma); |
| *mb++=(int64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SSHORT: |
| { |
| int16* ma; |
| int64* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| *mb++=(int64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| int64* mb; |
| uint32 n; |
| ma=(uint32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(ma); |
| *mb++=(int64)(*ma++); |
| } |
| } |
| break; |
| case TIFF_SLONG: |
| { |
| int32* ma; |
| int64* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| *mb++=(int64)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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*)origdata,count); |
| TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata); |
| *value=(float*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(float*)_TIFFmalloc(count*sizeof(float)); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| float* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(float)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| float* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(float)(*ma++); |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| float* mb; |
| uint32 n; |
| ma=(uint16*)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* ma; |
| float* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| *mb++=(float)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| float* mb; |
| uint32 n; |
| ma=(uint32*)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* ma; |
| float* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| *mb++=(float)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| float* mb; |
| uint32 n; |
| ma=(uint64*)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* ma; |
| float* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| *mb++=(float)(*ma++); |
| } |
| } |
| break; |
| case TIFF_RATIONAL: |
| { |
| uint32* ma; |
| uint32 maa; |
| uint32 mab; |
| float* mb; |
| uint32 n; |
| ma=(uint32*)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* ma; |
| int32 maa; |
| uint32 mab; |
| float* mb; |
| uint32 n; |
| ma=(uint32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(ma); |
| maa=*(int32*)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 n; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong8((uint64*)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; |
| } |
| _TIFFfree(origdata); |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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*)origdata,count); |
| TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata); |
| *value=(double*)origdata; |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(double*)_TIFFmalloc(count*sizeof(double)); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_BYTE: |
| { |
| uint8* ma; |
| double* mb; |
| uint32 n; |
| ma=(uint8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(double)(*ma++); |
| } |
| break; |
| case TIFF_SBYTE: |
| { |
| int8* ma; |
| double* mb; |
| uint32 n; |
| ma=(int8*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(double)(*ma++); |
| } |
| break; |
| case TIFF_SHORT: |
| { |
| uint16* ma; |
| double* mb; |
| uint32 n; |
| ma=(uint16*)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* ma; |
| double* mb; |
| uint32 n; |
| ma=(int16*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| *mb++=(double)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG: |
| { |
| uint32* ma; |
| double* mb; |
| uint32 n; |
| ma=(uint32*)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* ma; |
| double* mb; |
| uint32 n; |
| ma=(int32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| *mb++=(double)(*ma++); |
| } |
| } |
| break; |
| case TIFF_LONG8: |
| { |
| uint64* ma; |
| double* mb; |
| uint32 n; |
| ma=(uint64*)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* ma; |
| double* mb; |
| uint32 n; |
| ma=(int64*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| *mb++=(double)(*ma++); |
| } |
| } |
| break; |
| case TIFF_RATIONAL: |
| { |
| uint32* ma; |
| uint32 maa; |
| uint32 mab; |
| double* mb; |
| uint32 n; |
| ma=(uint32*)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* ma; |
| int32 maa; |
| uint32 mab; |
| double* mb; |
| uint32 n; |
| ma=(uint32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(ma); |
| maa=*(int32*)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 n; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong((uint32*)origdata,count); |
| TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata); |
| ma=(float*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| *mb++=(double)(*ma++); |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 count; |
| void* origdata; |
| uint64* 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*)origdata; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabArrayOfLong8(*value,count); |
| return(TIFFReadDirEntryErrOk); |
| } |
| data=(uint64*)_TIFFmalloc(count*8); |
| if (data==0) |
| { |
| _TIFFfree(origdata); |
| return(TIFFReadDirEntryErrAlloc); |
| } |
| switch (direntry->tdir_type) |
| { |
| case TIFF_LONG: |
| case TIFF_IFD: |
| { |
| uint32* ma; |
| uint64* mb; |
| uint32 n; |
| ma=(uint32*)origdata; |
| mb=data; |
| for (n=0; n<count; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(ma); |
| *mb++=(uint64)(*ma++); |
| } |
| } |
| break; |
| } |
| _TIFFfree(origdata); |
| *value=data; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint16* m; |
| uint16* na; |
| uint16 nb; |
| if (direntry->tdir_count<(uint64)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--; |
| } |
| _TIFFfree(m); |
| return(err); |
| } |
| |
| #if 0 |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) |
| { |
| enum TIFFReadDirEntryErr err; |
| double* m; |
| double* na; |
| uint16 nb; |
| if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel) |
| return(TIFFReadDirEntryErrCount); |
| err=TIFFReadDirEntryDoubleArray(tif,direntry,&m); |
| if (err!=TIFFReadDirEntryErrOk) |
| return(err); |
| na=m; |
| nb=tif->tif_dir.td_samplesperpixel; |
| *value=*na++; |
| nb--; |
| while (nb>0) |
| { |
| if (*na++!=*value) |
| { |
| err=TIFFReadDirEntryErrPsdif; |
| break; |
| } |
| nb--; |
| } |
| _TIFFfree(m); |
| return(err); |
| } |
| #endif |
| |
| static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value) |
| { |
| (void) tif; |
| *value=*(uint8*)(&direntry->tdir_offset); |
| } |
| |
| static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value) |
| { |
| (void) tif; |
| *value=*(int8*)(&direntry->tdir_offset); |
| } |
| |
| static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) |
| { |
| *value = direntry->tdir_offset.toff_short; |
| /* *value=*(uint16*)(&direntry->tdir_offset); */ |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort(value); |
| } |
| |
| static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value) |
| { |
| *value=*(int16*)(&direntry->tdir_offset); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)value); |
| } |
| |
| static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value) |
| { |
| *value=*(uint32*)(&direntry->tdir_offset); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(value); |
| } |
| |
| static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value) |
| { |
| *value=*(int32*)(&direntry->tdir_offset); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)value); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value) |
| { |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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* value) |
| { |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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*)(&direntry->tdir_offset); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)value); |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value) |
| { |
| UInt64Aligned_t m; |
| |
| assert(sizeof(double)==8); |
| assert(sizeof(uint64)==8); |
| assert(sizeof(uint32)==4); |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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)==8); |
| assert(sizeof(int32)==4); |
| assert(sizeof(uint32)==4); |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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)m.i[0]==0 || m.i[1]==0) |
| *value=0.0; |
| else |
| *value=(double)((int32)m.i[0])/(double)m.i[1]; |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value) |
| { |
| union |
| { |
| float f; |
| uint32 i; |
| } float_union; |
| assert(sizeof(float)==4); |
| assert(sizeof(uint32)==4); |
| assert(sizeof(float_union)==4); |
| float_union.i=*(uint32*)(&direntry->tdir_offset); |
| *value=float_union.f; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)value); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) |
| { |
| assert(sizeof(double)==8); |
| assert(sizeof(uint64)==8); |
| assert(sizeof(UInt64Aligned_t)==8); |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 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*)value); |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value) |
| { |
| if (value>0xFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value) |
| { |
| if ((value<0)||(value>0xFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value) |
| { |
| if (value>0xFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value) |
| { |
| if ((value<0)||(value>0xFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value) |
| { |
| if (value>0xFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value) |
| { |
| if ((value<0)||(value>0xFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value) |
| { |
| if (value>0x7F) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value) |
| { |
| if (value>0x7F) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value) |
| { |
| if ((value<-0x80)||(value>0x7F)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value) |
| { |
| if (value>0x7F) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value) |
| { |
| if ((value<-0x80)||(value>0x7F)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value) |
| { |
| if (value>0x7F) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value) |
| { |
| if ((value<-0x80)||(value>0x7F)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value) |
| { |
| if (value>0xFFFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value) |
| { |
| if ((value<0)||(value>0xFFFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value) |
| { |
| if (value>0xFFFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value) |
| { |
| if ((value<0)||(value>0xFFFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value) |
| { |
| if (value>0x7FFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value) |
| { |
| if (value>0x7FFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value) |
| { |
| if ((value<-0x8000)||(value>0x7FFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value) |
| { |
| if (value>0x7FFF) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value) |
| { |
| if ((value<-0x8000)||(value>0x7FFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value) |
| { |
| if (value<0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| /* |
| * Largest 32-bit unsigned integer value. |
| */ |
| #define TIFF_UINT32_MAX 0xFFFFFFFFU |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLongLong8(uint64 value) |
| { |
| if (value > TIFF_UINT32_MAX) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLongSlong8(int64 value) |
| { |
| if ((value < 0) || (value > (int64) TIFF_UINT32_MAX)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| #undef TIFF_UINT32_MAX |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeSlongLong(uint32 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 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 value) |
| { |
| if ((value < 0-((int64) 0x7FFFFFFF+1)) || (value > 0x7FFFFFFF)) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value) |
| { |
| if (value < 0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLong8Sshort(int16 value) |
| { |
| if (value < 0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLong8Slong(int32 value) |
| { |
| if (value < 0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeLong8Slong8(int64 value) |
| { |
| if (value < 0) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| /* |
| * Largest 64-bit signed integer value. |
| */ |
| #define TIFF_INT64_MAX ((int64)(((uint64) ~0) >> 1)) |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value) |
| { |
| if (value > TIFF_INT64_MAX) |
| return(TIFFReadDirEntryErrRange); |
| else |
| return(TIFFReadDirEntryErrOk); |
| } |
| |
| #undef TIFF_INT64_MAX |
| |
| static enum TIFFReadDirEntryErr |
| TIFFReadDirEntryData(TIFF* tif, uint64 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; |
| mb=ma+size; |
| if (((uint64)ma!=offset) |
| || (mb < ma) |
| || (mb - ma != (size_t) size) |
| || (mb < (size_t)size) |
| || (mb > (size_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: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Incorrect count for \"%s\"", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrType: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Incompatible type for \"%s\"", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrIo: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "IO error during reading of \"%s\"", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrRange: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Incorrect value for \"%s\"", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrPsdif: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle different values per sample for \"%s\"", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrSizesan: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Sanity check on size of \"%s\" value failed", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrAlloc: |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Out of memory reading of \"%s\"", |
| tagname); |
| break; |
| default: |
| assert(0); /* we should never get here */ |
| break; |
| } |
| } else { |
| switch (err) { |
| case TIFFReadDirEntryErrCount: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Incorrect count for \"%s\"; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrType: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Incompatible type for \"%s\"; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrIo: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "IO error during reading of \"%s\"; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrRange: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Incorrect value for \"%s\"; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrPsdif: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Cannot handle different values per sample for \"%s\"; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrSizesan: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Sanity check on size of \"%s\" value failed; tag ignored", |
| tagname); |
| break; |
| case TIFFReadDirEntryErrAlloc: |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Out of memory reading of \"%s\"; tag ignored", |
| tagname); |
| break; |
| default: |
| assert(0); /* we should never get here */ |
| break; |
| } |
| } |
| } |
| |
| /* |
| * 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 dircount; |
| TIFFDirEntry* dp; |
| uint16 di; |
| const TIFFField* fip; |
| uint32 fii=FAILED_FII; |
| toff_t nextdiroff; |
| int bitspersample_read = FALSE; |
| |
| tif->tif_diroff=tif->tif_nextdiroff; |
| if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff)) |
| return 0; /* last offset or bad offset (IFD looping) */ |
| (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ |
| tif->tif_curdir++; |
| nextdiroff = tif->tif_nextdiroff; |
| dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff); |
| if (!dircount) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module, |
| "Failed to read directory at offset " TIFF_UINT64_FORMAT,nextdiroff); |
| return 0; |
| } |
| TIFFReadDirectoryCheckOrder(tif,dir,dircount); |
| |
| /* |
| * Mark duplicates of any tag to be ignored (bugzilla 1994) |
| * to avoid certain pathological problems. |
| */ |
| { |
| TIFFDirEntry* ma; |
| uint16 mb; |
| for (ma=dir, mb=0; mb<dircount; ma++, mb++) |
| { |
| TIFFDirEntry* na; |
| uint16 nb; |
| for (na=ma+1, nb=mb+1; nb<dircount; na++, nb++) |
| { |
| if (ma->tdir_tag==na->tdir_tag) |
| na->tdir_tag=IGNORE; |
| } |
| } |
| } |
| |
| tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ |
| tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */ |
| /* 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. |
| */ |
| 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_tag=IGNORE; |
| } |
| 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 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_tag=IGNORE; |
| } |
| 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_tag!=IGNORE) |
| { |
| TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
| if (fii == FAILED_FII) |
| { |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Unknown field with tag %d (0x%x) 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)) { |
| TIFFWarningExt(tif->tif_clientdata, |
| module, |
| "Registering anonymous field with tag %d (0x%x) failed", |
| dp->tdir_tag, |
| dp->tdir_tag); |
| dp->tdir_tag=IGNORE; |
| } else { |
| TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
| assert(fii != FAILED_FII); |
| } |
| } |
| } |
| if (dp->tdir_tag!=IGNORE) |
| { |
| fip=tif->tif_fields[fii]; |
| if (fip->field_bit==FIELD_IGNORE) |
| dp->tdir_tag=IGNORE; |
| 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_tag=IGNORE; |
| break; |
| default: |
| if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) ) |
| dp->tdir_tag=IGNORE; |
| 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; |
| TIFFWarningExt(tif->tif_clientdata,module, |
| "Planarconfig tag value assumed incorrect, " |
| "assuming data is contig instead of chunky"); |
| } |
| } |
| } |
| /* |
| * Allocate directory structure and setup defaults. |
| */ |
| if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) |
| { |
| MissingRequired(tif,"ImageLength"); |
| goto bad; |
| } |
| /* |
| * Setup appropriate structures (by strip or by tile) |
| */ |
| 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) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle zero number of %s", |
| isTiled(tif) ? "tiles" : "strips"); |
| goto bad; |
| } |
| if (tif->tif_dir.td_nstrips > INT_MAX) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle %u number of %s", |
| tif->tif_dir.td_nstrips, |
| isTiled(tif) ? "tiles" : "strips"); |
| goto bad; |
| } |
| tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; |
| if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) |
| tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; |
| if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { |
| #ifdef OJPEG_SUPPORT |
| if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) && |
| (isTiled(tif)==0) && |
| (tif->tif_dir.td_nstrips==1)) { |
| /* |
| * XXX: OJPEG hack. |
| * If a) compression is OJPEG, b) it's not a tiled TIFF, |
| * and c) the number of strips is 1, |
| * then we tolerate the absence of stripoffsets tag, |
| * because, presumably, all required data is in the |
| * JpegInterchangeFormat stream. |
| */ |
| TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); |
| } else |
| #endif |
| { |
| MissingRequired(tif, |
| isTiled(tif) ? "TileOffsets" : "StripOffsets"); |
| goto bad; |
| } |
| } |
| /* |
| * Second pass: extract other information. |
| */ |
| for (di=0, dp=dir; di<dircount; di++, dp++) |
| { |
| switch (dp->tdir_tag) |
| { |
| case IGNORE: |
| break; |
| 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 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 saved_flags; |
| int m; |
| if (dp->tdir_count != (uint64)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; |
| _TIFFfree(data); |
| if (!m) |
| goto bad; |
| } |
| break; |
| case TIFFTAG_STRIPOFFSETS: |
| case TIFFTAG_TILEOFFSETS: |
| #if defined(DEFER_STRILE_LOAD) |
| _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry), |
| dp, sizeof(TIFFDirEntry) ); |
| #else |
| if( tif->tif_dir.td_stripoffset != NULL ) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "tif->tif_dir.td_stripoffset is " |
| "already allocated. Likely duplicated " |
| "StripOffsets/TileOffsets tag"); |
| goto bad; |
| } |
| if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset)) |
| goto bad; |
| #endif |
| break; |
| case TIFFTAG_STRIPBYTECOUNTS: |
| case TIFFTAG_TILEBYTECOUNTS: |
| #if defined(DEFER_STRILE_LOAD) |
| _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry), |
| dp, sizeof(TIFFDirEntry) ); |
| #else |
| if( tif->tif_dir.td_stripbytecount != NULL ) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "tif->tif_dir.td_stripbytecount is " |
| "already allocated. Likely duplicated " |
| "StripByteCounts/TileByteCounts tag"); |
| goto bad; |
| } |
| if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount)) |
| goto bad; |
| #endif |
| break; |
| case TIFFTAG_COLORMAP: |
| case TIFFTAG_TRANSFERFUNCTION: |
| { |
| enum TIFFReadDirEntryErr err; |
| uint32 countpersample; |
| uint32 countrequired; |
| uint32 incrementpersample; |
| uint16* 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); |
| TIFFWarningExt(tif->tif_clientdata,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); |
| TIFFWarningExt(tif->tif_clientdata,module, |
| "Ignoring %s because BitsPerSample=%d>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)countpersample)) |
| { |
| countrequired=countpersample; |
| incrementpersample=0; |
| } |
| else |
| { |
| countrequired=3*countpersample; |
| incrementpersample=countpersample; |
| } |
| if (dp->tdir_count!=(uint64)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); |
| _TIFFfree(value); |
| } |
| } |
| break; |
| /* BEGIN REV 4.0 COMPATIBILITY */ |
| case TIFFTAG_OSUBFILETYPE: |
| { |
| uint16 valueo; |
| uint32 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 */ |
| default: |
| (void) TIFFFetchNormalTag(tif, dp, TRUE); |
| break; |
| } |
| } |
| /* |
| * 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)) |
| { |
| TIFFWarningExt(tif->tif_clientdata, 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; |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Photometric tag value assumed incorrect, " |
| "assuming data is YCbCr instead of RGB"); |
| } |
| if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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; |
| } |
| } |
| } |
| /* |
| * 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)tif->tif_dir.td_samplesperpixel)) { |
| MissingRequired(tif, "StripByteCounts"); |
| goto bad; |
| } |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "TIFF directory is missing required " |
| "\"StripByteCounts\" field, calculating from imagelength"); |
| if (EstimateStripByteCounts(tif, dir, dircount) < 0) |
| goto bad; |
| /* |
| * 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. |
| */ |
| #define BYTECOUNTLOOKSBAD \ |
| ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \ |
| (tif->tif_dir.td_compression == COMPRESSION_NONE && \ |
| (tif->tif_dir.td_stripoffset[0] <= TIFFGetFileSize(tif) && \ |
| tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0])) || \ |
| (tif->tif_mode == O_RDONLY && \ |
| tif->tif_dir.td_compression == COMPRESSION_NONE && \ |
| tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) ) |
| |
| } else if (tif->tif_dir.td_nstrips == 1 |
| && !(tif->tif_flags&TIFF_ISTILED) |
| && _TIFFFillStriles(tif) |
| && tif->tif_dir.td_stripoffset[0] != 0 |
| && BYTECOUNTLOOKSBAD) { |
| /* |
| * 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. |
| */ |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength"); |
| if(EstimateStripByteCounts(tif, dir, dircount) < 0) |
| goto bad; |
| |
| #if !defined(DEFER_STRILE_LOAD) |
| } else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG |
| && tif->tif_dir.td_nstrips > 2 |
| && tif->tif_dir.td_compression == COMPRESSION_NONE |
| && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1] |
| && tif->tif_dir.td_stripbytecount[0] != 0 |
| && tif->tif_dir.td_stripbytecount[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. |
| */ |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength"); |
| if (EstimateStripByteCounts(tif, dir, dircount) < 0) |
| goto bad; |
| #endif /* !defined(DEFER_STRILE_LOAD) */ |
| } |
| } |
| if (dir) |
| { |
| _TIFFfree(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)((1L<<tif->tif_dir.td_bitspersample)-1); |
| } |
| /* |
| * 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 !defined(DEFER_STRILE_LOAD) |
| if (tif->tif_dir.td_nstrips > 1) { |
| uint32 strip; |
| |
| tif->tif_dir.td_stripbytecountsorted = 1; |
| for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { |
| if (tif->tif_dir.td_stripoffset[strip - 1] > |
| tif->tif_dir.td_stripoffset[strip]) { |
| tif->tif_dir.td_stripbytecountsorted = 0; |
| break; |
| } |
| } |
| } |
| #endif /* !defined(DEFER_STRILE_LOAD) */ |
| |
| /* |
| * 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)) |
| { |
| if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount ) |
| return 0; |
| ChopUpSingleUncompressedStrip(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) -1; |
| tif->tif_curstrip = (uint32) -1; |
| tif->tif_col = (uint32) -1; |
| tif->tif_curtile = (uint32) -1; |
| tif->tif_tilesize = (tmsize_t) -1; |
| |
| tif->tif_scanlinesize = TIFFScanlineSize(tif); |
| if (!tif->tif_scanlinesize) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle zero scanline size"); |
| return (0); |
| } |
| |
| if (isTiled(tif)) { |
| tif->tif_tilesize = TIFFTileSize(tif); |
| if (!tif->tif_tilesize) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle zero tile size"); |
| return (0); |
| } |
| } else { |
| if (!TIFFStripSize(tif)) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot handle zero strip size"); |
| return (0); |
| } |
| } |
| return (1); |
| bad: |
| if (dir) |
| _TIFFfree(dir); |
| return (0); |
| } |
| |
| static void |
| TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) |
| { |
| static const char module[] = "TIFFReadDirectoryCheckOrder"; |
| uint16 m; |
| uint16 n; |
| TIFFDirEntry* o; |
| m=0; |
| for (n=0, o=dir; n<dircount; n++, o++) |
| { |
| if (o->tdir_tag<m) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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 dircount, uint16 tagid) |
| { |
| TIFFDirEntry* m; |
| uint16 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 tagid, uint32* fii) |
| { |
| int32 ma,mb,mc; |
| ma=-1; |
| mc=(int32)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)tagid) |
| break; |
| if (tif->tif_fields[mb]->field_tag<(uint32)tagid) |
| ma=mb; |
| else |
| mc=mb; |
| } |
| while (1) |
| { |
| if (mb==0) |
| break; |
| if (tif->tif_fields[mb-1]->field_tag!=(uint32)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 dircount; |
| TIFFDirEntry* dp; |
| uint16 di; |
| const TIFFField* fip; |
| uint32 fii; |
| _TIFFSetupFields(tif, infoarray); |
| dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL); |
| if (!dircount) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module, |
| "Failed to read custom directory at offset " TIFF_UINT64_FORMAT,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) |
| { |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Unknown field with tag %d (0x%x) encountered", |
| dp->tdir_tag, dp->tdir_tag); |
| if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif, |
| dp->tdir_tag, |
| (TIFFDataType) dp->tdir_type), |
| 1)) { |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Registering anonymous field with tag %d (0x%x) failed", |
| dp->tdir_tag, dp->tdir_tag); |
| dp->tdir_tag=IGNORE; |
| } else { |
| TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
| assert( fii != FAILED_FII ); |
| } |
| } |
| if (dp->tdir_tag!=IGNORE) |
| { |
| fip=tif->tif_fields[fii]; |
| if (fip->field_bit==FIELD_IGNORE) |
| dp->tdir_tag=IGNORE; |
| 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)dp->tdir_tag)) |
| { |
| fii=0xFFFF; |
| break; |
| } |
| fip=tif->tif_fields[fii]; |
| } |
| if (fii==0xFFFF) |
| { |
| TIFFWarningExt(tif->tif_clientdata, module, |
| "Wrong data type %d for \"%s\"; tag ignored", |
| dp->tdir_type,fip->field_name); |
| dp->tdir_tag=IGNORE; |
| } |
| else |
| { |
| /* check count if known in advance */ |
| if ((fip->field_readcount!=TIFF_VARIABLE)&& |
| (fip->field_readcount!=TIFF_VARIABLE2)) |
| { |
| uint32 expected; |
| if (fip->field_readcount==TIFF_SPP) |
| expected=(uint32)tif->tif_dir.td_samplesperpixel; |
| else |
| expected=(uint32)fip->field_readcount; |
| if (!CheckDirCount(tif,dp,expected)) |
| dp->tdir_tag=IGNORE; |
| } |
| } |
| } |
| switch (dp->tdir_tag) |
| { |
| case IGNORE: |
| break; |
| case EXIFTAG_SUBJECTDISTANCE: |
| (void) TIFFFetchSubjectDistance(tif,dp); |
| break; |
| default: |
| (void) TIFFFetchNormalTag(tif, dp, TRUE); |
| break; |
| } |
| } |
| } |
| if (dir) |
| _TIFFfree(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); |
| } |
| |
| static int |
| EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) |
| { |
| static const char module[] = "EstimateStripByteCounts"; |
| |
| TIFFDirEntry *dp; |
| TIFFDirectory *td = &tif->tif_dir; |
| uint32 strip; |
| |
| /* Do not try to load stripbytecount as we will compute it */ |
| if( !_TIFFFillStrilesInternal( tif, 0 ) ) |
| return -1; |
| |
| if (td->td_stripbytecount) |
| _TIFFfree(td->td_stripbytecount); |
| td->td_stripbytecount = (uint64*) |
| _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64), |
| "for \"StripByteCounts\" array"); |
| if( td->td_stripbytecount == NULL ) |
| return -1; |
| |
| if (td->td_compression != COMPRESSION_NONE) { |
| uint64 space; |
| uint64 filesize; |
| uint16 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 typewidth; |
| uint64 datasize; |
| typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type); |
| if (typewidth == 0) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Cannot determine size of unknown tag type %d", |
| dp->tdir_type); |
| return -1; |
| } |
| datasize=(uint64)typewidth*dp->tdir_count; |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| if (datasize<=4) |
| datasize=0; |
| } |
| else |
| { |
| if (datasize<=8) |
| datasize=0; |
| } |
| 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[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[strip]+td->td_stripbytecount[strip] > filesize) |
| td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip]; |
| } else if (isTiled(tif)) { |
| uint64 bytespertile = TIFFTileSize64(tif); |
| |
| for (strip = 0; strip < td->td_nstrips; strip++) |
| td->td_stripbytecount[strip] = bytespertile; |
| } else { |
| uint64 rowbytes = TIFFScanlineSize64(tif); |
| uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; |
| for (strip = 0; strip < td->td_nstrips; strip++) |
| td->td_stripbytecount[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"; |
| |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "TIFF directory is missing required \"%s\" field", |
| tagname); |
| } |
| |
| /* |
| * Check the directory offset against the list of already seen directory |
| * 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 against that list. |
| */ |
| static int |
| TIFFCheckDirOffset(TIFF* tif, uint64 diroff) |
| { |
| uint16 n; |
| |
| if (diroff == 0) /* no more directories */ |
| return 0; |
| if (tif->tif_dirnumber == 65535) { |
| TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset", |
| "Cannot handle more than 65535 TIFF directories"); |
| return 0; |
| } |
| |
| for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { |
| if (tif->tif_dirlist[n] == diroff) |
| return 0; |
| } |
| |
| tif->tif_dirnumber++; |
| |
| if (tif->tif_dirlist == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) { |
| uint64* new_dirlist; |
| |
| /* |
| * XXX: Reduce memory allocation granularity of the dirlist |
| * array. |
| */ |
| new_dirlist = (uint64*)_TIFFCheckRealloc(tif, tif->tif_dirlist, |
| tif->tif_dirnumber, 2 * sizeof(uint64), "for IFD list"); |
| if (!new_dirlist) |
| return 0; |
| if( tif->tif_dirnumber >= 32768 ) |
| tif->tif_dirlistsize = 65535; |
| else |
| tif->tif_dirlistsize = 2 * tif->tif_dirnumber; |
| tif->tif_dirlist = new_dirlist; |
| } |
| |
| tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff; |
| |
| return 1; |
| } |
| |
| /* |
| * 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 count) |
| { |
| if ((uint64)count > dir->tdir_count) { |
| const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); |
| TIFFWarningExt(tif->tif_clientdata, tif->tif_name, |
| "incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag ignored", |
| fip ? fip->field_name : "unknown tagname", |
| dir->tdir_count, count); |
| return (0); |
| } else if ((uint64)count < dir->tdir_count) { |
| const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); |
| TIFFWarningExt(tif->tif_clientdata, tif->tif_name, |
| "incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); 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 |
| TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, |
| uint64 *nextdiroff) |
| { |
| static const char module[] = "TIFFFetchDirectory"; |
| |
| void* origdir; |
| uint16 dircount16; |
| uint32 dirsize; |
| TIFFDirEntry* dir; |
| uint8* ma; |
| TIFFDirEntry* mb; |
| uint16 n; |
| |
| assert(pdir); |
| |
| tif->tif_diroff = diroff; |
| if (nextdiroff) |
| *nextdiroff = 0; |
| if (!isMapped(tif)) { |
| if (!SeekOK(tif, tif->tif_diroff)) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "%s: Seek error accessing TIFF directory", |
| tif->tif_name); |
| return 0; |
| } |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| if (!ReadOK(tif, &dircount16, sizeof (uint16))) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "%s: Can not read TIFF directory count", |
| tif->tif_name); |
| return 0; |
| } |
| if (tif->tif_flags & TIFF_SWAB) |
| TIFFSwabShort(&dircount16); |
| if (dircount16>4096) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Sanity check on directory count failed, this is probably not a valid IFD offset"); |
| return 0; |
| } |
| dirsize = 12; |
| } else { |
| uint64 dircount64; |
| if (!ReadOK(tif, &dircount64, sizeof (uint64))) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "%s: Can not read TIFF directory count", |
| tif->tif_name); |
| return 0; |
| } |
| if (tif->tif_flags & TIFF_SWAB) |
| TIFFSwabLong8(&dircount64); |
| if (dircount64>4096) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Sanity check on directory count failed, this is probably not a valid IFD offset"); |
| return 0; |
| } |
| dircount16 = (uint16)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))) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "%.100s: Can not read TIFF directory", |
| tif->tif_name); |
| _TIFFfree(origdir); |
| return 0; |
| } |
| /* |
| * Read offset to next directory for sequential scans if |
| * needed. |
| */ |
| if (nextdiroff) |
| { |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| uint32 nextdiroff32; |
| if (!ReadOK(tif, &nextdiroff32, sizeof(uint32))) |
| nextdiroff32 = 0; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(&nextdiroff32); |
| *nextdiroff=nextdiroff32; |
| } else { |
| if (!ReadOK(tif, nextdiroff, sizeof(uint64))) |
| *nextdiroff = 0; |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8(nextdiroff); |
| } |
| } |
| } else { |
| tmsize_t m; |
| tmsize_t off = (tmsize_t) tif->tif_diroff; |
| if ((uint64)off!=tif->tif_diroff) |
| { |
| TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count"); |
| return(0); |
| } |
| |
| /* |
| * 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) > tif->tif_size |
| * |
| * to avoid overflow. |
| */ |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| m=off+sizeof(uint16); |
| if ((m<off)||(m<(tmsize_t)sizeof(uint16))||(m>tif->tif_size)) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Can not read TIFF directory count"); |
| return 0; |
| } else { |
| _TIFFmemcpy(&dircount16, tif->tif_base + off, |
| sizeof(uint16)); |
| } |
| off += sizeof (uint16); |
| if (tif->tif_flags & TIFF_SWAB) |
| TIFFSwabShort(&dircount16); |
| if (dircount16>4096) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Sanity check on directory count failed, this is probably not a valid IFD offset"); |
| return 0; |
| } |
| dirsize = 12; |
| } |
| else |
| { |
| uint64 dircount64; |
| m=off+sizeof(uint64); |
| if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size)) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Can not read TIFF directory count"); |
| return 0; |
| } else { |
| _TIFFmemcpy(&dircount64, tif->tif_base + off, |
| sizeof(uint64)); |
| } |
| off += sizeof (uint64); |
| if (tif->tif_flags & TIFF_SWAB) |
| TIFFSwabLong8(&dircount64); |
| if (dircount64>4096) |
| { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Sanity check on directory count failed, this is probably not a valid IFD offset"); |
| return 0; |
| } |
| dircount16 = (uint16)dircount64; |
| dirsize = 20; |
| } |
| if (dircount16 == 0 ) |
| { |
| TIFFErrorExt(tif->tif_clientdata, 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)) { |
| TIFFErrorExt(tif->tif_clientdata, module, |
| "Can not read TIFF directory"); |
| _TIFFfree(origdir); |
| return 0; |
| } else { |
| _TIFFmemcpy(origdir, tif->tif_base + off, |
| dircount16 * dirsize); |
| } |
| if (nextdiroff) { |
| off += dircount16 * dirsize; |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| uint32 nextdiroff32; |
| m=off+sizeof(uint32); |
| if ((m<off)||(m<(tmsize_t)sizeof(uint32))||(m>tif->tif_size)) |
| nextdiroff32 = 0; |
| else |
| _TIFFmemcpy(&nextdiroff32, tif->tif_base + off, |
| sizeof (uint32)); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong(&nextdiroff32); |
| *nextdiroff = nextdiroff32; |
| } |
| else |
| { |
| m=off+sizeof(uint64); |
| if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size)) |
| *nextdiroff = 0; |
| else |
| _TIFFmemcpy(nextdiroff, tif->tif_base + off, |
| sizeof (uint64)); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8(nextdiroff); |
| } |
| } |
| } |
| dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16, |
| sizeof(TIFFDirEntry), |
| "to read TIFF directory"); |
| if (dir==0) |
| { |
| _TIFFfree(origdir); |
| return 0; |
| } |
| ma=(uint8*)origdir; |
| mb=dir; |
| for (n=0; n<dircount16; n++) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| mb->tdir_tag=*(uint16*)ma; |
| ma+=sizeof(uint16); |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabShort((uint16*)ma); |
| mb->tdir_type=*(uint16*)ma; |
| ma+=sizeof(uint16); |
| if (!(tif->tif_flags&TIFF_BIGTIFF)) |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong((uint32*)ma); |
| mb->tdir_count=(uint64)(*(uint32*)ma); |
| ma+=sizeof(uint32); |
| *(uint32*)(&mb->tdir_offset)=*(uint32*)ma; |
| ma+=sizeof(uint32); |
| } |
| else |
| { |
| if (tif->tif_flags&TIFF_SWAB) |
| TIFFSwabLong8((uint64*)ma); |
| mb->tdir_count=TIFFReadUInt64(ma); |
| ma+=sizeof(uint64); |
| mb->tdir_offset.toff_long8=TIFFReadUInt64(ma); |
| ma+=sizeof(uint64); |
| } |
| mb++; |
| } |
| _TIFFfree(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 fii; |
| const TIFFField* fip = NULL; |
| TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
| if( fii == FAILED_FII ) |
| { |
| TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag", |
| "No definition found for tag %d", |
| 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: |
| break; |
| case TIFF_SETGET_ASCII: |
| { |
| uint8* data; |
| assert(fip->field_passcount==0); |
| err=TIFFReadDirEntryByteArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| uint8* ma; |
| uint32 mb; |
| int n; |
| ma=data; |
| mb=0; |
| while (mb<(uint32)dp->tdir_count) |
| { |
| if (*ma==0) |
| break; |
| ma++; |
| mb++; |
| } |
| if (mb+1<(uint32)dp->tdir_count) |
| TIFFWarningExt(tif->tif_clientdata,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)dp->tdir_count) |
| { |
| uint8* o; |
| TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name); |
| if ((uint32)dp->tdir_count+1!=dp->tdir_count+1) |
| o=NULL; |
| else |
| o=_TIFFmalloc((uint32)dp->tdir_count+1); |
| if (o==NULL) |
| { |
| if (data!=NULL) |
| _TIFFfree(data); |
| return(0); |
| } |
| _TIFFmemcpy(o,data,(uint32)dp->tdir_count); |
| o[(uint32)dp->tdir_count]=0; |
| if (data!=0) |
| _TIFFfree(data); |
| data=o; |
| } |
| n=TIFFSetField(tif,dp->tdir_tag,data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!n) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_UINT8: |
| { |
| uint8 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_UINT16: |
| { |
| uint16 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_UINT32: |
| { |
| uint32 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_UINT64: |
| { |
| uint64 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_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 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* data; |
| assert(fip->field_readcount==2); |
| assert(fip->field_passcount==0); |
| if (dp->tdir_count!=2) { |
| TIFFWarningExt(tif->tif_clientdata,module, |
| "incorrect count for field \"%s\", expected 2, got %d", |
| fip->field_name,(int)dp->tdir_count); |
| return(0); |
| } |
| err=TIFFReadDirEntryShortArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]); |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C0_UINT8: |
| { |
| uint8* data; |
| assert(fip->field_readcount>=1); |
| assert(fip->field_passcount==0); |
| if (dp->tdir_count!=(uint64)fip->field_readcount) { |
| TIFFWarningExt(tif->tif_clientdata,module, |
| "incorrect count for field \"%s\", expected %d, got %d", |
| fip->field_name,(int) fip->field_readcount, (int)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) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C0_UINT16: |
| { |
| uint16* data; |
| assert(fip->field_readcount>=1); |
| assert(fip->field_passcount==0); |
| if (dp->tdir_count!=(uint64)fip->field_readcount) |
| /* corrupt file */; |
| else |
| { |
| err=TIFFReadDirEntryShortArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| m=TIFFSetField(tif,dp->tdir_tag,data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C0_UINT32: |
| { |
| uint32* data; |
| assert(fip->field_readcount>=1); |
| assert(fip->field_passcount==0); |
| if (dp->tdir_count!=(uint64)fip->field_readcount) |
| /* corrupt file */; |
| else |
| { |
| err=TIFFReadDirEntryLongArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| m=TIFFSetField(tif,dp->tdir_tag,data); |
| if (data!=0) |
| _TIFFfree(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)fip->field_readcount) |
| /* corrupt file */; |
| else |
| { |
| err=TIFFReadDirEntryFloatArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| m=TIFFSetField(tif,dp->tdir_tag,data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_ASCII: |
| { |
| uint8* 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( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' ) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_UINT8: |
| { |
| uint8* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_UINT16: |
| { |
| uint16* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_UINT32: |
| { |
| uint32* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_UINT64: |
| { |
| uint64* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C16_IFD8: |
| { |
| uint64* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_ASCII: |
| { |
| uint8* data; |
| assert(fip->field_readcount==TIFF_VARIABLE2); |
| assert(fip->field_passcount==1); |
| err=TIFFReadDirEntryByteArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| if( dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' ) |
| { |
| TIFFWarningExt(tif->tif_clientdata,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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_UINT8: |
| { |
| uint8* data; |
| assert(fip->field_readcount==TIFF_VARIABLE2); |
| assert(fip->field_passcount==1); |
| err=TIFFReadDirEntryByteArray(tif,dp,&data); |
| if (err==TIFFReadDirEntryErrOk) |
| { |
| int m; |
| m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_SINT8: |
| { |
| int8* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_UINT16: |
| { |
| uint16* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_SINT16: |
| { |
| int16* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_UINT32: |
| { |
| uint32* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_SINT32: |
| { |
| int32* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_UINT64: |
| { |
| uint64* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_SINT64: |
| { |
| int64* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(data); |
| if (!m) |
| return(0); |
| } |
| } |
| break; |
| case TIFF_SETGET_C32_IFD8: |
| { |
| uint64* 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)(dp->tdir_count),data); |
| if (data!=0) |
| _TIFFfree(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 nstrips, uint64** lpp) |
| { |
| static const char module[] = "TIFFFetchStripThing"; |
| enum TIFFReadDirEntryErr err; |
| uint64* 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)nstrips) |
| { |
| uint64* resizeddata; |
| const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); |
| const char* pszMax = getenv("LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT"); |
| uint32 max_nstrips = 1000000; |
| if( pszMax ) |
| max_nstrips = (uint32) atoi(pszMax); |
| TIFFReadDirEntryOutputErr(tif,TIFFReadDirEntryErrCount, |
| module, |
| fip ? fip->field_name : "unknown tagname", |
| ( nstrips <= max_nstrips ) ); |
| |
| if( nstrips > max_nstrips ) |
| { |
| _TIFFfree(data); |
| return(0); |
| } |
| |
| resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array"); |
| if (resizeddata==0) { |
| _TIFFfree(data); |
| return(0); |
| } |
| _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64)); |
| _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64)); |
| _TIFFfree(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)==8); |
| assert(sizeof(uint32)==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 offset; |
| offset=*(uint32*)(&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) |
| /* |
| * 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); |
| } |
| } |
| |
| /* |
| * 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 bytecount; |
| uint64 offset; |
| uint32 rowblock; |
| uint64 rowblockbytes; |
| uint64 stripbytes; |
| uint32 strip; |
| uint32 nstrips; |
| uint32 rowsperstrip; |
| uint64* newcounts; |
| uint64* newoffsets; |
| |
| bytecount = td->td_stripbytecount[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 = td->td_stripoffset[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 rowblocksperstrip; |
| rowblocksperstrip = (uint32) (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; |
| |
| newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64), |
| "for chopped \"StripByteCounts\" array"); |
| newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64), |
| "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) |
| _TIFFfree(newcounts); |
| if (newoffsets != NULL) |
| _TIFFfree(newoffsets); |
| return; |
| } |
| /* |
| * Fill the strip information arrays with new bytecounts and offsets |
| * that reflect the broken-up format. |
| */ |
| for (strip = 0; strip < nstrips; strip++) { |
| if (stripbytes > bytecount) |
| stripbytes = bytecount; |
| newcounts[strip] = stripbytes; |
| newoffsets[strip] = 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); |
| |
| _TIFFfree(td->td_stripbytecount); |
| _TIFFfree(td->td_stripoffset); |
| td->td_stripbytecount = newcounts; |
| td->td_stripoffset = newoffsets; |
| td->td_stripbytecountsorted = 1; |
| } |
| |
| int _TIFFFillStriles( TIFF *tif ) |
| { |
| return _TIFFFillStrilesInternal( tif, 1 ); |
| } |
| |
| static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ) |
| { |
| #if defined(DEFER_STRILE_LOAD) |
| register TIFFDirectory *td = &tif->tif_dir; |
| int return_value = 1; |
| |
| if( td->td_stripoffset != NULL ) |
| return 1; |
| |
| if( td->td_stripoffset_entry.tdir_count == 0 ) |
| return 0; |
| |
| if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry), |
| td->td_nstrips,&td->td_stripoffset)) |
| { |
| return_value = 0; |
| } |
| |
| if (loadStripByteCount && |
| !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry), |
| td->td_nstrips,&td->td_stripbytecount)) |
| { |
| return_value = 0; |
| } |
| |
| _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); |
| _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); |
| |
| if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) { |
| uint32 strip; |
| |
| tif->tif_dir.td_stripbytecountsorted = 1; |
| for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { |
| if (tif->tif_dir.td_stripoffset[strip - 1] > |
| tif->tif_dir.td_stripoffset[strip]) { |
| tif->tif_dir.td_stripbytecountsorted = 0; |
| break; |
| } |
| } |
| } |
| |
| return return_value; |
| #else /* !defined(DEFER_STRILE_LOAD) */ |
| (void) tif; |
| (void) loadStripByteCount; |
| return 1; |
| #endif |
| } |
| |
| |
| /* vim: set ts=8 sts=8 sw=8 noet: */ |
| /* |
| * Local Variables: |
| * mode: c |
| * c-basic-offset: 8 |
| * fill-column: 78 |
| * End: |
| */ |