mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6495 lines
169 KiB
6495 lines
169 KiB
/* |
|
* Copyright (c) 1988-1997 Sam Leffler |
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc. |
|
* |
|
* Permission to use, copy, modify, distribute, and sell this software and |
|
* its documentation for any purpose is hereby granted without fee, provided |
|
* that (i) the above copyright notices and this permission notice appear in |
|
* all copies of the software and related documentation, and (ii) the names of |
|
* Sam Leffler and Silicon Graphics may not be used in any advertising or |
|
* publicity relating to the software without the specific, prior written |
|
* permission of Sam Leffler and Silicon Graphics. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
|
* |
|
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR |
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
|
* OF THIS SOFTWARE. |
|
*/ |
|
|
|
/* |
|
* TIFF Library. |
|
* |
|
* Directory Read Support Routines. |
|
*/ |
|
|
|
/* Suggested pending improvements: |
|
* - add a field 'field_info' to the TIFFDirEntry structure, and set that with |
|
* the pointer to the appropriate TIFFField structure early on in |
|
* TIFFReadDirectory, so as to eliminate current possibly repetitive lookup. |
|
*/ |
|
|
|
#include "tiffiop.h" |
|
#include <float.h> |
|
#include <stdlib.h> |
|
|
|
#define FAILED_FII ((uint32) -1) |
|
|
|
/* |
|
* Largest 64-bit signed integer value. |
|
*/ |
|
#define TIFF_INT64_MAX ((int64)(TIFF_UINT64_MAX >> 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 void TryChopUpUncompressedBigTiff(TIFF*); |
|
static uint64 TIFFReadUInt64(const uint8 *value); |
|
static int _TIFFGetMaxColorChannels(uint16 photometric); |
|
|
|
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: |
|
case TIFF_UNDEFINED: /* Support to read TIFF_UNDEFINED with field_readcount==1 */ |
|
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_MAX)) |
|
return(TIFFReadDirEntryErrRange); |
|
*value=(float)m; |
|
return(TIFFReadDirEntryErrOk); |
|
} |
|
default: |
|
return(TIFFReadDirEntryErrType); |
|
} |
|
} |
|
|
|
static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) |
|
{ |
|
enum TIFFReadDirEntryErr err; |
|
if (direntry->tdir_count!=1) |
|
return(TIFFReadDirEntryErrCount); |
|
switch (direntry->tdir_type) |
|
{ |
|
case TIFF_BYTE: |
|
{ |
|
uint8 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_SIZE_T == 8 |
|
tmsize_t threshold = INITIAL_THRESHOLD; |
|
#endif |
|
tmsize_t already_read = 0; |
|
|
|
assert( !isMapped(tif) ); |
|
|
|
if (!SeekOK(tif,offset)) |
|
return(TIFFReadDirEntryErrIo); |
|
|
|
/* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */ |
|
/* so as to avoid allocating too much memory in case the file is too */ |
|
/* short. We could ask for the file size, but this might be */ |
|
/* expensive with some I/O layers (think of reading a gzipped file) */ |
|
/* Restrict to 64 bit processes, so as to avoid reallocs() */ |
|
/* on 32 bit processes where virtual memory is scarce. */ |
|
while( already_read < size ) |
|
{ |
|
void* new_dest; |
|
tmsize_t bytes_read; |
|
tmsize_t to_read = size - already_read; |
|
#if SIZEOF_SIZE_T == 8 |
|
if( to_read >= threshold && threshold < MAX_THRESHOLD ) |
|
{ |
|
to_read = threshold; |
|
threshold *= THRESHOLD_MULTIPLIER; |
|
} |
|
#endif |
|
|
|
new_dest = (uint8*) _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; |
|
int original_datasize_clamped; |
|
typesize=TIFFDataWidth(direntry->tdir_type); |
|
|
|
target_count64 = (direntry->tdir_count > maxcount) ? |
|
maxcount : direntry->tdir_count; |
|
|
|
if ((target_count64==0)||(typesize==0)) |
|
{ |
|
*value=0; |
|
return(TIFFReadDirEntryErrOk); |
|
} |
|
(void) desttypesize; |
|
|
|
/* We just want to know if the original tag size is more than 4 bytes |
|
* (classic TIFF) or 8 bytes (BigTIFF) |
|
*/ |
|
original_datasize_clamped = |
|
((direntry->tdir_count > 10) ? 10 : (int)direntry->tdir_count) * typesize; |
|
|
|
/* |
|
* As a sanity check, make sure we have no more than a 2GB tag array |
|
* in either the current data type or the dest data type. This also |
|
* avoids problems with overflow of tmsize_t on 32bit systems. |
|
*/ |
|
if ((uint64)(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 > (uint64)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 (original_datasize_clamped<=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 (original_datasize_clamped<=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); |
|
} |
|
|
|
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); |
|
} |
|
|
|
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); |
|
} |
|
|
|
static enum TIFFReadDirEntryErr |
|
TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value) |
|
{ |
|
if (value > TIFF_INT64_MAX) |
|
return(TIFFReadDirEntryErrRange); |
|
else |
|
return(TIFFReadDirEntryErrOk); |
|
} |
|
|
|
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; |
|
if( (uint64)ma!=offset || |
|
ma > (~(size_t)0) - (size_t)size ) |
|
{ |
|
return TIFFReadDirEntryErrIo; |
|
} |
|
mb=ma+size; |
|
if (mb > (uint64)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; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* Return the maximum number of color channels specified for a given photometric |
|
* type. 0 is returned if photometric type isn't supported or no default value |
|
* is defined by the specification. |
|
*/ |
|
static int _TIFFGetMaxColorChannels( uint16 photometric ) |
|
{ |
|
switch (photometric) { |
|
case PHOTOMETRIC_PALETTE: |
|
case PHOTOMETRIC_MINISWHITE: |
|
case PHOTOMETRIC_MINISBLACK: |
|
return 1; |
|
case PHOTOMETRIC_YCBCR: |
|
case PHOTOMETRIC_RGB: |
|
case PHOTOMETRIC_CIELAB: |
|
case PHOTOMETRIC_LOGLUV: |
|
case PHOTOMETRIC_ITULAB: |
|
case PHOTOMETRIC_ICCLAB: |
|
return 3; |
|
case PHOTOMETRIC_SEPARATED: |
|
case PHOTOMETRIC_MASK: |
|
return 4; |
|
case PHOTOMETRIC_LOGL: |
|
case PHOTOMETRIC_CFA: |
|
default: |
|
return 0; |
|
} |
|
} |
|
|
|
static int ByteCountLooksBad(TIFF* tif) |
|
{ |
|
/* |
|
* Assume we have wrong StripByteCount value (in case |
|
* of single strip) in following cases: |
|
* - it is equal to zero along with StripOffset; |
|
* - it is larger than file itself (in case of uncompressed |
|
* image); |
|
* - it is smaller than the size of the bytes per row |
|
* multiplied on the number of rows. The last case should |
|
* not be checked in the case of writing new image, |
|
* because we may do not know the exact strip size |
|
* until the whole image will be written and directory |
|
* dumped out. |
|
*/ |
|
uint64 bytecount = TIFFGetStrileByteCount(tif, 0); |
|
uint64 offset = TIFFGetStrileOffset(tif, 0); |
|
uint64 filesize; |
|
|
|
if( offset == 0 ) |
|
return 0; |
|
if (bytecount == 0) |
|
return 1; |
|
if ( tif->tif_dir.td_compression != COMPRESSION_NONE ) |
|
return 0; |
|
filesize = TIFFGetFileSize(tif); |
|
if( offset <= filesize && bytecount > filesize - offset ) |
|
return 1; |
|
if( tif->tif_mode == O_RDONLY ) |
|
{ |
|
uint64 scanlinesize = TIFFScanlineSize64(tif); |
|
if( tif->tif_dir.td_imagelength > 0 && |
|
scanlinesize > TIFF_UINT64_MAX / tif->tif_dir.td_imagelength ) |
|
{ |
|
return 1; |
|
} |
|
if( bytecount < scanlinesize * tif->tif_dir.td_imagelength) |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
/* |
|
* Read the next TIFF directory from a file and convert it to the internal |
|
* format. We read directories sequentially. |
|
*/ |
|
int |
|
TIFFReadDirectory(TIFF* tif) |
|
{ |
|
static const char module[] = "TIFFReadDirectory"; |
|
TIFFDirEntry* dir; |
|
uint16 dircount; |
|
TIFFDirEntry* dp; |
|
uint16 di; |
|
const TIFFField* fip; |
|
uint32 fii=FAILED_FII; |
|
toff_t nextdiroff; |
|
int bitspersample_read = FALSE; |
|
int color_channels; |
|
|
|
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_ignore = TRUE; |
|
} |
|
} |
|
} |
|
} |
|
|
|
tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ |
|
tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */ |
|
tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS; |
|
|
|
/* free any old stuff and reinit */ |
|
TIFFFreeDirectory(tif); |
|
TIFFDefaultDirectory(tif); |
|
/* |
|
* Electronic Arts writes gray-scale TIFF files |
|
* without a PlanarConfiguration directory entry. |
|
* Thus we setup a default value here, even though |
|
* the TIFF spec says there is no default value. |
|
*/ |
|
TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); |
|
/* |
|
* Setup default value and then make a pass over |
|
* the fields to check type and tag information, |
|
* and to extract info required to size data |
|
* structures. A second pass is made afterwards |
|
* to read in everything not taken in the first pass. |
|
* But we must process the Compression tag first |
|
* in order to merge in codec-private tag definitions (otherwise |
|
* we may get complaints about unknown tags). However, the |
|
* Compression tag may be dependent on the SamplesPerPixel |
|
* tag value because older TIFF specs permitted Compression |
|
* to be written as a SamplesPerPixel-count tag entry. |
|
* Thus if we don't first figure out the correct SamplesPerPixel |
|
* tag value then we may end up ignoring the Compression tag |
|
* value because it has an incorrect count value (if the |
|
* true value of SamplesPerPixel is not 1). |
|
*/ |
|
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL); |
|
if (dp) |
|
{ |
|
if (!TIFFFetchNormalTag(tif,dp,0)) |
|
goto bad; |
|
dp->tdir_ignore = TRUE; |
|
} |
|
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION); |
|
if (dp) |
|
{ |
|
/* |
|
* The 5.0 spec says the Compression tag has one value, while |
|
* earlier specs say it has one value per sample. Because of |
|
* this, we accept the tag if one value is supplied with either |
|
* count. |
|
*/ |
|
uint16 value; |
|
enum TIFFReadDirEntryErr err; |
|
err=TIFFReadDirEntryShort(tif,dp,&value); |
|
if (err==TIFFReadDirEntryErrCount) |
|
err=TIFFReadDirEntryPersampleShort(tif,dp,&value); |
|
if (err!=TIFFReadDirEntryErrOk) |
|
{ |
|
TIFFReadDirEntryOutputErr(tif,err,module,"Compression",0); |
|
goto bad; |
|
} |
|
if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value)) |
|
goto bad; |
|
dp->tdir_ignore = TRUE; |
|
} |
|
else |
|
{ |
|
if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE)) |
|
goto bad; |
|
} |
|
/* |
|
* First real pass over the directory. |
|
*/ |
|
for (di=0, dp=dir; di<dircount; di++, dp++) |
|
{ |
|
if (!dp->tdir_ignore) |
|
{ |
|
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
|
if (fii == FAILED_FII) |
|
{ |
|
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_ignore = TRUE; |
|
} else { |
|
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
|
assert(fii != FAILED_FII); |
|
} |
|
} |
|
} |
|
if (!dp->tdir_ignore) |
|
{ |
|
fip=tif->tif_fields[fii]; |
|
if (fip->field_bit==FIELD_IGNORE) |
|
dp->tdir_ignore = TRUE; |
|
else |
|
{ |
|
switch (dp->tdir_tag) |
|
{ |
|
case TIFFTAG_STRIPOFFSETS: |
|
case TIFFTAG_STRIPBYTECOUNTS: |
|
case TIFFTAG_TILEOFFSETS: |
|
case TIFFTAG_TILEBYTECOUNTS: |
|
TIFFSetFieldBit(tif,fip->field_bit); |
|
break; |
|
case TIFFTAG_IMAGEWIDTH: |
|
case TIFFTAG_IMAGELENGTH: |
|
case TIFFTAG_IMAGEDEPTH: |
|
case TIFFTAG_TILELENGTH: |
|
case TIFFTAG_TILEWIDTH: |
|
case TIFFTAG_TILEDEPTH: |
|
case TIFFTAG_PLANARCONFIG: |
|
case TIFFTAG_ROWSPERSTRIP: |
|
case TIFFTAG_EXTRASAMPLES: |
|
if (!TIFFFetchNormalTag(tif,dp,0)) |
|
goto bad; |
|
dp->tdir_ignore = TRUE; |
|
break; |
|
default: |
|
if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) ) |
|
dp->tdir_ignore = TRUE; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
/* |
|
* XXX: OJPEG hack. |
|
* If a) compression is OJPEG, b) planarconfig tag says it's separate, |
|
* c) strip offsets/bytecounts tag are both present and |
|
* d) both contain exactly one value, then we consistently find |
|
* that the buggy implementation of the buggy compression scheme |
|
* matches contig planarconfig best. So we 'fix-up' the tag here |
|
*/ |
|
if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&& |
|
(tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE)) |
|
{ |
|
if (!_TIFFFillStriles(tif)) |
|
goto bad; |
|
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS); |
|
if ((dp!=0)&&(dp->tdir_count==1)) |
|
{ |
|
dp=TIFFReadDirectoryFindEntry(tif,dir,dircount, |
|
TIFFTAG_STRIPBYTECOUNTS); |
|
if ((dp!=0)&&(dp->tdir_count==1)) |
|
{ |
|
tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG; |
|
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; |
|
} |
|
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++) |
|
{ |
|
if (!dp->tdir_ignore) { |
|
switch (dp->tdir_tag) |
|
{ |
|
case TIFFTAG_MINSAMPLEVALUE: |
|
case TIFFTAG_MAXSAMPLEVALUE: |
|
case TIFFTAG_BITSPERSAMPLE: |
|
case TIFFTAG_DATATYPE: |
|
case TIFFTAG_SAMPLEFORMAT: |
|
/* |
|
* The MinSampleValue, MaxSampleValue, BitsPerSample |
|
* DataType and SampleFormat tags are supposed to be |
|
* written as one value/sample, but some vendors |
|
* incorrectly write one value only -- so we accept |
|
* that as well (yuck). Other vendors write correct |
|
* value for NumberOfSamples, but incorrect one for |
|
* BitsPerSample and friends, and we will read this |
|
* too. |
|
*/ |
|
{ |
|
uint16 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: |
|
switch( dp->tdir_type ) |
|
{ |
|
case TIFF_SHORT: |
|
case TIFF_LONG: |
|
case TIFF_LONG8: |
|
break; |
|
default: |
|
/* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */ |
|
if( !(tif->tif_mode == O_RDWR && |
|
dp->tdir_count == 0 && |
|
dp->tdir_type == 0 && |
|
dp->tdir_offset.toff_long8 == 0) ) |
|
{ |
|
fip = TIFFFieldWithTag(tif,dp->tdir_tag); |
|
TIFFWarningExt(tif->tif_clientdata,module, |
|
"Invalid data type for tag %s", |
|
fip ? fip->field_name : "unknown tagname"); |
|
} |
|
break; |
|
} |
|
_TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry), |
|
dp, sizeof(TIFFDirEntry) ); |
|
break; |
|
case TIFFTAG_STRIPBYTECOUNTS: |
|
case TIFFTAG_TILEBYTECOUNTS: |
|
switch( dp->tdir_type ) |
|
{ |
|
case TIFF_SHORT: |
|
case TIFF_LONG: |
|
case TIFF_LONG8: |
|
break; |
|
default: |
|
/* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */ |
|
if( !(tif->tif_mode == O_RDWR && |
|
dp->tdir_count == 0 && |
|
dp->tdir_type == 0 && |
|
dp->tdir_offset.toff_long8 == 0) ) |
|
{ |
|
fip = TIFFFieldWithTag(tif,dp->tdir_tag); |
|
TIFFWarningExt(tif->tif_clientdata,module, |
|
"Invalid data type for tag %s", |
|
fip ? fip->field_name : "unknown tagname"); |
|
} |
|
break; |
|
} |
|
_TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry), |
|
dp, sizeof(TIFFDirEntry) ); |
|
break; |
|
case TIFFTAG_COLORMAP: |
|
case TIFFTAG_TRANSFERFUNCTION: |
|
{ |
|
enum TIFFReadDirEntryErr err; |
|
uint32 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; |
|
} |
|
} /* -- if (!dp->tdir_ignore) */ |
|
} /* -- for-loop -- */ |
|
|
|
if( tif->tif_mode == O_RDWR && |
|
tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && |
|
tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && |
|
tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && |
|
tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && |
|
tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && |
|
tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && |
|
tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && |
|
tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 ) |
|
{ |
|
/* Directory typically created with TIFFDeferStrileArrayWriting() */ |
|
TIFFSetupStrips(tif); |
|
} |
|
else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) |
|
{ |
|
if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 ) |
|
{ |
|
if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry), |
|
tif->tif_dir.td_nstrips, |
|
&tif->tif_dir.td_stripoffset_p)) |
|
{ |
|
goto bad; |
|
} |
|
} |
|
if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 ) |
|
{ |
|
if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry), |
|
tif->tif_dir.td_nstrips, |
|
&tif->tif_dir.td_stripbytecount_p)) |
|
{ |
|
goto bad; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* 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; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* Make sure all non-color channels are extrasamples. |
|
* If it's not the case, define them as such. |
|
*/ |
|
color_channels = _TIFFGetMaxColorChannels(tif->tif_dir.td_photometric); |
|
if (color_channels && tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples > color_channels) { |
|
uint16 old_extrasamples; |
|
uint16 *new_sampleinfo; |
|
|
|
TIFFWarningExt(tif->tif_clientdata,module, "Sum of Photometric type-related " |
|
"color channels and ExtraSamples doesn't match SamplesPerPixel. " |
|
"Defining non-color channels as ExtraSamples."); |
|
|
|
old_extrasamples = tif->tif_dir.td_extrasamples; |
|
tif->tif_dir.td_extrasamples = (uint16) (tif->tif_dir.td_samplesperpixel - color_channels); |
|
|
|
// sampleinfo should contain information relative to these new extra samples |
|
new_sampleinfo = (uint16*) _TIFFcalloc(tif->tif_dir.td_extrasamples, sizeof(uint16)); |
|
if (!new_sampleinfo) { |
|
TIFFErrorExt(tif->tif_clientdata, module, "Failed to allocate memory for " |
|
"temporary new sampleinfo array (%d 16 bit elements)", |
|
tif->tif_dir.td_extrasamples); |
|
goto bad; |
|
} |
|
|
|
memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, old_extrasamples * sizeof(uint16)); |
|
_TIFFsetShortArray(&tif->tif_dir.td_sampleinfo, new_sampleinfo, tif->tif_dir.td_extrasamples); |
|
_TIFFfree(new_sampleinfo); |
|
} |
|
|
|
/* |
|
* Verify Palette image has a Colormap. |
|
*/ |
|
if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE && |
|
!TIFFFieldSet(tif, FIELD_COLORMAP)) { |
|
if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3) |
|
tif->tif_dir.td_photometric = PHOTOMETRIC_RGB; |
|
else if (tif->tif_dir.td_bitspersample>=8) |
|
tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK; |
|
else { |
|
MissingRequired(tif, "Colormap"); |
|
goto bad; |
|
} |
|
} |
|
/* |
|
* OJPEG hack: |
|
* We do no further messing with strip/tile offsets/bytecounts in OJPEG |
|
* TIFFs |
|
*/ |
|
if (tif->tif_dir.td_compression!=COMPRESSION_OJPEG) |
|
{ |
|
/* |
|
* Attempt to deal with a missing StripByteCounts tag. |
|
*/ |
|
if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { |
|
/* |
|
* Some manufacturers violate the spec by not giving |
|
* the size of the strips. In this case, assume there |
|
* is one uncompressed strip of data. |
|
*/ |
|
if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && |
|
tif->tif_dir.td_nstrips > 1) || |
|
(tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE && |
|
tif->tif_dir.td_nstrips != (uint32)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; |
|
|
|
} else if (tif->tif_dir.td_nstrips == 1 |
|
&& !(tif->tif_flags&TIFF_ISTILED) |
|
&& ByteCountLooksBad(tif)) { |
|
/* |
|
* XXX: Plexus (and others) sometimes give a value of |
|
* zero for a tag when they don't know what the |
|
* correct value is! Try and handle the simple case |
|
* of estimating the size of a one strip image. |
|
*/ |
|
TIFFWarningExt(tif->tif_clientdata, module, |
|
"Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength"); |
|
if(EstimateStripByteCounts(tif, dir, dircount) < 0) |
|
goto bad; |
|
|
|
} else if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) |
|
&& tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG |
|
&& tif->tif_dir.td_nstrips > 2 |
|
&& tif->tif_dir.td_compression == COMPRESSION_NONE |
|
&& TIFFGetStrileByteCount(tif, 0) != TIFFGetStrileByteCount(tif, 1) |
|
&& TIFFGetStrileByteCount(tif, 0) != 0 |
|
&& TIFFGetStrileByteCount(tif, 1) != 0 ) { |
|
/* |
|
* XXX: Some vendors fill StripByteCount array with |
|
* absolutely wrong values (it can be equal to |
|
* StripOffset array, for example). Catch this case |
|
* here. |
|
* |
|
* We avoid this check if deferring strile loading |
|
* as it would always force us to load the strip/tile |
|
* information. |
|
*/ |
|
TIFFWarningExt(tif->tif_clientdata, module, |
|
"Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength"); |
|
if (EstimateStripByteCounts(tif, dir, dircount) < 0) |
|
goto bad; |
|
} |
|
} |
|
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); |
|
} |
|
|
|
#ifdef STRIPBYTECOUNTSORTED_UNUSED |
|
/* |
|
* XXX: We can optimize checking for the strip bounds using the sorted |
|
* bytecounts array. See also comments for TIFFAppendToStrip() |
|
* function in tif_write.c. |
|
*/ |
|
if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) && tif->tif_dir.td_nstrips > 1) { |
|
uint32 strip; |
|
|
|
tif->tif_dir.td_stripbytecountsorted = 1; |
|
for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { |
|
if (TIFFGetStrileOffset(tif, strip - 1) > |
|
TIFFGetStrileOffset(tif, strip)) { |
|
tif->tif_dir.td_stripbytecountsorted = 0; |
|
break; |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
/* |
|
* An opportunity for compression mode dependent tag fixup |
|
*/ |
|
(*tif->tif_fixuptags)(tif); |
|
|
|
/* |
|
* Some manufacturers make life difficult by writing |
|
* large amounts of uncompressed data as a single strip. |
|
* This is contrary to the recommendations of the spec. |
|
* The following makes an attempt at breaking such images |
|
* into strips closer to the recommended 8k bytes. A |
|
* side effect, however, is that the RowsPerStrip tag |
|
* value may be changed. |
|
*/ |
|
if ((tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&& |
|
(tif->tif_dir.td_nstrips==1)&& |
|
(tif->tif_dir.td_compression==COMPRESSION_NONE)&& |
|
((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP)) |
|
{ |
|
ChopUpSingleUncompressedStrip(tif); |
|
} |
|
|
|
/* There are also uncompressed striped files with strips larger than */ |
|
/* 2 GB, which make them unfriendly with a lot of code. If possible, */ |
|
/* try to expose smaller "virtual" strips. */ |
|
if( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && |
|
tif->tif_dir.td_compression == COMPRESSION_NONE && |
|
(tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP && |
|
TIFFStripSize64(tif) > 0x7FFFFFFFUL ) |
|
{ |
|
TryChopUpUncompressedBigTiff(tif); |
|
} |
|
|
|
/* |
|
* Clear the dirty directory flag. |
|
*/ |
|
tif->tif_flags &= ~TIFF_DIRTYDIRECT; |
|
tif->tif_flags &= ~TIFF_DIRTYSTRIP; |
|
|
|
/* |
|
* Reinitialize i/o since we are starting on a new directory. |
|
*/ |
|
tif->tif_row = (uint32) -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"; |
|
uint32 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; |
|
(*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ |
|
_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_ignore = TRUE; |
|
} else { |
|
TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); |
|
assert( fii != FAILED_FII ); |
|
} |
|
} |
|
if (!dp->tdir_ignore) |
|
{ |
|
fip=tif->tif_fields[fii]; |
|
if (fip->field_bit==FIELD_IGNORE) |
|
dp->tdir_ignore = TRUE; |
|
else |
|
{ |
|
/* check data type */ |
|
while ((fip->field_type!=TIFF_ANY)&&(fip->field_type!=dp->tdir_type)) |
|
{ |
|
fii++; |
|
if ((fii==tif->tif_nfields)|| |
|
(tif->tif_fields[fii]->field_tag!=(uint32)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_ignore = TRUE; |
|
} |
|
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_ignore = TRUE; |
|
} |
|
} |
|
} |
|
if (!dp->tdir_ignore) { |
|
switch (dp->tdir_tag) |
|
{ |
|
case EXIFTAG_SUBJECTDISTANCE: |
|
(void)TIFFFetchSubjectDistance(tif, dp); |
|
break; |
|
default: |
|
(void)TIFFFetchNormalTag(tif, dp, TRUE); |
|
break; |
|
} |
|
} /*-- if (!dp->tdir_ignore) */ |
|
} |
|
} |
|
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); |
|
} |
|
|
|
/* |
|
*--: EXIF-GPS custom directory reading as another special case of custom IFD. |
|
*/ |
|
int |
|
TIFFReadGPSDirectory(TIFF* tif, toff_t diroff) |
|
{ |
|
const TIFFFieldArray* gpsFieldArray; |
|
gpsFieldArray = _TIFFGetGpsFields(); |
|
return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray); |
|
} |
|
|
|
static int |
|
EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 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_p) |
|
_TIFFfree(td->td_stripbytecount_p); |
|
td->td_stripbytecount_p = (uint64*) |
|
_TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64), |
|
"for \"StripByteCounts\" array"); |
|
if( td->td_stripbytecount_p == 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; |
|
} |
|
if( dp->tdir_count > TIFF_UINT64_MAX / typewidth ) |
|
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; |
|
} |
|
if( space > TIFF_UINT64_MAX - datasize ) |
|
return -1; |
|
space+=datasize; |
|
} |
|
if( filesize < space ) |
|
/* we should perhaps return in error ? */ |
|
space = filesize; |
|
else |
|
space = filesize - space; |
|
if (td->td_planarconfig == PLANARCONFIG_SEPARATE) |
|
space /= td->td_samplesperpixel; |
|
for (strip = 0; strip < td->td_nstrips; strip++) |
|
td->td_stripbytecount_p[strip] = space; |
|
/* |
|
* This gross hack handles the case were the offset to |
|
* the last strip is past the place where we think the strip |
|
* should begin. Since a strip of data must be contiguous, |
|
* it's safe to assume that we've overestimated the amount |
|
* of data in the strip and trim this number back accordingly. |
|
*/ |
|
strip--; |
|
if (td->td_stripoffset_p[strip] > TIFF_UINT64_MAX - td->td_stripbytecount_p[strip]) |
|
return -1; |
|
if (td->td_stripoffset_p[strip]+td->td_stripbytecount_p[strip] > filesize) { |
|
if( td->td_stripoffset_p[strip] >= filesize ) { |
|
/* Not sure what we should in that case... */ |
|
td->td_stripbytecount_p[strip] = 0; |
|
} else { |
|
td->td_stripbytecount_p[strip] = filesize - td->td_stripoffset_p[strip]; |
|
} |
|
} |
|
} else if (isTiled(tif)) { |
|
uint64 bytespertile = TIFFTileSize64(tif); |
|
|
|
for (strip = 0; strip < td->td_nstrips; strip++) |
|
td->td_stripbytecount_p[strip] = bytespertile; |
|
} else { |
|
uint64 rowbytes = TIFFScanlineSize64(tif); |
|
uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; |
|
for (strip = 0; strip < td->td_nstrips; strip++) |
|
{ |
|
if( rowbytes > 0 && rowsperstrip > TIFF_UINT64_MAX / rowbytes ) |
|
return -1; |
|
td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip; |
|
} |
|
} |
|
TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); |
|
if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) |
|
td->td_rowsperstrip = td->td_imagelength; |
|
return 1; |
|
} |
|
|
|
static void |
|
MissingRequired(TIFF* tif, const char* tagname) |
|
{ |
|
static const char module[] = "MissingRequired"; |
|
|
|
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; |
|
if (tif->tif_diroff > (uint64)TIFF_INT64_MAX) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count"); |
|
return(0); |
|
} |
|
off = (tmsize_t) tif->tif_diroff; |
|
|
|
/* |
|
* Check for integer overflow when validating the dir_off, |
|
* otherwise a very high offset may cause an OOB read and |
|
* crash the client. Make two comparisons instead of |
|
* |
|
* off + sizeof(uint16) > 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++) |
|
{ |
|
mb->tdir_ignore = FALSE; |
|
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); |
|
mb->tdir_offset.toff_long8=0; |
|
*(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) |
|
{ |
|
uint32 mb = 0; |
|
int n; |
|
if (data != NULL) |
|
{ |
|
uint8* ma = data; |
|
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; |
|
assert(data); /* avoid CLang static Analyzer false positive */ |
|
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; |
|
/*--: Rational2Double: Extend for Double Arrays and Rational-Arrays read into Double-Arrays. */ |
|
case TIFF_SETGET_C0_DOUBLE: |
|
{ |
|
double* data; |
|
assert(fip->field_readcount>=1); |
|
assert(fip->field_passcount==0); |
|
if (dp->tdir_count!=(uint64)fip->field_readcount) |
|
/* corrupt file */; |
|
else |
|
{ |
|
err=TIFFReadDirEntryDoubleArray(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( data != 0 && 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( data != 0 && 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 || m.i[1]==0) |
|
/* |
|
* XXX: Numerator 0xFFFFFFFF means that we have infinite |
|
* distance. Indicate that with a negative floating point |
|
* SubjectDistance value. |
|
*/ |
|
n=-1.0; |
|
else |
|
n=(double)m.i[0]/(double)m.i[1]; |
|
return(TIFFSetField(tif,dir->tdir_tag,n)); |
|
} |
|
else |
|
{ |
|
TIFFReadDirEntryOutputErr(tif,err,module,"SubjectDistance",TRUE); |
|
return(0); |
|
} |
|
} |
|
|
|
static void allocChoppedUpStripArrays(TIFF* tif, uint32 nstrips, |
|
uint64 stripbytes, uint32 rowsperstrip) |
|
{ |
|
TIFFDirectory *td = &tif->tif_dir; |
|
uint64 bytecount; |
|
uint64 offset; |
|
uint64 last_offset; |
|
uint64 last_bytecount; |
|
uint32 i; |
|
uint64 *newcounts; |
|
uint64 *newoffsets; |
|
|
|
offset = TIFFGetStrileOffset(tif, 0); |
|
last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1); |
|
last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1); |
|
if( last_offset > TIFF_UINT64_MAX - last_bytecount || |
|
last_offset + last_bytecount < offset ) |
|
{ |
|
return; |
|
} |
|
bytecount = last_offset + last_bytecount - offset; |
|
|
|
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 (i = 0; i < nstrips; i++) |
|
{ |
|
if (stripbytes > bytecount) |
|
stripbytes = bytecount; |
|
newcounts[i] = stripbytes; |
|
newoffsets[i] = stripbytes ? offset : 0; |
|
offset += stripbytes; |
|
bytecount -= stripbytes; |
|
} |
|
|
|
/* |
|
* Replace old single strip info with multi-strip info. |
|
*/ |
|
td->td_stripsperimage = td->td_nstrips = nstrips; |
|
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); |
|
|
|
_TIFFfree(td->td_stripbytecount_p); |
|
_TIFFfree(td->td_stripoffset_p); |
|
td->td_stripbytecount_p = newcounts; |
|
td->td_stripoffset_p = newoffsets; |
|
#ifdef STRIPBYTECOUNTSORTED_UNUSED |
|
td->td_stripbytecountsorted = 1; |
|
#endif |
|
tif->tif_flags |= TIFF_CHOPPEDUPARRAYS; |
|
} |
|
|
|
|
|
/* |
|
* Replace a single strip (tile) of uncompressed data by multiple strips |
|
* (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for |
|
* dealing with large images or for dealing with machines with a limited |
|
* amount memory. |
|
*/ |
|
static void |
|
ChopUpSingleUncompressedStrip(TIFF* tif) |
|
{ |
|
register TIFFDirectory *td = &tif->tif_dir; |
|
uint64 bytecount; |
|
uint64 offset; |
|
uint32 rowblock; |
|
uint64 rowblockbytes; |
|
uint64 stripbytes; |
|
uint32 nstrips; |
|
uint32 rowsperstrip; |
|
|
|
bytecount = TIFFGetStrileByteCount(tif, 0); |
|
/* On a newly created file, just re-opened to be filled, we */ |
|
/* don't want strip chop to trigger as it is going to cause issues */ |
|
/* later ( StripOffsets and StripByteCounts improperly filled) . */ |
|
if( bytecount == 0 && tif->tif_mode != O_RDONLY ) |
|
return; |
|
offset = TIFFGetStrileByteCount(tif, 0); |
|
assert(td->td_planarconfig == PLANARCONFIG_CONTIG); |
|
if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& |
|
(!isUpSampled(tif))) |
|
rowblock = td->td_ycbcrsubsampling[1]; |
|
else |
|
rowblock = 1; |
|
rowblockbytes = TIFFVTileSize64(tif, rowblock); |
|
/* |
|
* Make the rows hold at least one scanline, but fill specified amount |
|
* of data if possible. |
|
*/ |
|
if (rowblockbytes > STRIP_SIZE_DEFAULT) { |
|
stripbytes = rowblockbytes; |
|
rowsperstrip = rowblock; |
|
} else if (rowblockbytes > 0 ) { |
|
uint32 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; |
|
|
|
/* If we are going to allocate a lot of memory, make sure that the */ |
|
/* file is as big as needed */ |
|
if( tif->tif_mode == O_RDONLY && |
|
nstrips > 1000000 && |
|
(offset >= TIFFGetFileSize(tif) || |
|
stripbytes > (TIFFGetFileSize(tif) - offset) / (nstrips - 1)) ) |
|
{ |
|
return; |
|
} |
|
|
|
allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); |
|
} |
|
|
|
|
|
/* |
|
* Replace a file with contiguous strips > 2 GB of uncompressed data by |
|
* multiple smaller strips. This is useful for |
|
* dealing with large images or for dealing with machines with a limited |
|
* amount memory. |
|
*/ |
|
static void TryChopUpUncompressedBigTiff( TIFF* tif ) |
|
{ |
|
TIFFDirectory *td = &tif->tif_dir; |
|
uint32 rowblock; |
|
uint64 rowblockbytes; |
|
uint32 i; |
|
uint64 stripsize; |
|
uint32 rowblocksperstrip; |
|
uint32 rowsperstrip; |
|
uint64 stripbytes; |
|
uint32 nstrips; |
|
|
|
stripsize = TIFFStripSize64(tif); |
|
|
|
assert( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG ); |
|
assert( tif->tif_dir.td_compression == COMPRESSION_NONE ); |
|
assert( (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP ); |
|
assert( stripsize > 0x7FFFFFFFUL ); |
|
|
|
/* On a newly created file, just re-opened to be filled, we */ |
|
/* don't want strip chop to trigger as it is going to cause issues */ |
|
/* later ( StripOffsets and StripByteCounts improperly filled) . */ |
|
if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY ) |
|
return; |
|
|
|
if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& |
|
(!isUpSampled(tif))) |
|
rowblock = td->td_ycbcrsubsampling[1]; |
|
else |
|
rowblock = 1; |
|
rowblockbytes = TIFFVStripSize64(tif, rowblock); |
|
if( rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL ) |
|
{ |
|
/* In case of file with gigantic width */ |
|
return; |
|
} |
|
|
|
/* Check that the strips are contiguous and of the expected size */ |
|
for( i = 0; i < td->td_nstrips; i++ ) |
|
{ |
|
if( i == td->td_nstrips - 1 ) |
|
{ |
|
if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64( |
|
tif, td->td_imagelength - i * td->td_rowsperstrip ) ) |
|
{ |
|
return; |
|
} |
|
} |
|
else |
|
{ |
|
if( TIFFGetStrileByteCount(tif, i) != stripsize ) |
|
{ |
|
return; |
|
} |
|
if( i > 0 && TIFFGetStrileOffset(tif, i) != |
|
TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) ) |
|
{ |
|
return; |
|
} |
|
} |
|
} |
|
|
|
/* Aim for 512 MB strips (that will still be manageable by 32 bit builds */ |
|
rowblocksperstrip = (uint32) (512 * 1024 * 1024 / rowblockbytes); |
|
if( rowblocksperstrip == 0 ) |
|
rowblocksperstrip = 1; |
|
rowsperstrip = rowblocksperstrip * rowblock; |
|
stripbytes = rowblocksperstrip * rowblockbytes; |
|
assert( stripbytes <= 0x7FFFFFFFUL ); |
|
|
|
nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); |
|
if( nstrips == 0 ) |
|
return; |
|
|
|
/* If we are going to allocate a lot of memory, make sure that the */ |
|
/* file is as big as needed */ |
|
if( tif->tif_mode == O_RDONLY && |
|
nstrips > 1000000 ) |
|
{ |
|
uint64 last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1); |
|
uint64 filesize = TIFFGetFileSize(tif); |
|
uint64 last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1); |
|
if( last_offset > filesize || |
|
last_bytecount > filesize - last_offset ) |
|
{ |
|
return; |
|
} |
|
} |
|
|
|
allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); |
|
} |
|
|
|
|
|
TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW |
|
static uint64 _TIFFUnsanitizedAddUInt64AndInt(uint64 a, int b) |
|
{ |
|
return a + b; |
|
} |
|
|
|
/* Read the value of [Strip|Tile]Offset or [Strip|Tile]ByteCount around |
|
* strip/tile of number strile. Also fetch the neighbouring values using a |
|
* 4096 byte page size. |
|
*/ |
|
static |
|
int _TIFFPartialReadStripArray( TIFF* tif, TIFFDirEntry* dirent, |
|
int strile, uint64* panVals ) |
|
{ |
|
static const char module[] = "_TIFFPartialReadStripArray"; |
|
#define IO_CACHE_PAGE_SIZE 4096 |
|
|
|
size_t sizeofval; |
|
const int bSwab = (tif->tif_flags & TIFF_SWAB) != 0; |
|
int sizeofvalint; |
|
uint64 nBaseOffset; |
|
uint64 nOffset; |
|
uint64 nOffsetStartPage; |
|
uint64 nOffsetEndPage; |
|
tmsize_t nToRead; |
|
tmsize_t nRead; |
|
uint64 nLastStripOffset; |
|
int iStartBefore; |
|
int i; |
|
const uint32 arraySize = tif->tif_dir.td_stripoffsetbyteallocsize; |
|
unsigned char buffer[2 * IO_CACHE_PAGE_SIZE]; |
|
|
|
assert( dirent->tdir_count > 4 ); |
|
|
|
if( dirent->tdir_type == TIFF_SHORT ) |
|
{ |
|
sizeofval = sizeof(uint16); |
|
} |
|
else if( dirent->tdir_type == TIFF_LONG ) |
|
{ |
|
sizeofval = sizeof(uint32); |
|
} |
|
else if( dirent->tdir_type == TIFF_LONG8 ) |
|
{ |
|
sizeofval = sizeof(uint64); |
|
} |
|
else if( dirent->tdir_type == TIFF_SLONG8 ) |
|
{ |
|
/* Non conformant but used by some images as in */ |
|
/* https://github.com/OSGeo/gdal/issues/2165 */ |
|
sizeofval = sizeof(int64); |
|
} |
|
else |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Invalid type for [Strip|Tile][Offset/ByteCount] tag"); |
|
panVals[strile] = 0; |
|
return 0; |
|
} |
|
sizeofvalint = (int)(sizeofval); |
|
|
|
if( tif->tif_flags&TIFF_BIGTIFF ) |
|
{ |
|
uint64 offset = dirent->tdir_offset.toff_long8; |
|
if( bSwab ) |
|
TIFFSwabLong8(&offset); |
|
nBaseOffset = offset; |
|
} |
|
else |
|
{ |
|
uint32 offset = dirent->tdir_offset.toff_long; |
|
if( bSwab ) |
|
TIFFSwabLong(&offset); |
|
nBaseOffset = offset; |
|
} |
|
/* To avoid later unsigned integer overflows */ |
|
if( nBaseOffset > (uint64)TIFF_INT64_MAX ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Cannot read offset/size for strile %d", strile); |
|
panVals[strile] = 0; |
|
return 0; |
|
} |
|
nOffset = nBaseOffset + sizeofval * strile; |
|
nOffsetStartPage = |
|
(nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE; |
|
nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE; |
|
|
|
if( nOffset + sizeofval > nOffsetEndPage ) |
|
nOffsetEndPage += IO_CACHE_PAGE_SIZE; |
|
#undef IO_CACHE_PAGE_SIZE |
|
|
|
nLastStripOffset = nBaseOffset + arraySize * sizeofval; |
|
if( nLastStripOffset < nOffsetEndPage ) |
|
nOffsetEndPage = nLastStripOffset; |
|
if( nOffsetStartPage >= nOffsetEndPage ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Cannot read offset/size for strile %d", strile); |
|
panVals[strile] = 0; |
|
return 0; |
|
} |
|
if (!SeekOK(tif,nOffsetStartPage)) |
|
{ |
|
panVals[strile] = 0; |
|
return 0; |
|
} |
|
|
|
nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage); |
|
nRead = TIFFReadFile(tif, buffer, nToRead); |
|
if( nRead < nToRead ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Cannot read offset/size for strile around ~%d", strile); |
|
return 0; |
|
} |
|
iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval); |
|
if( strile + iStartBefore < 0 ) |
|
iStartBefore = -strile; |
|
for( i = iStartBefore; |
|
(uint32)(strile + i) < arraySize && |
|
_TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage; |
|
++i ) |
|
{ |
|
if( dirent->tdir_type == TIFF_SHORT ) |
|
{ |
|
uint16 val; |
|
memcpy(&val, |
|
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, |
|
sizeof(val)); |
|
if( bSwab ) |
|
TIFFSwabShort(&val); |
|
panVals[strile + i] = val; |
|
} |
|
else if( dirent->tdir_type == TIFF_LONG ) |
|
{ |
|
uint32 val; |
|
memcpy(&val, |
|
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, |
|
sizeof(val)); |
|
if( bSwab ) |
|
TIFFSwabLong(&val); |
|
panVals[strile + i] = val; |
|
} |
|
else if( dirent->tdir_type == TIFF_LONG8 ) |
|
{ |
|
uint64 val; |
|
memcpy(&val, |
|
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, |
|
sizeof(val)); |
|
if( bSwab ) |
|
TIFFSwabLong8(&val); |
|
panVals[strile + i] = val; |
|
} |
|
else /* if( dirent->tdir_type == TIFF_SLONG8 ) */ |
|
{ |
|
/* Non conformant data type */ |
|
int64 val; |
|
memcpy(&val, |
|
buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, |
|
sizeof(val)); |
|
if( bSwab ) |
|
TIFFSwabLong8((uint64*) &val); |
|
panVals[strile + i] = (uint64) val; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
static int _TIFFFetchStrileValue(TIFF* tif, |
|
uint32 strile, |
|
TIFFDirEntry* dirent, |
|
uint64** parray) |
|
{ |
|
static const char module[] = "_TIFFFetchStrileValue"; |
|
TIFFDirectory *td = &tif->tif_dir; |
|
if( strile >= dirent->tdir_count ) |
|
{ |
|
return 0; |
|
} |
|
if( strile >= td->td_stripoffsetbyteallocsize ) |
|
{ |
|
uint32 nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize; |
|
uint32 nStripArrayAllocNew; |
|
uint64 nArraySize64; |
|
size_t nArraySize; |
|
uint64* offsetArray; |
|
uint64* bytecountArray; |
|
|
|
if( strile > 1000000 ) |
|
{ |
|
uint64 filesize = TIFFGetFileSize(tif); |
|
/* Avoid excessive memory allocation attempt */ |
|
/* For such a big blockid we need at least a TIFF_LONG per strile */ |
|
/* for the offset array. */ |
|
if( strile > filesize / sizeof(uint32) ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, "File too short"); |
|
return 0; |
|
} |
|
} |
|
|
|
if( td->td_stripoffsetbyteallocsize == 0 && |
|
td->td_nstrips < 1024 * 1024 ) |
|
{ |
|
nStripArrayAllocNew = td->td_nstrips; |
|
} |
|
else |
|
{ |
|
#define TIFF_MAX(a,b) (((a)>(b)) ? (a) : (b)) |
|
#define TIFF_MIN(a,b) (((a)<(b)) ? (a) : (b)) |
|
nStripArrayAllocNew = TIFF_MAX(strile + 1, 1024U * 512U ); |
|
if( nStripArrayAllocNew < 0xFFFFFFFFU / 2 ) |
|
nStripArrayAllocNew *= 2; |
|
nStripArrayAllocNew = TIFF_MIN(nStripArrayAllocNew, td->td_nstrips); |
|
} |
|
assert( strile < nStripArrayAllocNew ); |
|
nArraySize64 = (uint64)sizeof(uint64) * nStripArrayAllocNew; |
|
nArraySize = (size_t)(nArraySize64); |
|
#if SIZEOF_SIZE_T == 4 |
|
if( nArraySize != nArraySize64 ) |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Cannot allocate strip offset and bytecount arrays"); |
|
return 0; |
|
} |
|
#endif |
|
offsetArray = (uint64*)( |
|
_TIFFrealloc( td->td_stripoffset_p, nArraySize ) ); |
|
bytecountArray = (uint64*)( |
|
_TIFFrealloc( td->td_stripbytecount_p, nArraySize ) ); |
|
if( offsetArray ) |
|
td->td_stripoffset_p = offsetArray; |
|
if( bytecountArray ) |
|
td->td_stripbytecount_p = bytecountArray; |
|
if( offsetArray && bytecountArray ) |
|
{ |
|
td->td_stripoffsetbyteallocsize = nStripArrayAllocNew; |
|
/* Initialize new entries to ~0 / -1 */ |
|
memset(td->td_stripoffset_p + nStripArrayAllocBefore, |
|
0xFF, |
|
(td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) ); |
|
memset(td->td_stripbytecount_p + nStripArrayAllocBefore, |
|
0xFF, |
|
(td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64) ); |
|
} |
|
else |
|
{ |
|
TIFFErrorExt(tif->tif_clientdata, module, |
|
"Cannot allocate strip offset and bytecount arrays"); |
|
_TIFFfree(td->td_stripoffset_p); |
|
td->td_stripoffset_p = NULL; |
|
_TIFFfree(td->td_stripbytecount_p); |
|
td->td_stripbytecount_p = NULL; |
|
td->td_stripoffsetbyteallocsize = 0; |
|
} |
|
} |
|
if( *parray == NULL || strile >= td->td_stripoffsetbyteallocsize ) |
|
return 0; |
|
|
|
if( ~((*parray)[strile]) == 0 ) |
|
{ |
|
if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) ) |
|
{ |
|
(*parray)[strile] = 0; |
|
return 0; |
|
} |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
static uint64 _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32 strile, |
|
TIFFDirEntry* dirent, |
|
uint64** parray, |
|
int *pbErr) |
|
{ |
|
TIFFDirectory *td = &tif->tif_dir; |
|
if( pbErr ) |
|
*pbErr = 0; |
|
if( (tif->tif_flags&TIFF_DEFERSTRILELOAD) && !(tif->tif_flags&TIFF_CHOPPEDUPARRAYS) ) |
|
{ |
|
if( !(tif->tif_flags&TIFF_LAZYSTRILELOAD) || |
|
/* If the values may fit in the toff_long/toff_long8 member */ |
|
/* then use _TIFFFillStriles to simplify _TIFFFetchStrileValue */ |
|
dirent->tdir_count <= 4 ) |
|
{ |
|
if( !_TIFFFillStriles(tif) ) |
|
{ |
|
if( pbErr ) |
|
*pbErr = 1; |
|
/* Do not return, as we want this function to always */ |
|
/* return the same value if called several times with */ |
|
/* the same arguments */ |
|
} |
|
} |
|
else |
|
{ |
|
if( !_TIFFFetchStrileValue(tif, strile, dirent, parray) ) |
|
{ |
|
if( pbErr ) |
|
*pbErr = 1; |
|
return 0; |
|
} |
|
} |
|
} |
|
if( *parray == NULL || strile >= td->td_nstrips ) |
|
{ |
|
if( pbErr ) |
|
*pbErr = 1; |
|
return 0; |
|
} |
|
return (*parray)[strile]; |
|
} |
|
|
|
/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */ |
|
uint64 TIFFGetStrileOffset(TIFF *tif, uint32 strile) |
|
{ |
|
return TIFFGetStrileOffsetWithErr(tif, strile, NULL); |
|
} |
|
|
|
/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */ |
|
uint64 TIFFGetStrileOffsetWithErr(TIFF *tif, uint32 strile, int *pbErr) |
|
{ |
|
TIFFDirectory *td = &tif->tif_dir; |
|
return _TIFFGetStrileOffsetOrByteCountValue(tif, strile, |
|
&(td->td_stripoffset_entry), |
|
&(td->td_stripoffset_p), pbErr); |
|
} |
|
|
|
/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */ |
|
uint64 TIFFGetStrileByteCount(TIFF *tif, uint32 strile) |
|
{ |
|
return TIFFGetStrileByteCountWithErr(tif, strile, NULL); |
|
} |
|
|
|
/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */ |
|
uint64 TIFFGetStrileByteCountWithErr(TIFF *tif, uint32 strile, int *pbErr) |
|
{ |
|
TIFFDirectory *td = &tif->tif_dir; |
|
return _TIFFGetStrileOffsetOrByteCountValue(tif, strile, |
|
&(td->td_stripbytecount_entry), |
|
&(td->td_stripbytecount_p), pbErr); |
|
} |
|
|
|
|
|
int _TIFFFillStriles( TIFF *tif ) |
|
{ |
|
return _TIFFFillStrilesInternal( tif, 1 ); |
|
} |
|
|
|
static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ) |
|
{ |
|
register TIFFDirectory *td = &tif->tif_dir; |
|
int return_value = 1; |
|
|
|
/* Do not do anything if TIFF_DEFERSTRILELOAD is not set */ |
|
if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) || (tif->tif_flags&TIFF_CHOPPEDUPARRAYS) != 0 ) |
|
return 1; |
|
|
|
if( tif->tif_flags&TIFF_LAZYSTRILELOAD ) |
|
{ |
|
/* In case of lazy loading, reload completely the arrays */ |
|
_TIFFfree(td->td_stripoffset_p); |
|
_TIFFfree(td->td_stripbytecount_p); |
|
td->td_stripoffset_p = NULL; |
|
td->td_stripbytecount_p = NULL; |
|
td->td_stripoffsetbyteallocsize = 0; |
|
tif->tif_flags &= ~TIFF_LAZYSTRILELOAD; |
|
} |
|
|
|
/* If stripoffset array is already loaded, exit with success */ |
|
if( td->td_stripoffset_p != NULL ) |
|
return 1; |
|
|
|
/* If tdir_count was canceled, then we already got there, but in error */ |
|
if( td->td_stripoffset_entry.tdir_count == 0 ) |
|
return 0; |
|
|
|
if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry), |
|
td->td_nstrips,&td->td_stripoffset_p)) |
|
{ |
|
return_value = 0; |
|
} |
|
|
|
if (loadStripByteCount && |
|
!TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry), |
|
td->td_nstrips,&td->td_stripbytecount_p)) |
|
{ |
|
return_value = 0; |
|
} |
|
|
|
_TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); |
|
_TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); |
|
|
|
#ifdef STRIPBYTECOUNTSORTED_UNUSED |
|
if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) { |
|
uint32 strip; |
|
|
|
tif->tif_dir.td_stripbytecountsorted = 1; |
|
for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { |
|
if (tif->tif_dir.td_stripoffset_p[strip - 1] > |
|
tif->tif_dir.td_stripoffset_p[strip]) { |
|
tif->tif_dir.td_stripbytecountsorted = 0; |
|
break; |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
return return_value; |
|
} |
|
|
|
|
|
/* vim: set ts=8 sts=8 sw=8 noet: */ |
|
/* |
|
* Local Variables: |
|
* mode: c |
|
* c-basic-offset: 8 |
|
* fill-column: 78 |
|
* End: |
|
*/
|
|
|