예제 #1
0
	const inline void* GetDataPtr ( const TweakedIFDEntry* tifdEntry ) const
		{ if ( GetUns32AsIs(&tifdEntry->bytes) <= 4 ) {
		  	return &tifdEntry->dataOrPos;
		  } else {
		  	return (this->tiffStream + GetUns32AsIs(&tifdEntry->dataOrPos));
		  }
		}
예제 #2
0
bool TIFF_MemoryReader::GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const
{
	if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
	const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];

	if ( ifdMap != 0 ) ifdMap->clear();
	if ( thisIFD->count == 0 ) return false;

	if ( ifdMap != 0 ) {

		for ( size_t i = 0; i < thisIFD->count; ++i ) {

			TweakedIFDEntry* thisTag = &(thisIFD->entries[i]);
			if ( (thisTag->type < kTIFF_ByteType) || (thisTag->type > kTIFF_LastType) ) continue;	// Bad type, skip this tag.

			TagInfo info ( thisTag->id, thisTag->type, 0, 0, GetUns32AsIs(&thisTag->bytes)  );
			info.count = info.dataLen / (XMP_Uns32)kTIFF_TypeSizes[info.type];
			info.dataPtr = this->GetDataPtr ( thisTag );

			(*ifdMap)[info.id] = info;

		}

	}

	return true;

}	// TIFF_MemoryReader::GetIFD
예제 #3
0
bool TIFF_MemoryReader::GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
{
	const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
	if ( thisTag == 0 ) return false;

	if ( thisTag->type > kTIFF_LastType ) return false;	// Unknown type.
	if ( GetUns32AsIs(&thisTag->bytes) != kTIFF_TypeSizes[thisTag->type] ) return false;	// Wrong count.

	XMP_Uns32 uns32;
	XMP_Int32 int32;

	switch ( thisTag->type ) {
	
		case kTIFF_ByteType:
			uns32 = GetUns8 ( this->GetDataPtr ( thisTag ) );
			break;
	
		case kTIFF_ShortType:
			uns32 = this->GetUns16 ( this->GetDataPtr ( thisTag ) );
			break;
	
		case kTIFF_LongType:
			uns32 = this->GetUns32 ( this->GetDataPtr ( thisTag ) );
			break;
	
		case kTIFF_SByteType:
			int32 = (XMP_Int8) GetUns8 ( this->GetDataPtr ( thisTag ) );
			uns32 = (XMP_Uns32) int32;	// Make sure sign bits are properly set.
			break;
	
		case kTIFF_SShortType:
			int32 = (XMP_Int16) this->GetUns16 ( this->GetDataPtr ( thisTag ) );
			uns32 = (XMP_Uns32) int32;	// Make sure sign bits are properly set.
			break;
	
		case kTIFF_SLongType:
			int32 = (XMP_Int32) this->GetUns32 ( this->GetDataPtr ( thisTag ) );
			uns32 = (XMP_Uns32) int32;	// Make sure sign bits are properly set.
			break;
	
		default: return false;

	}

	if ( data != 0 ) *data = uns32;
	return true;

}	// TIFF_MemoryReader::GetTag_Integer
예제 #4
0
bool TIFF_MemoryReader::GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const
{
	const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
	if ( thisTag == 0 ) return false;
	
	XMP_Uns16 thisType = GetUns16AsIs ( &thisTag->type );
	XMP_Uns32 thisBytes = GetUns32AsIs ( &thisTag->bytes );
	
	if ( (thisType < kTIFF_ByteType) || (thisType > kTIFF_LastType) ) return false;	// Bad type, skip this tag.

	if ( info != 0 ) {

		info->id = GetUns16AsIs ( &thisTag->id );
		info->type = thisType;
		info->count = thisBytes / (XMP_Uns32)kTIFF_TypeSizes[thisType];
		info->dataLen = thisBytes;

		info->dataPtr = this->GetDataPtr ( thisTag );

	}

	return true;

}	// TIFF_MemoryReader::GetTag
예제 #5
0
XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
{
	TweakedIFDInfo& ifdInfo = this->containedIFDs[ifd];

	if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
		XMP_Error error(kXMPErr_BadTIFF, "Bad IFD offset" );
		this->NotifyClient ( kXMPErrSev_FileFatal, error );
	}

	XMP_Uns8* ifdPtr = this->tiffStream + ifdOffset;
	XMP_Uns16 ifdCount = this->GetUns16 ( ifdPtr );
	TweakedIFDEntry* ifdEntries = (TweakedIFDEntry*)(ifdPtr+2);

	if ( ifdCount >= 0x8000 ) {
		XMP_Error error(kXMPErr_BadTIFF, "Outrageous IFD count" );
		this->NotifyClient ( kXMPErrSev_FileFatal, error );
	}

	if ( (XMP_Uns32)(2 + ifdCount*12 + 4) > (this->tiffLength - ifdOffset) ) {
		XMP_Error error(kXMPErr_BadTIFF, "Out of bounds IFD" );
		this->NotifyClient ( kXMPErrSev_FileFatal, error );
	}

	ifdInfo.count = ifdCount;
	ifdInfo.entries = ifdEntries;

	XMP_Int32 prevTag = -1;	// ! The GPS IFD has a tag 0, so we need a signed initial value.
	bool needsSorting = false;
	for ( size_t i = 0; i < ifdCount; ++i ) {

		TweakedIFDEntry* thisEntry = &ifdEntries[i];	// Tweak the IFD entry to be more useful.

		if ( ! this->nativeEndian ) {
			Flip2 ( &thisEntry->id );
			Flip2 ( &thisEntry->type );
			Flip4 ( &thisEntry->bytes );
		}

		if ( GetUns16AsIs(&thisEntry->id) <= prevTag ) needsSorting = true;
		prevTag = GetUns16AsIs ( &thisEntry->id );

		if ( (GetUns16AsIs(&thisEntry->type) < kTIFF_ByteType) || (GetUns16AsIs(&thisEntry->type) > kTIFF_LastType) ) continue;	// Bad type, skip this tag.

		#if ! SUNOS_SPARC
	
			thisEntry->bytes *= (XMP_Uns32)kTIFF_TypeSizes[thisEntry->type];
			if ( thisEntry->bytes > 4 ) {
				if ( ! this->nativeEndian ) Flip4 ( &thisEntry->dataOrPos );
				if ( (thisEntry->dataOrPos < 8) || (thisEntry->dataOrPos >= this->tiffLength) ) {
					thisEntry->bytes = thisEntry->dataOrPos = 0;	// Make this bad tag look empty.
				}
				if ( thisEntry->bytes > (this->tiffLength - thisEntry->dataOrPos) ) {
					thisEntry->bytes = thisEntry->dataOrPos = 0;	// Make this bad tag look empty.
				}
			}
	
		#else
	
			void *tempEntryByte = &thisEntry->bytes;
			XMP_Uns32 temp = GetUns32AsIs(&thisEntry->bytes);
			temp = temp * (XMP_Uns32)kTIFF_TypeSizes[GetUns16AsIs(&thisEntry->type)];
			memcpy ( tempEntryByte, &temp, sizeof(thisEntry->bytes) );
	
			// thisEntry->bytes *= (XMP_Uns32)kTIFF_TypeSizes[thisEntry->type];
			if ( GetUns32AsIs(&thisEntry->bytes) > 4 ) {
				void *tempEntryDataOrPos = &thisEntry->dataOrPos;
				if ( ! this->nativeEndian ) Flip4 ( &thisEntry->dataOrPos );
				if ( (GetUns32AsIs(&thisEntry->dataOrPos) < 8) || (GetUns32AsIs(&thisEntry->dataOrPos) >= this->tiffLength) ) {
					// thisEntry->bytes = thisEntry->dataOrPos = 0;	// Make this bad tag look empty.
					memset ( tempEntryByte, 0, sizeof(XMP_Uns32) );
					memset ( tempEntryDataOrPos, 0, sizeof(XMP_Uns32) );
				}
				if ( GetUns32AsIs(&thisEntry->bytes) > (this->tiffLength - GetUns32AsIs(&thisEntry->dataOrPos)) ) {
					// thisEntry->bytes = thisEntry->dataOrPos = 0;	// Make this bad tag look empty.
					memset ( tempEntryByte, 0, sizeof(XMP_Uns32) );
					memset ( tempEntryDataOrPos, 0, sizeof(XMP_Uns32) );
				}
			}
	
		#endif

	}

	ifdPtr += (2 + ifdCount*12);
	XMP_Uns32 nextIFDOffset = this->GetUns32 ( ifdPtr );

	if ( needsSorting ) SortIFD ( &ifdInfo );	// ! Don't perturb the ifdCount used to find the next IFD offset.

	return nextIFDOffset;

}	// TIFF_MemoryReader::ProcessOneIFD
예제 #6
0
void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
{
	// Get rid of any current TIFF.

	if ( this->ownedStream ) free ( this->tiffStream );
	this->ownedStream = false;
	this->tiffStream  = 0;
	this->tiffLength  = 0;

	for ( size_t i = 0; i < kTIFF_KnownIFDCount; ++i ) {
		this->containedIFDs[i].count = 0;
		this->containedIFDs[i].entries = 0;
	}

	if ( length == 0 ) return;

	// Allocate space for the full in-memory stream and copy it.

	if ( ! copyData ) {
		XMP_Assert ( ! this->ownedStream );
		this->tiffStream = (XMP_Uns8*) data;
	} else {
		if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based TIFF", kXMPErr_BadTIFF );
		this->tiffStream = (XMP_Uns8*) malloc(length);
		if ( this->tiffStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
		memcpy ( this->tiffStream, data, length );	// AUDIT: Safe, malloc'ed length bytes above.
		this->ownedStream = true;
	}

	this->tiffLength = length;
	XMP_Uns32 ifdLimit = this->tiffLength - 6;	// An IFD must start before this offset.

	// Find and process the primary, Exif, GPS, and Interoperability IFDs.

	XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->tiffStream, length );
	XMP_Uns32 tnailIFDOffset   = 0;

	if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
	
	// ! Need the thumbnail IFD for checking full Exif APP1 in some JPEG files!
	if ( tnailIFDOffset != 0 ) {
		if ( IsOffsetValid(tnailIFDOffset, 8, ifdLimit ) ) { 	// Ignore a bad Thumbnail IFD offset.
			(void) this->ProcessOneIFD ( tnailIFDOffset, kTIFF_TNailIFD );
		} else {
			XMP_Error error ( kXMPErr_BadTIFF, "Bad IFD offset" );
			this->NotifyClient (kXMPErrSev_Recoverable, error );
		}
	}

	const TweakedIFDEntry* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
	if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (GetUns32AsIs(&exifIFDTag->bytes) == 4) ) {
		XMP_Uns32 exifOffset = this->GetUns32 ( &exifIFDTag->dataOrPos );
		(void) this->ProcessOneIFD ( exifOffset, kTIFF_ExifIFD );
	}

	const TweakedIFDEntry* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
	if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (GetUns32AsIs(&gpsIFDTag->bytes) == 4) ) {
		XMP_Uns32 gpsOffset = this->GetUns32 ( &gpsIFDTag->dataOrPos );
		if ( IsOffsetValid ( gpsOffset, 8, ifdLimit ) ) {	// Ignore a bad GPS IFD offset.
			(void) this->ProcessOneIFD ( gpsOffset, kTIFF_GPSInfoIFD );
		} else {
			XMP_Error error ( kXMPErr_BadTIFF, "Bad IFD offset" );
			this->NotifyClient (kXMPErrSev_Recoverable, error );
		}
	}

	const TweakedIFDEntry* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
	if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (GetUns32AsIs(&interopIFDTag->bytes) == 4) ) {
		XMP_Uns32 interopOffset = this->GetUns32 ( &interopIFDTag->dataOrPos );
		if ( IsOffsetValid ( interopOffset, 8, ifdLimit ) ) {	// Ignore a bad Interoperability IFD offset.
			(void) this->ProcessOneIFD ( interopOffset, kTIFF_InteropIFD );
		} else {
			XMP_Error error ( kXMPErr_BadTIFF, "Bad IFD offset" );
			this->NotifyClient (kXMPErrSev_Recoverable, error );
		}
	}

}	// TIFF_MemoryReader::ParseMemoryStream