tif_dirread.c

来自「支持各种栅格图像和矢量图像读取的库」· C语言 代码 · 共 1,972 行 · 第 1/4 页

C
1,972
字号
		toff_t* new_dirlist;		/*		 * XXX: Reduce memory allocation granularity of the dirlist		 * array.		 */		new_dirlist = (toff_t *)_TIFFCheckRealloc(tif,							  tif->tif_dirlist,							  tif->tif_dirnumber,							  2 * sizeof(toff_t),							  "for IFD list");		if (!new_dirlist)			return 0;		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 intCheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count){	if (count > dir->tdir_count) {		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,	"incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored",		    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,		    dir->tdir_count, count);		return (0);	} else if (count < dir->tdir_count) {		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,	"incorrect count for field \"%s\" (%lu, expecting %lu); tag trimmed",		    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,		    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 uint16TIFFFetchDirectory(TIFF* tif, toff_t diroff, TIFFDirEntry **pdir,		   toff_t *nextdiroff){	static const char module[] = "TIFFFetchDirectory";	TIFFDirEntry *dir;	uint16 dircount;	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 (!ReadOK(tif, &dircount, 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(&dircount);		dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount,						sizeof (TIFFDirEntry),						"to read TIFF directory");		if (dir == NULL)			return 0;		if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {			TIFFErrorExt(tif->tif_clientdata, module,				"%.100s: Can not read TIFF directory",				tif->tif_name);			_TIFFfree(dir);			return 0;		}		/*		 * Read offset to next directory for sequential scans if		 * needed.		 */		if (nextdiroff)			(void) ReadOK(tif, nextdiroff, sizeof(uint32));	} else {		toff_t off = 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_size < sizeof (uint16) ||		    off > tif->tif_size - sizeof(uint16)) {			TIFFErrorExt(tif->tif_clientdata, module,				"%s: Can not read TIFF directory count",				tif->tif_name);			return 0;		} else {			_TIFFmemcpy(&dircount, tif->tif_base + off,				    sizeof(uint16));		}		off += sizeof (uint16);		if (tif->tif_flags & TIFF_SWAB)			TIFFSwabShort(&dircount);		dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount,						sizeof(TIFFDirEntry),						"to read TIFF directory");		if (dir == NULL)			return 0;		if (off + dircount * sizeof (TIFFDirEntry) > tif->tif_size) {			TIFFErrorExt(tif->tif_clientdata, module,				     "%s: Can not read TIFF directory",				     tif->tif_name);			_TIFFfree(dir);			return 0;		} else {			_TIFFmemcpy(dir, tif->tif_base + off,				    dircount * sizeof(TIFFDirEntry));		}		if (nextdiroff) {			off += dircount * sizeof (TIFFDirEntry);			if (off + sizeof (uint32) <= tif->tif_size) {				_TIFFmemcpy(nextdiroff, tif->tif_base + off,					    sizeof (uint32));			}		}	}	if (nextdiroff && tif->tif_flags & TIFF_SWAB)		TIFFSwabLong(nextdiroff);	*pdir = dir;	return dircount;}/* * Fetch a contiguous directory item. */static tsize_tTIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp){	int w = TIFFDataWidth((TIFFDataType) dir->tdir_type);	tsize_t cc = dir->tdir_count * w;	/* Check for overflow. */	if (!dir->tdir_count || !w || cc / w != (tsize_t)dir->tdir_count)		goto bad;	if (!isMapped(tif)) {		if (!SeekOK(tif, dir->tdir_offset))			goto bad;		if (!ReadOK(tif, cp, cc))			goto bad;	} else {		/* Check for overflow. */		if ((tsize_t)dir->tdir_offset + cc < (tsize_t)dir->tdir_offset		    || (tsize_t)dir->tdir_offset + cc < cc		    || (tsize_t)dir->tdir_offset + cc > (tsize_t)tif->tif_size)			goto bad;		_TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc);	}	if (tif->tif_flags & TIFF_SWAB) {		switch (dir->tdir_type) {		case TIFF_SHORT:		case TIFF_SSHORT:			TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);			break;		case TIFF_LONG:		case TIFF_SLONG:		case TIFF_FLOAT:			TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);			break;		case TIFF_RATIONAL:		case TIFF_SRATIONAL:			TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);			break;		case TIFF_DOUBLE:			TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);			break;		}	}	return (cc);bad:	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,		     "Error fetching data for field \"%s\"",		     _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);	return (tsize_t) 0;}/* * Fetch an ASCII item from the file. */static tsize_tTIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp){	if (dir->tdir_count <= 4) {		uint32 l = dir->tdir_offset;		if (tif->tif_flags & TIFF_SWAB)			TIFFSwabLong(&l);		_TIFFmemcpy(cp, &l, dir->tdir_count);		return (1);	}	return (TIFFFetchData(tif, dir, cp));}/* * Convert numerator+denominator to float. */static intcvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv){	if (denom == 0) {		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,		    "%s: Rational with zero denominator (num = %lu)",		    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);		return (0);	} else {		if (dir->tdir_type == TIFF_RATIONAL)			*rv = ((float)num / (float)denom);		else			*rv = ((float)(int32)num / (float)(int32)denom);		return (1);	}}/* * Fetch a rational item from the file * at offset off and return the value * as a floating point number. */static floatTIFFFetchRational(TIFF* tif, TIFFDirEntry* dir){	uint32 l[2];	float v;	return (!TIFFFetchData(tif, dir, (char *)l) ||	    !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v);}/* * Fetch a single floating point value * from the offset field and return it * as a native float. */static floatTIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir){	float v;	int32 l = TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);        _TIFFmemcpy(&v, &l, sizeof(float));	TIFFCvtIEEEFloatToNative(tif, 1, &v);	return (v);}/* * Fetch an array of BYTE or SBYTE values. */static intTIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint8* v){    if (dir->tdir_count <= 4) {        /*         * Extract data from offset field.         */        if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {	    if (dir->tdir_type == TIFF_SBYTE)                switch (dir->tdir_count) {                    case 4: v[3] = dir->tdir_offset & 0xff;                    case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;                    case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;		    case 1: v[0] = dir->tdir_offset >> 24;                }	    else                switch (dir->tdir_count) {                    case 4: v[3] = dir->tdir_offset & 0xff;                    case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;                    case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;		    case 1: v[0] = dir->tdir_offset >> 24;                }	} else {	    if (dir->tdir_type == TIFF_SBYTE)                switch (dir->tdir_count) {                    case 4: v[3] = dir->tdir_offset >> 24;                    case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;                    case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;                    case 1: v[0] = dir->tdir_offset & 0xff;		}	    else                switch (dir->tdir_count) {                    case 4: v[3] = dir->tdir_offset >> 24;                    case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;                    case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;                    case 1: v[0] = dir->tdir_offset & 0xff;		}	}        return (1);    } else        return (TIFFFetchData(tif, dir, (char*) v) != 0);	/* XXX */}/* * Fetch an array of SHORT or SSHORT values. */static intTIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v){	if (dir->tdir_count <= 2) {		if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {			switch (dir->tdir_count) {			case 2: v[1] = (uint16) (dir->tdir_offset & 0xffff);			case 1: v[0] = (uint16) (dir->tdir_offset >> 16);			}		} else {			switch (dir->tdir_count) {			case 2: v[1] = (uint16) (dir->tdir_offset >> 16);			case 1: v[0] = (uint16) (dir->tdir_offset & 0xffff);			}		}		return (1);	} else		return (TIFFFetchData(tif, dir, (char *)v) != 0);}/* * Fetch a pair of SHORT or BYTE values. Some tags may have either BYTE * or SHORT type and this function works with both ones. */static intTIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir){	/*	 * Prevent overflowing the v stack arrays below by performing a sanity	 * check on tdir_count, this should never be greater than two.	 */	if (dir->tdir_count > 2) {		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,		"unexpected count for field \"%s\", %lu, expected 2; ignored",			_TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,			dir->tdir_count);		return 0;	}	switch (dir->tdir_type) {		case TIFF_BYTE:		case TIFF_SBYTE:			{			uint8 v[4];			return TIFFFetchByteArray(tif, dir, v)				&& TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);			}		case TIFF_SHORT:		case TIFF_SSHORT:			{			uint16 v[2];			return TIFFFetchShortArray(tif, dir, v)				&& TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);			}		default:			return 0;	}}/* * Fetch an array of LONG or SLONG values. */static intTIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v){	if (dir->tdir_count == 1) {		v[0] = dir->tdir_offset;		return (1);	} else		return (TIFFFetchData(tif, dir, (char*) v) != 0);}/* * Fetch an array of RATIONAL or SRATIONAL values. */static intTIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v){	int ok = 0;	uint32* l;	l = (uint32*)_TIFFCheckMalloc(tif,	    dir->tdir_count, TIFFDataWidth((TIFFDataType) dir->tdir_type),	    "to fetch array of rationals");	if (l) {		if (TIFFFetchData(tif, dir, (char *)l)) {			uint32 i;			for (i = 0; i < dir->tdir_count; i++) {				ok = cvtRational(tif, dir,				    l[2*i+0], l[2*i+1], &v[i]);				if (!ok)					break;			}		}		_TIFFfree((char *)l);	}	return (ok);}/* * Fetch an array of FLOAT values. */static intTIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v){	if (dir->tdir_count == 1) {		v[0] = *(float*) &dir->tdir_offset;		TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);		return (1);	} else	if (TIFFFetchData(tif, dir, (char*) v)) {		TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);		return (1);	} else		return (0);}/* * Fetch an array of DOUBLE values. */static intTIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v){	if (TIFFFetchData(tif, dir, (char*) v)) {		TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v);		return (1);	} else		return (0);}/* * Fetch an array of ANY values.  The actual values are returned as doubles * which should be able hold all the types.  Yes, there really should be an * tany_t to avoid this potential non-portability ...  Note in particular that * we assume that the double return value vector is large enough to read in * any fundamental type.  We use that vector as a buffer to read in the base * type vector and then convert it in place to double (from end to front of * course). */static intTIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v){	int i;	switch (dir->tdir_type) {	case TIFF_BYTE:	case TIFF_SBYTE:		if (!TIFFFetchByteArray(tif, dir, (uint8*) v))			return (0);		if (dir->tdir_type == TIFF_BYTE) {			uint8* vp = (uint8*) v;			for (i = dir->tdir_count-1; i >= 0; i--)				v[i] = vp[i];		} else {			int8* vp = (int8*) v;			for (i = dir->tdir_count-1; i >= 0; i--)				v[i] = vp[i];		}		break;	case TIFF_SHORT:	case TIFF_SSHORT:		if (!TIFFFetchShortArray(tif, dir, (uint16*) v))			return (0);		if (dir->tdir_type == TIFF_SHORT) {			uint16* vp = (uint16*) v;			for (i = dir->tdir_count-1; i >= 0; i--)				v[i] = vp[i];		} else {			int16* vp = (int16*) v;			for (i = dir->tdir_count-1; i >= 0; i--)				v[i] = vp[i];		}		break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?