mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ifdgeneral.cpp
branchRCL_3
changeset 50 948c7f65f6d4
parent 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ifdgeneral.cpp	Wed Sep 01 12:38:50 2010 +0100
@@ -0,0 +1,1817 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "ifdgeneral.h"
+#include "ifdgeneralentry.h"
+#include "ExifTagDescriptions.h"
+#include "exifreaderwriter.h"
+#include "ExifTagHelper.h"
+#include <bafl/sysutil.h>
+
+// Number of consecutive invalid IFD entries that may appear before the whole IFD is considered corrupt
+// This value is set in the ExifLibStatic.mmp file, the default is 7.
+const TUint KMaxNumberOfConsecInvalidEntries = SYMBIAN_ICL_EXIF_CONSEC_INVALID_TAGS;
+
+CIfdGeneral::CIfdGeneral(const TInt aIfdNumber, const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: iIfdNumber(aIfdNumber)
+	, iIntel(aIntel)
+	, iOffsetToIfd(aOffsetToIfd)
+	, iBase(aBase)
+	, iExifDataLength(aExifDataLength)
+	{	
+	}
+
+CIfdGeneral::~CIfdGeneral()
+	{
+	iIfdEntries.ResetAndDestroy();
+	}
+	
+void CIfdGeneral::ConstructL()
+	{
+	if(iBase)
+		{
+		// read the entries from the data block
+		AddAllIfdEntriesL();
+		}
+	else
+		{
+		// create default entries
+		SetupDirectoryEntriesL();
+		}
+	}
+
+// Alters a directory in a given IFD - used when the directory is known to exist 
+// (i.e. for mandatory entries) which are set/created upon initialisation.
+TInt CIfdGeneral::SetParam8(const TUint aTag, HBufC8* aParam)
+	{	
+	ASSERT(aParam!=NULL);
+		
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			// May be undefined type or ascii type.
+			if(iIfdEntries[i]->IsStringFormat())
+				{
+				//pass in ifd number as the same ascii tag may be in more than one ifd
+				return iIfdEntries[i]->UpdateString(aParam);				
+				}
+			else if(iIfdEntries[i]->IsUndefinedFormat())
+				{
+				return iIfdEntries[i]->UpdateData(aParam->Length(), aParam->Des().Ptr());	
+				}
+			else if (iIfdEntries[i]->Format()==EByte)
+				{
+				//we need to support byte entries too as they are Param8
+				return iIfdEntries[i]->UpdateData(aParam->Length(), aParam->Des().Ptr());
+				}			
+			}
+		}
+	return KErrNotSupported;
+	}
+	
+TInt CIfdGeneral::SetParam16(const TUint aTag, HBufC16* aParam)
+	{	
+	ASSERT(aParam!=NULL);
+			
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.			
+			HBufC8* extendedData=NULL;
+			TRAPD(err, extendedData=TExifTagHelper::CreateUnicodePrefixedBufferL(*aParam));
+			if(err!=KErrNone)
+				{
+				return KErrNoMemory;
+				} 
+			TInt componentCount=extendedData->Length();
+			TInt updateErr = iIfdEntries[i]->UpdateData(componentCount, extendedData->Des().Ptr()); 
+			delete extendedData;		
+			return updateErr;
+			}
+		}
+	return KErrNotSupported;
+	}
+	
+TInt CIfdGeneral::SetIntegerParam(const TUint aTag, const TInt aParam)
+	{
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			return iIfdEntries[i]->UpdateInteger(aParam);
+			}
+		}
+	return KErrNotSupported;
+	}
+	
+TInt CIfdGeneral::SetShortParam(const TUint aTag, const TUint16 aParam)
+	{
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			return iIfdEntries[i]->UpdateShort(aParam);
+			}
+		}
+	return KErrNotSupported;
+	}
+
+TInt CIfdGeneral::SetRationalParam(const TUint aTag, const TInt aNumerator, const TInt aDenominator)
+	{
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			return iIfdEntries[i]->UpdateRational(aNumerator, aDenominator);
+			}
+		}
+	return KErrNotSupported;
+	}
+
+
+/* 
+Add a directory in a given IFD - used for the optional directories, since these are not
+set/created upon initialisation.  Must check for existence of the tag along with validity
+of adding the tag to this particular IFD.
+*/
+void CIfdGeneral::AddParam8L(const TUint aTag, const TUint aFormat, const TUint aComponentCount, HBufC8* aParam)
+	{
+	ASSERT(aParam!=NULL);
+		
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	TInt index = GetTagIndex(aTag);
+	if(index != KErrNotFound)
+		{
+		//The length is checked, but really it should be done in the IfdEntry
+		TUint paramLength=aParam->Length();
+		const TUint* tag = GetTagInformation(index);
+		TUint requiredComponentCount=tag[EComponentCountValue];
+		TBool legal=EFalse;
+		if((requiredComponentCount==0) || (aFormat!=EAscii))
+			{
+			//Either this tag can be of any length (so no further length checks needed)
+			//or it is not ASCII, which means it simply has to be at least as long
+			//as the required length
+			legal=(paramLength >= requiredComponentCount * KDataFormatSize[aFormat]);	
+			}
+		else
+			{
+			//We have a fixed length ASCII string.  For such strings we must
+			//consider NULL termination.  Considering that we add the NULL if the 
+			//user forgets to add it for other tags, we should do it here as well 
+			//to be consistent.
+			if (paramLength==requiredComponentCount)
+				{
+				//The string is already of the max length so it is only legal if it is NULL
+				//terminated
+				legal=((*aParam)[paramLength-1] == KNullCharacter);	
+				}
+			else if (paramLength==requiredComponentCount-1)
+				{
+				//The string is one less than the required length.  If it is NULL terminated already,
+				//then the string is too short (illegal).  If it is not NULL terminated, we let it
+				//pass anyway and CEncoderIfdEntry software will add the NULL.  
+				legal=((*aParam)[paramLength-1] != KNullCharacter);						
+				}
+			else
+				{
+				//Strings that pass the first two checks are only legal if exactly the
+				//required length.
+				legal=(paramLength == requiredComponentCount);	
+				}
+			}
+		if (legal)				
+			{
+			// Entry is legal, so add entry.
+			const TUint8* valueOffset = aParam->Des().Ptr();			
+			CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aComponentCount, valueOffset, this);
+			iIfdEntries.AppendL(entry);
+			CleanupStack::Pop(entry);
+			err = KErrNone;
+			}
+		else
+			{
+			err = KErrNotSupported;
+			}
+		}
+	User::LeaveIfError(err);
+	}
+	
+void CIfdGeneral::AddParam16L(const TUint aTag, const TUint aFormat, const TUint /*aComponentCount*/, HBufC16* aParam)
+	{
+	ASSERT(aParam!=NULL);
+		
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	TInt index = GetTagIndex(aTag);
+	if(index != KErrNotFound)
+		{	
+		TUint paramLength=aParam->Length();
+		const TUint* tag = GetTagInformation(index);
+		if( (paramLength >= tag[EComponentCountValue] * KDataFormatSize[aFormat]))
+			{				
+			
+			// Entry is legal, so add entry.
+			// Must add UNICODE\0 to start of data.				
+			TInt size = aParam->Length()*2 + KUnicode().Length();
+			TUint8* data = static_cast<TUint8*>(User::AllocL(size));								
+			CleanupStack::PushL(data);
+			
+			Mem::Copy(data, KUnicode().Ptr(), KUnicode().Length());
+			Mem::Copy(data+KUnicode().Length(), aParam->Des().Ptr(), aParam->Length()*2);												
+			
+			CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, size, data, this);
+			iIfdEntries.AppendL(entry);
+			CleanupStack::Pop(entry);
+			CleanupStack::PopAndDestroy(data);
+			err = KErrNone;		
+			}
+		} 
+	User::LeaveIfError(err);
+	}
+
+	
+void CIfdGeneral::AddIntegerParamL(const TUint aTag, const TUint aFormat, const TUint aComponentCount, TInt aParam)
+	{
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		// Entry is legal, so add entry.
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aComponentCount, reinterpret_cast<const TUint8*>(&aParam), this);
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		err = KErrNone;		
+		} 
+	User::LeaveIfError(err);
+	}
+	
+void CIfdGeneral::AddShortParamL(const TUint aTag, const TUint aFormat, const TUint aComponentCount, TUint16 aParam)
+	{
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		// Entry is legal, so add entry.
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aComponentCount, reinterpret_cast<const TUint8*>(&aParam),this);
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		err = KErrNone;		
+		} 
+	User::LeaveIfError(err);
+	}
+	
+void CIfdGeneral::AddRationalParamL(const TUint aTag, const TUint aFormat, const TUint aComponentCount, const TInt aNumerator, const TInt aDenominator)
+	{
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		TUint8* valueOffset = static_cast<TUint8*>(User::AllocL(KSizeOfRational));
+		CleanupStack::PushL(valueOffset);
+		
+		// Entry is legal, so add entry.
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aComponentCount, valueOffset, this);
+		User::LeaveIfError(entry->UpdateRational(aNumerator, aDenominator));
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		CleanupStack::PopAndDestroy(valueOffset);
+	
+		err = KErrNone;			
+		} 
+	if(err != KErrNone)
+		{
+		User::LeaveIfError(err);			
+		}
+	return;
+	}
+
+
+
+void CIfdGeneral::SetIntegerArrayParamL(const TUint aTag, const CArrayFix<TInt>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			HBufC8* ptr = HBufC8::NewL(aParam.Count()*K32BitIntegerByteCount/K8BitIntegerByteCount);
+			CleanupStack::PushL(ptr);
+			const TUint8* bytePtr = ptr->Des().Ptr();
+			TInt* dataPtr = const_cast<TInt*>(reinterpret_cast<const TInt*>(bytePtr));								
+			for(TInt j = 0; j < aParam.Count(); j++)
+				{
+				TInt value = aParam.At(j);
+				dataPtr[j] = value;
+				}
+			User::LeaveIfError(iIfdEntries[i]->UpdateData(aParam.Count(), bytePtr));
+			CleanupStack::PopAndDestroy(ptr);
+			err = KErrNone;
+			}
+		}
+	User::LeaveIfError(err);
+	}
+
+void CIfdGeneral::AddIntegerArrayParamL(const TUint aTag, const TUint aFormat, const CArrayFix<TInt>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		// Entry is legal, so add entry.
+		HBufC8* ptr = HBufC8::NewL(aParam.Count()*K32BitIntegerByteCount/K8BitIntegerByteCount);
+		CleanupStack::PushL(ptr);
+		const TUint8* bytePtr = ptr->Des().Ptr();
+		TInt* dataPtr = const_cast<TInt*>(reinterpret_cast<const TInt*>(bytePtr));								
+		for(TInt i = 0; i < aParam.Count(); i++)
+			{
+			TInt value = aParam.At(i);
+			dataPtr[i] = value;
+			}
+
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aParam.Count(), bytePtr, this);								
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		CleanupStack::PopAndDestroy(ptr);
+		err = KErrNone;					
+		}
+	User::LeaveIfError(err);
+	}
+
+void CIfdGeneral::AddRationalArrayParamL(const TUint aTag, const TUint aFormat, const CArrayFix<TRational>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		// Entry is legal, so add entry.
+		HBufC8* ptr = HBufC8::NewL((aParam.Count()*2) * K32BitIntegerByteCount);
+		CleanupStack::PushL(ptr);
+		const TUint8* bytePtr = ptr->Des().Ptr();
+		TInt* dataPtr = const_cast<TInt*>(reinterpret_cast<const TInt*>(bytePtr));
+		TInt ptrInc = 0;
+		for(TInt i = 0; i < aParam.Count(); i++)
+			{
+			TInt numer = (aParam.At(i)).iNumerator;
+			TInt denom = (aParam.At(i)).iDenominator;
+			dataPtr[ptrInc++] = numer;
+			dataPtr[ptrInc++] = denom;
+			}
+
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aParam.Count(), bytePtr, this);								
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		CleanupStack::PopAndDestroy(ptr);
+		err = KErrNone;						
+		} 
+	User::LeaveIfError(err);
+	}
+	
+void CIfdGeneral::SetRationalArrayParamL(const TUint aTag, const CArrayFix<TRational>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	// find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			// Found the tag.
+			HBufC8* ptr = HBufC8::NewL((aParam.Count()*2) * K32BitIntegerByteCount);
+			CleanupStack::PushL(ptr);
+			const TUint8* bytePtr = ptr->Des().Ptr();
+			TInt* dataPtr = const_cast<TInt*>(reinterpret_cast<const TInt*>(bytePtr));
+			TInt ptrInc = 0;
+			for(TInt j = 0; j < aParam.Count(); j++)
+				{
+				TInt numer = (aParam.At(j)).iNumerator;
+				TInt denom = (aParam.At(j)).iDenominator;
+				dataPtr[ptrInc++] = numer;
+				dataPtr[ptrInc++] = denom;
+				}
+			User::LeaveIfError(iIfdEntries[i]->UpdateData(aParam.Count(), bytePtr));
+			CleanupStack::PopAndDestroy(ptr);
+			err = KErrNone;
+			}
+		}
+	User::LeaveIfError(err);
+	}
+	
+	
+void CIfdGeneral::AddShortArrayParamL(const TUint aTag, const TUint aFormat, const CArrayFix<TUint16>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	// Check that aTag belongs in this IFD.
+	if(FindTag(aTag))
+		{
+		// Entry is legal, so add entry.
+		HBufC8* ptr = HBufC8::NewL(aParam.Count()*K16BitIntegerByteCount/K8BitIntegerByteCount);
+		CleanupStack::PushL(ptr);
+		const TUint8* bytePtr = ptr->Des().Ptr();
+		TInt16* dataPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(bytePtr));								
+		for(TInt i = 0; i < aParam.Count(); i++)
+			{
+			TInt value = aParam.At(i);
+			dataPtr[i] = value;
+			}
+
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(aTag, aFormat, aParam.Count(), bytePtr, this);								
+		iIfdEntries.AppendL(entry);
+		CleanupStack::Pop(entry);
+		CleanupStack::PopAndDestroy(ptr);
+		err = KErrNone;							
+		} 
+	User::LeaveIfError(err);
+	}
+
+void CIfdGeneral::SetShortArrayParamL(const TUint aTag, const CArrayFix<TUint16>& aParam)
+	{
+	TInt err = KErrNotSupported;
+	// Find the entry with the required tag.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			HBufC8* ptr = HBufC8::NewL(aParam.Count()*K16BitIntegerByteCount/K8BitIntegerByteCount);
+			CleanupStack::PushL(ptr);
+			const TUint8* bytePtr = ptr->Des().Ptr();
+			TInt16* dataPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(bytePtr));								
+			for(TInt j = 0; j < aParam.Count(); j++)
+				{
+				TInt value = aParam.At(j);
+				dataPtr[j] = value;
+				}
+			User::LeaveIfError(iIfdEntries[i]->UpdateData(aParam.Count(), bytePtr));
+			CleanupStack::PopAndDestroy(ptr);
+			err = KErrNone;
+			}		
+		}
+	User::LeaveIfError(err);
+	}	
+
+TInt CIfdGeneral::GetIntegerParam(const TUint aTag, TInt& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+	
+	// Check that we are dealing with an Integer format.
+	switch(iIfdEntries[entry]->Format())
+		{		
+		case (EUnsignedLong):
+		case (ESignedLong):
+			break;
+		default:
+			return KErrArgument;
+		}
+
+	// Check the size.
+	TUint totalSize = iIfdEntries[entry]->ComponentCount() * KDataFormatSize[iIfdEntries[entry]->Format()];
+	if(totalSize > KSizeOfValueOffsetField)
+		{
+		// Data is offset, so we are dealing with more than one integer, so this function cannot deal with it.
+		return KErrArgument;
+		}
+	
+	aParam = iIfdEntries[entry]->ValueOffset();
+	return KErrNone;
+	}
+	
+	
+
+
+TInt CIfdGeneral::GetShortParam(const TUint aTag, TUint16& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+	
+	// Check that we are dealing with an short format.
+	if(iIfdEntries[entry]->Format() != EUnsignedShort)
+		{
+		return KErrArgument;
+		}
+
+	// Check the size.
+	TUint totalSize = iIfdEntries[entry]->ComponentCount() * KDataFormatSize[iIfdEntries[entry]->Format()];
+
+	 // Since 2 shorts could be in 4 byte field, we only return one!
+	if(totalSize > KSizeOfValueOffsetField / 2)
+		{
+		// Data is offset, so we are dealing with more than one integer, so this function cannot deal with it.
+		return KErrArgument;
+		}
+	
+	aParam = iIfdEntries[entry]->ValueOffset();
+
+	return KErrNone;
+	}
+
+TInt CIfdGeneral::GetRationalParam(const TUint aTag, TInt& aNumer, TInt& aDenom) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+	
+	// Check that we are dealing with an rational format.
+	switch(iIfdEntries[entry]->Format())
+		{
+		case (EUnsignedRational):
+		case (ESignedRational):
+			break;
+		default:
+			return KErrArgument;
+		}
+
+	// Check the size.
+	TUint totalSize = iIfdEntries[entry]->ComponentCount() * KDataFormatSize[iIfdEntries[entry]->Format()];
+
+	// A single rational datum is 8 bytes, so we only deal with single values here.
+	if(totalSize > KSizeOfValueOffsetField * 2)
+		{
+		return KErrArgument;
+		}
+	
+	const TUint8* rationalData = iIfdEntries[entry]->ActualValue();
+	if(!rationalData)
+		{
+		return KErrArgument;
+		}
+	Mem::Copy(&aNumer, rationalData, sizeof(aNumer));
+	Mem::Copy(&aDenom, rationalData+sizeof(aNumer), sizeof(aDenom));
+	return KErrNone;
+	}
+
+TInt CIfdGeneral::GetParam8(const TUint aTag, HBufC8*& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+	
+	// Check that we are dealing with correct format.
+	TUint format = iIfdEntries[entry]->Format();
+	switch(format)
+		{
+		case (EByte):
+		case (EAscii):
+		case (EUndefined):
+			break;
+		default:
+			return KErrArgument;
+		}
+
+	// Check the size.
+	TUint totalSize = iIfdEntries[entry]->ComponentCount();
+	
+	delete aParam;
+	aParam = HBufC8::New(totalSize);				
+	if(aParam == NULL)
+		{
+		return KErrNoMemory;
+		}
+		
+	_LIT8(KStringFormat, "%s");
+	if(totalSize > KSizeOfValueOffsetField)
+		{
+		const TUint8* theData=iIfdEntries[entry]->ActualValue();
+		if(!theData)
+			{
+			return KErrArgument;
+			}
+
+		if (aTag == KTag8298[ETagValue])
+			{
+			//the copyright tag is a special case as it can have null mid string
+			if (*(theData+totalSize-1) == NULL)
+				{
+				//we remove null at the end for consistency
+				totalSize--;
+				}
+			aParam->Des().Copy(theData, totalSize);	
+			}
+		else if (format == EAscii)
+			{
+			aParam->Des().Format(KStringFormat, theData);
+			}
+		else
+			{
+			aParam->Des().Copy(theData, totalSize);	
+			}
+		}
+	else if (totalSize>0)
+		{
+		// Get data from value/offset field.
+		TInt value = iIfdEntries[entry]->ValueOffset();
+
+		if (aTag == KTag8298[ETagValue])
+			{
+			//the copyright tag is a special case as it can have null mid string
+			//note we would only get here if the copyright was <= 4 bytes
+			if (*(reinterpret_cast<TUint8*>(&value)+totalSize-1) == NULL)
+				{
+				//we remove null at the end for consistency
+				totalSize--;
+				}
+			aParam->Des().Copy(reinterpret_cast<TUint8*> (&value), totalSize);	
+			}
+		else if (format == EAscii)
+			{
+			aParam->Des().Format(KStringFormat, reinterpret_cast<TUint8*> (&value));
+			}
+		else
+			{
+			aParam->Des().Copy(reinterpret_cast<TUint8*> (&value), totalSize);
+			}
+		}
+	return KErrNone;
+	}
+
+TInt CIfdGeneral::GetParam16(const TUint aTag, HBufC16*& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+	
+	// Check that we are dealing with the undefined format.
+	switch(iIfdEntries[entry]->Format())
+		{
+		case (EUndefined):
+			break;
+		default:
+			return KErrArgument;
+		}
+
+	// Check the size.
+	const TInt totalByteSize = iIfdEntries[entry]->ComponentCount();
+	
+	delete aParam;
+	aParam = HBufC16::NewMax((totalByteSize+1)>>1);
+	if(aParam == NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	TPtr ptr(aParam->Des());
+	Mem::Copy(reinterpret_cast<TText8*>(&ptr[0]), iIfdEntries[entry]->ActualValue(), totalByteSize);
+
+	return KErrNone;
+	}
+
+void CIfdGeneral::GetIntegerArrayParamL(const TUint aTag, CArrayFix<TInt>& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		User::Leave(KErrNotFound);
+		}
+	
+	// Check that we are dealing with an Integer format.
+	switch(iIfdEntries[entry]->Format())
+		{
+		case (EUnsignedLong):
+		case (ESignedLong):
+			break;
+		default:
+			User::Leave(KErrArgument);
+		}
+
+	// Check the size.
+	TUint totalSize = iIfdEntries[entry]->ComponentCount() * KDataFormatSize[iIfdEntries[entry]->Format()];
+	if(totalSize > KSizeOfValueOffsetField)
+		{
+		// Obviously have multiple entries.
+		// However, as of Exif 2.2 there are no Integer Array tags defined that have
+		// more than one entry.
+		TInt numberOfInts = totalSize / KDataFormatSize[iIfdEntries[entry]->Format()];
+		aParam.ResizeL(numberOfInts);
+		const TUint8* dataStream = iIfdEntries[entry]->ActualValue();
+		if(!dataStream)
+			{
+			User::Leave(KErrArgument);
+			}
+
+		TInt value = 0;
+		for(TInt i = 0; i < numberOfInts; i++)
+			{
+			Mem::Copy(&value, dataStream, sizeof(value));
+			aParam[i] = value;
+			dataStream += sizeof(value);
+			}
+		}
+	else
+		{
+		// A single entry
+		aParam.ResizeL(1);
+		aParam[0] = iIfdEntries[entry]->ValueOffset();
+		}
+	}
+
+void CIfdGeneral::GetShortArrayParamL(const TUint aTag, CArrayFix<TUint16>& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	// Check that we are dealing with an Short format.
+	TUint format = iIfdEntries[entry]->Format();
+	if(format != EUnsignedShort)
+		{
+		User::Leave(KErrArgument);
+		}
+		
+	// Check the size.
+	TUint componentCount = iIfdEntries[entry]->ComponentCount();
+	TUint dataSize = KDataFormatSize[format];
+	TUint totalSize = componentCount * dataSize;	
+	if(totalSize > KSizeOfValueOffsetField)
+		{
+		// Obviously have multiple entries.
+		aParam.ResizeL(componentCount);
+		const TUint8* dataStream = iIfdEntries[entry]->ActualValue();
+		if(dataStream==NULL)
+			{
+			User::Leave(KErrArgument);
+			}
+
+		TUint16 value = 0;
+		for(TInt i = 0; i < componentCount; i++)
+			{
+			Mem::Copy(&value, dataStream, sizeof(value));
+			aParam[i] = value;
+			dataStream += sizeof(value);
+			}
+		}
+	else
+		{
+		// Either one or two entries
+		ASSERT((componentCount==1) || (componentCount==2));
+		aParam.ResizeL(componentCount);
+		TUint value = iIfdEntries[entry]->ValueOffset();
+		
+		// When component count is 1, we read a UShort as a UShort,
+		// so the byte order is correct on return.
+		//
+		// When component count is 2, we read the UShorts as a UInt.
+		// i.e. Data is stored on DISK as TWO Shorts but read as ONE TUint32.
+		//
+		// Example representation of data on Disk:
+		//    0x0300 0x0500 (Intel II LittleEndian) - 0x0003 & 0x0005 (Motorola MM BigEndian)
+		//
+		// For Intel data, it is read in as an Intel UInt and the bytes reversed. 
+		// This is important as a pointer is usually stored here:
+		//    0x0300 0500  becomes  0x0005 0003
+		//
+
+		// For Big-endian formatted files
+		TUint32 highOrderShortMask = 0xFFFF0000;
+		TUint32 lowOrderShortMask  = 0x0000FFFF;
+		
+		if (componentCount==1)
+			{
+			aParam[0] = (value & lowOrderShortMask);
+			}
+		else
+			{
+			if(iIntel)	
+				{ // II format
+				aParam[0] = (value & lowOrderShortMask);				
+				aParam[1] = (value & highOrderShortMask) >> 16;									
+				}				
+			else
+				{ // MM format
+				aParam[0] = (value & highOrderShortMask) >> 16;									
+				aParam[1] = (value & lowOrderShortMask);				
+				}
+			}
+		}
+   	}
+
+void CIfdGeneral::GetRationalArrayParamL(const TUint aTag, CArrayFix<TRational>& aParam) const
+	{
+	TInt entry = LocateEntry(aTag);
+	if(entry == KErrNotFound)
+		{
+		User::Leave(KErrNotFound);
+		}
+	
+	// Check that we are dealing with an Rational format.
+	switch(iIfdEntries[entry]->Format())
+		{
+		case (EUnsignedRational):
+		case (ESignedRational):
+			break;
+		default:
+			User::Leave(KErrArgument);
+		}
+
+	// Check the size.
+	TInt totalSize = iIfdEntries[entry]->ComponentCount() * KDataFormatSize[iIfdEntries[entry]->Format()];
+	// Obviously have multiple entries.
+	TInt numberOfRationalValues = totalSize / KDataFormatSize[iIfdEntries[entry]->Format()];
+	aParam.ResizeL(numberOfRationalValues);
+	const TUint8* dataStream = iIfdEntries[entry]->ActualValue();
+	if(!dataStream)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	TRational rational;
+	for(TInt i = 0; i < numberOfRationalValues; i++)
+		{
+		Mem::Copy(&rational.iNumerator, dataStream, sizeof(rational.iNumerator));
+		Mem::Copy(&rational.iDenominator, dataStream+sizeof(rational.iNumerator), sizeof(rational.iDenominator));
+		aParam[i] = rational;
+		dataStream += sizeof(rational.iNumerator) + sizeof(rational.iDenominator); // Move pointer on 8 bytes.
+		}
+	}
+
+TInt CIfdGeneral::Size() const
+	{
+	TUint totalSize = 0;
+	// Get the size of each directory entry.
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		TInt size = iIfdEntries[i]->TotalSize();
+		totalSize+=size;				
+		}
+	return totalSize;
+	}
+	
+	
+
+// Can only be called by the 0th Ifd (otherwise returns KErrNotSupported).
+TInt CIfdGeneral::GetOffsetToFirstIfd(TUint& aOffset) const
+	{
+	if(iIfdNumber == 0)
+		{
+		aOffset = CExifReaderWriter::ReadUint32(iIntel, iBase +
+													(iIfdEntryCount * KMinimumIfdEntrySize)+
+													sizeof(TUint16)+
+													iOffsetToIfd);		
+		return KErrNone;
+		}
+	return KErrNotSupported;
+	}
+
+/**
+	Parses the buffer, extracting the data.
+	Ignores corrupt IFD entries (e.g. one with a value offset that is beyond the buffer's boundaries)
+	unless more than KMaxNumberOfConsecInvalidEntries invalid entries appear in succession. In that case
+	the whole IFD is considered corrupt.
+	
+	@leave	KErrNoMemory	If there is insufficient memory to process the data
+	@leave	KErrCorrupt		If there are more than KMaxNumberOfConsecInvalidEntries consecutive
+							corrupt entries
+*/
+void CIfdGeneral::AddAllIfdEntriesL()
+	{
+	// Set the Ifd entry count.
+	iIfdEntryCount = CExifReaderWriter::ReadUint16(iIntel, iBase + iOffsetToIfd);
+	
+	const TUint8* ifdPtr = iBase + iOffsetToIfd + sizeof(iIfdEntryCount);
+	
+	//check for the validity of the iIfdEntryCount
+	if(!IsValidIfdEntryCount(iIfdEntryCount))
+		{//most likely an invalid exif header
+		User::Leave(KErrCorrupt);		
+		}
+
+	// records if an entry is corrupt
+	TBool ifdEntryIsCorrupt = EFalse;
+	
+	// counter to track the number of consec corrupt ifd entries
+	// if more than KMaxNumberOfConsecInvalidEntries corrupt ifd entries occurr in a
+	// row then the entire IFD is deemed to be corrupt and all the iIfdEntries are to
+	// be deleted
+	TUint numberOfConsecutiveCorruptIfdEntries = 0;
+
+	// initialise the offset, which acts as a pointer increment.
+	TInt offset = 0;
+	for(TInt ifdEntry = 0; ifdEntry < iIfdEntryCount; ifdEntry++)
+		{
+		ifdEntryIsCorrupt = EFalse;
+		
+		// Create the new CIfdEntry to populate.
+
+		// Set the general data of the Ifd entry.
+		TUint16 tag = CExifReaderWriter::ReadUint16(iIntel, ifdPtr + offset+KTagFieldPosition);
+		TUint16 format = CExifReaderWriter::ReadUint16(iIntel, ifdPtr + offset+KFormatFieldPosition);
+		TUint componentCount = CExifReaderWriter::ReadUint32(iIntel, ifdPtr + offset+KComponentCountFieldPosition);
+
+		// Determine if the data is held in the value/offset or if it is pointed to.
+		TUint totalSize = 0;
+		
+		TUint valueOffset;
+		TBool endianess = iIntel;
+		const TUint8* valuePtr = NULL;
+			
+		if (!(format < KDataFormatSizeLength) ||
+			((totalSize = componentCount * KDataFormatSize[format]) > iExifDataLength) ||
+			(totalSize == 0) ||
+			(tag == NULL && !AllowNullTags())) //null tag is valid for GPS IFD
+			{
+			// if invalid format or size is unreasonable this IFD entry is corrupt
+			// (second check is a bit crude but worthwhile since it
+			//  can catch some obviously invalid entries early on)
+			ifdEntryIsCorrupt = ETrue;
+			}
+		else
+			{
+			if (((format == EAscii)||(format == EByte)||(format == EUndefined)) && (totalSize <= KSizeOfValueOffsetField))
+				{
+				//If the above condition is true then the data is such that it needs to 
+				//keep the byte order as is ie an ASCII field, a byte field or an undefined field
+				//if this is the case we do not want to invert the bytes for big endian/motorola
+				//ie order is unchanged
+				//if the data is greater than 4 bytes then it should be copied across as is
+				endianess = ETrue; //so set endianess to Intel even if the file is motorola
+				}
+			if(totalSize <= sizeof(TUint16))
+				{
+				valueOffset = CExifReaderWriter::ReadUint16(endianess, ifdPtr + offset+KValueOffsetFieldPosition);
+				}
+			else
+				{
+				valueOffset = CExifReaderWriter::ReadUint32(endianess, ifdPtr + offset+KValueOffsetFieldPosition);
+				}
+					
+			if (totalSize>KSizeOfValueOffsetField)
+				{
+				if((valueOffset) && ((valueOffset + totalSize) <= iExifDataLength))
+					{
+					valuePtr = iBase+valueOffset;
+					}
+				else
+					{
+					// the offset is either null, pointing beyond the length of the exif data or
+					// pointing to a value which goes beyond the length of the exif data
+					// ie we are dealing with a corrupt entry
+					ifdEntryIsCorrupt = ETrue;
+					}
+				}
+			else
+				{
+				valuePtr = reinterpret_cast<const TUint8*> (&valueOffset);
+				}
+			}
+			
+		// try to make the entry
+		CIfdGeneralEntry* entry = NULL;
+		if(!ifdEntryIsCorrupt)
+			{
+			// entries with unknown tags are created but count towards corrupt entries
+			// so that if many appear in succession we assume the IFD is corrupt
+			entry = CreateIfdEntryLC(tag, format, componentCount, valuePtr, valueOffset, totalSize, ifdEntryIsCorrupt);
+			
+			if(!entry)
+				{
+				ifdEntryIsCorrupt = ETrue;
+				}
+			}		
+			
+		//an entry of all 0's could be padding so don't count it as corrupt
+		if ((ifdEntryIsCorrupt) && !((tag == 0)&&(format == 0)&&(componentCount == 0)))
+			{
+			numberOfConsecutiveCorruptIfdEntries++;
+			if ((numberOfConsecutiveCorruptIfdEntries == iIfdEntryCount)||(numberOfConsecutiveCorruptIfdEntries > KMaxNumberOfConsecInvalidEntries))
+				{
+				//if the above condition is true then it is likely that we are scanning the IFD from the offset
+				//or that the data is non IFD
+				//so we will skip further processing of the IFD and abandon
+				User::Leave(KErrCorrupt);
+				}
+			}
+		else
+			{
+			numberOfConsecutiveCorruptIfdEntries = 0; //reset
+			}
+			
+		if (entry)
+			{//always ensure entry is valid before appending - might not be if we have a null tag
+			iIfdEntries.AppendL(entry);
+			CleanupStack::Pop(entry);
+			}
+
+		offset += KMinimumIfdEntrySize;
+		}
+	
+	// All entries have now been added.	
+	}
+	
+/**
+	Creates an IFD entry and pushes it onto the cleanup stack.
+	If the entry cannot be created (most likely due to some
+	corrupt data) NULL will be returned.
+	
+	@param	aTag			EXIF tag number for this entry
+	@param	aFormat			Format of this entry's data
+	@param	aComponentCount	Number of values in the data
+	@param	aValuePtr		Pointer to the start of the data
+	@param	aValueOffset	Offset from start of EXIF data to start of entry data
+	@param	aTotalSize		Length of the data
+	@param	aUnknownTag		Set to ETrue if the entry's tag is unknown (for this IFD),
+							EFalse otherwise.
+	
+	@return	The newly created entry or NULL if it could not be created.
+	
+	@leave	KErrNoMemory	If there wasn't sufficient memory to create entry. This
+							is the only type of leave this function can make.
+
+*/
+CIfdGeneralEntry* CIfdGeneral::CreateIfdEntryLC(const TUint& aTag, const TUint& aFormat, const TUint& aComponentCount, const TUint8* aValuePtr, TUint aValueOffset, TUint aTotalSize, TBool& aUnknownTag)
+	{
+	CIfdGeneralEntry* entry= NULL;
+	
+	TRAPD(err, entry = CIfdGeneralEntry::NewL(aTag, aFormat, aComponentCount, aValuePtr, this, aUnknownTag));
+	if (err != KErrNone)
+		{
+		if (err == KErrNoMemory)
+			{
+			User::Leave(err); //only leave if no memory
+			}
+		}
+	else
+		{
+		CleanupStack::PushL( entry );
+		// no errors so far, so read the entry's values
+		if(aTotalSize > KSizeOfValueOffsetField)
+			{
+			// Byte swap each component, if necessary.
+			TUint8* byteSwappedDataBuffer = static_cast<TUint8*>(User::AllocL(aTotalSize));
+			TUint8* tempPtr = byteSwappedDataBuffer;
+			TInt updateErr=KErrNone;
+			TInt i;
+			switch(aFormat)
+				{
+				case(EByte):
+				case(EAscii):
+				case(EUndefined):
+					updateErr = entry->SetActualData(iBase+aValueOffset, aComponentCount, KDataFormatSize[aFormat]);						
+					break;
+				case(EUnsignedRational):
+				case(ESignedRational):
+					// Comprised of 2 * 4-byte integers.
+					{
+					for(i = 0; i < aComponentCount; i++)
+						{
+						TUint numer = CExifReaderWriter::ReadUint32(iIntel, iBase + aValueOffset + 8*i);
+						TUint denom = CExifReaderWriter::ReadUint32(iIntel, iBase + aValueOffset + 8*i + 4);
+						tempPtr = Mem::Copy(tempPtr, &numer, sizeof(numer));
+						tempPtr = Mem::Copy(tempPtr, &denom, sizeof(denom));
+						}
+					updateErr = entry->SetActualData(byteSwappedDataBuffer, aComponentCount, KDataFormatSize[aFormat]);						
+					}
+					break;
+				case(EUnsignedLong):
+				case(ESignedLong):
+					{
+					for(i = 0; i < aComponentCount; i++)
+						{
+						TUint value = CExifReaderWriter::ReadUint32(iIntel, iBase + aValueOffset+(i*sizeof(value)));
+						tempPtr = Mem::Copy(tempPtr, &value, sizeof(value));
+						}
+					updateErr = entry->SetActualData(byteSwappedDataBuffer, aComponentCount, KDataFormatSize[aFormat]);						
+					}
+					break;
+				case(EUnsignedShort):
+					{
+					for(i = 0; i < aComponentCount; i++)
+						{
+						TUint16 value = CExifReaderWriter::ReadUint16(iIntel, iBase + aValueOffset+(i*sizeof(value)));
+						tempPtr = Mem::Copy(tempPtr, &value, sizeof(value));
+						}
+					updateErr = entry->SetActualData(byteSwappedDataBuffer, aComponentCount, KDataFormatSize[aFormat]);						
+					}
+					break;
+				default:
+					break;
+				}
+			User::Free(byteSwappedDataBuffer);
+			if(updateErr)
+				{
+				if(updateErr == KErrNoMemory)
+					{
+					User::Leave(KErrNoMemory);
+					}
+				else
+					{
+					// if we get here entry object was made, but data could not be set
+					// so we remove the entry object
+					CleanupStack::PopAndDestroy( entry );
+					entry = NULL;
+					}
+				}
+			} // end if(aTotalSize > KSizeOfValueOffsetField)
+		}
+
+		return entry;	
+	}
+	
+
+void CIfdGeneral::SetupDirectoryEntriesL()
+	{
+	// Loop through all legal tags.
+	for(TInt i = 0; i < GetNumberOfValidTags(); i++)
+		{
+		const TUint* tagInfo = GetTagInformation(i);
+		// Only initialise the default Ifd with Mandatory tags.
+		if (tagInfo[ESupportLevelValue] == EMandatory)
+			{
+			TUint temp = tagInfo[EValueOffsetValue];
+			TUint8* valueOffset = reinterpret_cast<TUint8*>(&temp);
+			
+			TUint format = tagInfo[EFormatValue];
+			TUint componentCount = tagInfo[EComponentCountValue];
+			if (format == EAscii)
+				{
+				valueOffset = reinterpret_cast<TUint8*> (temp);
+				componentCount = 0;
+
+				TUint8* strPtr = valueOffset;
+				while(*strPtr++)
+					componentCount++;
+				}
+			
+			CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(tagInfo[ETagValue], format, componentCount, valueOffset, this);
+			iIfdEntries.AppendL(entry); 	
+			CleanupStack::Pop(entry);
+			}			
+		}
+	}
+
+TInt CIfdGeneral::LocateEntry(const TUint16 aTag) const
+	{
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			return i;
+			}
+		}
+	return KErrNotFound;
+	}	
+	
+TInt CIfdGeneral::Ifd() const
+	{
+	return iIfdNumber;
+	}
+
+TUint CIfdGeneral::EntryCount() const
+	{
+	return iIfdEntries.Count();
+	}
+	
+TUint8* CIfdGeneral::CreateIfdBlockL(TUint aOffset)
+	{
+	TUint allocSize = Size() + KIfdOffsetByteCount;
+	aOffset += KIfdOffsetByteCount;
+	TUint8* ifdBlock = static_cast<TUint8*>(User::AllocLC(allocSize)); // Allocate buffer for all IFD data.	
+	WriteIfdDirEntriesL(ifdBlock, aOffset);
+	TUint8* tempPtr = ifdBlock + EntryCount() * KMinimumIfdEntrySize;
+
+	TInt temporary = 0;
+	// The pointer to the next Ifd is temporarily zero-filled, and the actual value filled later.
+	tempPtr = Mem::Copy(tempPtr, &temporary, sizeof(temporary));		
+
+	WriteIfdData(tempPtr);
+	CleanupStack::Pop();
+	return ifdBlock;
+	}	
+	
+TBool CIfdGeneral::AllowNullTags() 
+	{
+	// The general case
+	return EFalse;
+	}
+
+TBool CIfdGeneral::IsValidIfdEntryCount(TUint16 aIfdEntryCount) const
+	{
+	// Check that aIfdEntryCount is reasonable
+	// The check is fairly basic but we will check that the minimum size of the ifd entry 
+	// based on the aIfdEntryCount does not exceed the exif data length
+	// no check for minimum number of mandatory entries is done	
+	if ( (iOffsetToIfd + sizeof(aIfdEntryCount) + (aIfdEntryCount * KMinimumIfdEntrySize)) > iExifDataLength)
+		{
+		return EFalse;
+		}
+	else
+		{
+		return ETrue;		
+		}
+	}
+
+
+void CIfdGeneral::WriteIfdDirEntriesL(TUint8* aBlock, TUint aOffset)
+	{
+	TUint16 dirCount = EntryCount();
+
+	//Address where data pointed to by offset values, starts.
+	TUint offsetDataAddress = aOffset + sizeof(dirCount) + (dirCount * KMinimumIfdEntrySize); 
+	
+	// Copy each stored directory entry into the buffer.
+	TInt i;
+	TUint tag;
+	TUint format;
+	TUint sizeOfData;
+	for(i = 0; i < dirCount; i++)
+		{
+		tag = iIfdEntries[i]->Tag();		
+		format = iIfdEntries[i]->Format();
+		
+			
+		TUint compCount = iIfdEntries[i]->ComponentCount();		
+		TBool unicode = iIfdEntries[i]->IsUnicodeData();
+		
+		aBlock = Mem::Copy(aBlock, &tag, KSizeOfTagField); // Write tag.
+		aBlock = Mem::Copy(aBlock, &format, KSizeOfFormatField); // Write format
+		aBlock = Mem::Copy(aBlock, &compCount, KSizeOfComponentCountField); // Write component count.
+		// tempPtr now points to the value/offset field.
+	
+		sizeOfData = iIfdEntries[i]->ExtraSize();
+		
+		// Here we must check  as to whether we are writing an offset to an IFD, since 
+		// its component count is 1 and it is a long - thus check explicitly for tag number 0x8769
+		// (Exif Sub Ifd), or 0xA005 (Interoperability Ifd), and write the offset.
+		
+		if((iIfdEntries[i]->Tag() == KTag8769[ETagValue]) ||
+			(iIfdEntries[i]->Tag() == KTagA005[ETagValue]) ||
+			(iIfdEntries[i]->Tag() == KThumbTag8769[ETagValue]) ||
+			(iIfdEntries[i]->Tag() == KThumbTag0201[ETagValue]))
+			{
+			TUint address = Size() + aOffset + sizeof(dirCount);	
+			// Write offset value.  The value to which this points will be written later.
+			aBlock = Mem::Copy(aBlock, &address, KSizeOfValueOffsetField);			
+			}				
+		//Must check if we are writing an offset or an actual value.
+		else if(sizeOfData > 0)
+			{
+			// Write offset value.  The value to which this points will be written later.
+			aBlock = Mem::Copy(aBlock, &offsetDataAddress, KSizeOfValueOffsetField);
+			// Move the offset address onward, ready for next time.
+			offsetDataAddress += sizeOfData;
+			}
+		else
+			{
+			TUint valueOffset = iIfdEntries[i]->ValueOffset();
+			aBlock = Mem::Copy(aBlock, &valueOffset, sizeof(valueOffset)); // Write actual value.				
+			}
+		// tempPtr now points to position after the value/offset field.
+		}
+
+	}
+	
+void CIfdGeneral::WriteIfdData(TUint8* aBlock)
+	{
+	TUint16 dirCount = EntryCount();
+
+	TInt i;
+	TUint format;
+	TUint sizeOfData;
+	
+	// We have written the main blocks of data, so now need to write out the values that any offsets point to.
+	for(i = 0; i < dirCount; i++)
+		{
+		format = iIfdEntries[i]->Format();
+		sizeOfData = KDataFormatSize[format] * iIfdEntries[i]->ComponentCount();
+		if(sizeOfData > KSizeOfValueOffsetField)
+			{
+			if(iIfdEntries[i]->ActualValue() != NULL)
+				{
+				aBlock = Mem::Copy(aBlock, iIfdEntries[i]->ActualValue(), sizeOfData);
+				if ((sizeOfData%2) == 1) 
+					{
+					(*aBlock++) = '\0'; 
+					}
+				}
+			}
+		}
+	}
+
+
+// Does the given tag exist in this Ifd?
+TBool CIfdGeneral::EntryExists(const TUint aTag) const
+	{
+	for(TInt i = 0; i < iIfdEntries.Count(); i++)
+		{
+		if(aTag == iIfdEntries[i]->Tag())
+			{
+			return ETrue;
+			}
+		}
+	return EFalse;
+	}
+	
+TBool CIfdGeneral::FindTag(const TUint aTag)
+	{
+	return GetTagIndex(aTag)!=KErrNotFound;
+	}
+
+	
+TInt CIfdGeneral::GetFormat(TUint aTag, TUint& aFormat)
+	{
+	TInt index = GetTagIndex(aTag);
+	if (index != KErrNotFound)
+		{
+		const TUint* tag = GetTagInformation(index);
+		aFormat = tag[EFormatValue];
+		return KErrNone;
+		}
+	return KErrNotFound;
+	}
+	
+TInt CIfdGeneral::GetComponentCount(TUint aTag, TUint& aComponentCount)
+	{
+	TInt index = GetTagIndex(aTag);
+	if (index != KErrNotFound)
+		{
+		const TUint* tag = GetTagInformation(index);
+		aComponentCount = tag[EComponentCountValue];
+		return KErrNone;
+		}
+	return KErrNotFound;
+	}
+	
+TInt CIfdGeneral::GetTagIndex(const TUint aTag)
+	{
+	for (TInt i = 0 ; i< GetNumberOfValidTags(); i++ ) 
+		{
+		if (GetTagInformation(i)[ETagValue] == aTag)
+			{
+			return i;	
+			}
+		}	
+	return KErrNotFound;
+	}
+
+void CIfdGeneral::RemoveEntryL(const TUint aTag)
+	{
+	TInt entry=LocateEntry(aTag);
+	if(entry==KErrNotFound)
+		{
+		User::Leave(entry);
+		}
+	delete iIfdEntries[entry];
+	iIfdEntries.Remove(entry);
+	}
+
+void CIfdGeneral::CheckMandatoryEntriesL()
+	{
+	}
+
+// class CIfd0
+CIfd0* CIfd0::NewLC(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CIfd0* self = new (ELeave) CIfd0(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;		
+	}
+
+	
+TInt CIfd0::GetNumberOfValidTags()
+	{
+	return KIfd0NumberTags;		
+	}
+	
+const TUint* CIfd0::GetTagInformation(TInt aIndex) 
+	{
+	if((aIndex < 0) || (aIndex >= KIfd0NumberTags))
+		{//invalid argument
+		return NULL;
+		}
+	else
+		{
+		TUint tagValue = KIfd0TagArray[aIndex][ETagValue];
+		if(tagValue == KTag010F[ETagValue])
+			{
+			return iTag010F;
+			}
+		else if(tagValue == KTag0110[ETagValue])
+			{
+			return iTag0110;
+			}
+		else if(tagValue == KTag0131[ETagValue])
+			{
+			return iTag0131;
+			}
+		else 
+			{
+			return KIfd0TagArray[aIndex];
+			}		
+		}
+	}
+
+void CIfd0::ConstructL()
+	{
+	//For Device information tags - copy the contents from the constants and 
+	//overwrite only the - EValueOffsetValue. 
+	Mem::Copy(iTag010F, KTag010F, sizeof(KTag010F));
+	Mem::Copy(iTag0110, KTag0110, sizeof(KTag0110));
+	Mem::Copy(iTag0131, KTag0131, sizeof(KTag0131));
+	//get the device information from SysUtil API.
+	iManufacturerName = GetDeviceInfo(KTag010F[ETagValue]);
+	iModelName = GetDeviceInfo(KTag0110[ETagValue]);
+	iUIPlatform = GetDeviceInfo(KTag0131[ETagValue]);
+	TUint8* data = NULL;
+	//If reading from SysUtil API is not successful, let the tags carry the values from the constants.
+	//Moreover, the tags manufacturer and model are mandatory. They should have non-NULL value for EValueOffsetValue.
+	if(iManufacturerName != NULL)
+		{
+		data = const_cast<TUint8*>(iManufacturerName->Des().PtrZ());
+		iTag010F[EValueOffsetValue] = reinterpret_cast<TUint>(data);
+		}
+	if(iModelName != NULL)
+		{
+		data = const_cast<TUint8*>(iModelName->Des().PtrZ());
+		iTag0110[EValueOffsetValue] = reinterpret_cast<TUint>(data);
+		}
+	if(iUIPlatform != NULL)
+		{
+		data = const_cast<TUint8*>(iUIPlatform->Des().PtrZ());
+		iTag0131[EValueOffsetValue] = reinterpret_cast<TUint>(data);
+		}
+
+	CIfdGeneral::ConstructL();
+	}
+
+//Reads device information from SysUtil API and makes a copy and returns the value.
+//On failure returns NULL.If the tag aTagValue, does not belong to device information returns NULL.
+HBufC8* CIfd0::GetDeviceInfo(TUint aTagValue)
+	{
+	HBufC8* buff = NULL;
+	//if the tag is one of - manufacturer name, device model name and UI Platform - get 
+	//the values from SysUtil.
+	if((aTagValue == KTag010F[ETagValue]) || (aTagValue == KTag0110[ETagValue]) || (aTagValue == KTag0131[ETagValue]))
+		{
+		CDeviceTypeInformation* deviceAtts = NULL;
+		TInt err = KErrNone;
+		//Get device type information
+		TRAP(err, deviceAtts = SysUtil::GetDeviceTypeInfoL());
+		if(err == KErrNone && deviceAtts != NULL)
+			{
+			TPtrC16 ptr;
+			if(aTagValue == KTag010F[ETagValue])
+				{//manufacturer name
+				err = deviceAtts->GetManufacturerName(ptr);
+				}
+			else if(aTagValue == KTag0110[ETagValue])
+				{//model name
+				err = deviceAtts->GetModelName(ptr);
+				}
+			else if(aTagValue == KTag0131[ETagValue])
+				{//UI platform
+				err = deviceAtts->GetUIPlatformName(ptr);
+				}
+			delete deviceAtts;
+			//error code should be one of - KErrNone, KDefaultValue and KErrOverflow
+			if((err == KErrNone) || (err == CDeviceTypeInformation::KDefaultValue) || (err == KErrOverflow))
+				{
+				buff = HBufC8::NewMax(ptr.Length() + 1);
+				if(buff != NULL)
+					{
+					TPtr8 ptr8 = buff->Des();
+					ptr8.Copy(ptr);
+					}
+				}			
+			}
+		}	
+	return buff;
+	}
+
+CIfd0::~CIfd0()
+	{
+	delete iManufacturerName;
+	delete iModelName;
+	delete iUIPlatform;
+	}
+
+TBool CIfd0::IsValidIfdEntryCount(TUint16 aIfdEntryCount) const
+	{
+	//should have atleast one mandatory entry
+	if(aIfdEntryCount >= 1)
+		{
+		return 	CIfdGeneral::IsValidIfdEntryCount(aIfdEntryCount);
+		}
+	else
+		{
+		return EFalse;			
+		}
+	}
+
+CIfd0::CIfd0(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: CIfdGeneral(EZeroth, aOffsetToIfd, aBase, aIntel, aExifDataLength)
+	{
+	}
+	
+//class CExifIfd
+CExifIfd* CExifIfd::NewLC(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CExifIfd* self = new (ELeave) CExifIfd(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;		
+	}
+	
+CExifIfd* CExifIfd::NewL(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CExifIfd* self = NewLC(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::Pop(self);
+	return self;		
+	}
+
+TInt CExifIfd::GetNumberOfValidTags()
+	{
+	return KExifSubNumberTags;		
+	}
+	
+const TUint* CExifIfd::GetTagInformation(TInt aIndex) 
+	{
+	return KExifSubTagArray[aIndex];
+	}
+
+void CExifIfd::CheckMandatoryEntriesL()
+	{
+	HBufC8* buffer = NULL;
+	TInt err = GetParam8(KTag9000[ETagValue], buffer);
+	if (err == KErrNotFound)
+		{
+		TUint temp = KTag9000[EValueOffsetValue];
+		TUint8* valueOffset = reinterpret_cast<TUint8*>(&temp);
+		TUint format = KTag9000[EFormatValue];
+		TUint componentCount = KTag9000[EComponentCountValue];
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(KTag9000[ETagValue], format, componentCount, valueOffset, this);
+		iIfdEntries.AppendL(entry); 	
+		CleanupStack::Pop(entry);
+		}	
+	delete buffer;
+	buffer = NULL;	
+	
+	err = GetParam8(KTag9101[ETagValue], buffer);
+	if (err == KErrNotFound)
+		{
+		_LIT8(KComponentsConfigurationDefault, "1230");
+		buffer = KComponentsConfigurationDefault().AllocL();
+		CleanupStack::PushL(buffer);
+		TUint format = 0;
+		err = GetFormat(KTag9101[ETagValue], format);		
+		if (err == KErrNone) 
+			{
+			AddParam8L(KTag9101[ETagValue], format, buffer->Length(), buffer);
+			}
+		CleanupStack::Pop();
+		}
+	delete buffer;
+	buffer = NULL;
+			
+	err = GetParam8(KTagA000[ETagValue], buffer);
+	if (err == KErrNotFound)
+		{
+		TUint temp = KTagA000[EValueOffsetValue];
+		TUint8* valueOffset = reinterpret_cast<TUint8*>(&temp);
+		TUint format = KTagA000[EFormatValue];
+		TUint componentCount = KTagA000[EComponentCountValue];
+		CIfdGeneralEntry* entry = CIfdGeneralEntry::NewLC(KTagA000[ETagValue], format, componentCount, valueOffset, this);
+		iIfdEntries.AppendL(entry); 	
+		CleanupStack::Pop(entry);		
+		}
+	delete buffer;
+	buffer = NULL;	
+				
+	TUint16 buffer16 = 0;
+	err = GetShortParam(KTagA001[ETagValue], buffer16);
+	if (err == KErrNotFound)
+		{
+		const TUint KColorSpaceDefault = 0xFFFF;
+		TUint format = 0;
+		err = GetFormat(KTagA001[ETagValue], format);		
+		if (err == KErrNone) 
+			{
+			AddShortParamL(KTagA001[ETagValue], format, 1, KColorSpaceDefault);
+			}
+		}	
+	}
+	
+TBool CExifIfd::CheckImageSizeTags()
+	{
+	TUint16 buffer16 = NULL;
+	TInt err = GetShortParam(KTagA002[ETagValue], buffer16);
+	if (err == KErrNotFound)
+		{
+		return EFalse;
+		}
+	err = GetShortParam(KTagA003[ETagValue], buffer16);
+	if (err == KErrNotFound)
+		{
+		return EFalse;
+		}
+	return ETrue;
+	}
+	
+void CExifIfd::UpdateImageSizeTagsL(const TSize& aSize)
+	{
+	TUint16 value = NULL;
+	TInt err = GetShortParam(KTagA002[ETagValue], value);
+	if (err == KErrNotFound)
+		{
+		TUint format = 0;
+		err = GetFormat(KTagA002[ETagValue], format);		
+		if (err == KErrNone) 
+			{
+			AddShortParamL(KTagA002[ETagValue], format, 1, aSize.iWidth);
+			}
+		}
+	else
+		{
+		if (value != aSize.iWidth)
+			{
+			SetShortParam(KTagA002[ETagValue], aSize.iWidth);
+			}
+		}
+	err = GetShortParam(KTagA003[ETagValue], value);
+	if (err == KErrNotFound)
+		{
+		TUint format = 0;
+		err = GetFormat(KTagA003[ETagValue], format);		
+		if (err == KErrNone) 
+			{
+			AddShortParamL(KTagA003[ETagValue], format, 1, aSize.iHeight);
+			}
+		}
+	else
+		{
+		if (value != aSize.iHeight)
+			{
+			SetShortParam(KTagA003[ETagValue], aSize.iHeight);
+			}
+		}
+	}
+
+CExifIfd::CExifIfd(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: CIfdGeneral(EExifSub, aOffsetToIfd, aBase, aIntel, aExifDataLength)
+	{	
+	}
+
+
+//class CInteropIfd
+CInteropIfd* CInteropIfd::NewLC(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CInteropIfd* self = new (ELeave) CInteropIfd(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;		
+	}
+
+CInteropIfd* CInteropIfd::NewL(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CInteropIfd* self = NewLC(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::Pop(self);
+	return self;	
+	}
+	
+TInt CInteropIfd::GetNumberOfValidTags()
+	{
+	return KInteropNumberTags;		
+	}
+	
+const TUint* CInteropIfd::GetTagInformation(TInt aIndex) 
+	{
+	return KInteropTagArray[aIndex];
+	}
+
+TBool CInteropIfd::IsValidIfdEntryCount(TUint16 aIfdEntryCount) const
+	{
+	//should have atleast one mandatory entry
+	if(aIfdEntryCount >= 1)
+		{
+		return 	CIfdGeneral::IsValidIfdEntryCount(aIfdEntryCount);
+		}
+	else
+		{
+		return EFalse;			
+		}
+	}
+
+CInteropIfd::CInteropIfd(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: CIfdGeneral(EInterop, aOffsetToIfd, aBase, aIntel, aExifDataLength)
+	{	
+	}
+
+//class CIfd1
+CIfd1* CIfd1::NewLC(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CIfd1* self = new (ELeave) CIfd1(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;		
+	}
+	
+	
+TInt CIfd1::GetNumberOfValidTags()
+	{
+	return KIfd1NumberTags;		
+	}
+	
+const TUint* CIfd1::GetTagInformation(TInt aIndex) 
+	{
+	return KIfd1TagArray[aIndex];
+	}
+
+CIfd1::CIfd1(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: CIfdGeneral(EFirst, aOffsetToIfd, aBase, aIntel, aExifDataLength)
+	{	
+	}
+
+//class CGpsIfd
+CGpsIfd* CGpsIfd::NewLC(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CGpsIfd* self = new (ELeave) CGpsIfd(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;		
+	}
+
+CGpsIfd* CGpsIfd::NewL(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	{
+	CGpsIfd* self = NewLC(aOffsetToIfd, aBase, aIntel, aExifDataLength);
+	CleanupStack::Pop(self);
+	return self;	
+	}
+	
+TInt CGpsIfd::GetNumberOfValidTags()
+	{
+	return KGpsSubNumberTags;		
+	}
+	
+const TUint* CGpsIfd::GetTagInformation(TInt aIndex) 
+	{
+	return KGpsSubTagArray[aIndex];
+	}
+
+TBool CGpsIfd::IsValidIfdEntryCount(TUint16 aIfdEntryCount) const
+	{
+	//should have atleast one mandatory entry
+	if(aIfdEntryCount >= 1)
+		{
+		return 	CIfdGeneral::IsValidIfdEntryCount(aIfdEntryCount);
+		}
+	else
+		{
+		return EFalse;			
+		}		
+	}
+
+CGpsIfd::CGpsIfd(const TUint aOffsetToIfd, const TUint8* aBase, const TBool aIntel, const TUint aExifDataLength)
+	: CIfdGeneral(EGpsSub, aOffsetToIfd, aBase, aIntel, aExifDataLength)
+	{	
+	}
+
+TBool CGpsIfd::AllowNullTags() 
+	{
+	// Null tags are allowed for GPS
+	return ETrue;
+	}
+