diff -r 735348f59235 -r 948c7f65f6d4 mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ifdgeneralentry.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ifdgeneralentry.cpp Wed Sep 01 12:38:50 2010 +0100 @@ -0,0 +1,693 @@ +// 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 "ExifTagHelper.h" +#include "ImageUtils.h" + +const TUint KAnySize = 0; // For tags that have no upper limit on their content size. + +GLDEF_C void Cleanup(TAny *aObject) + { + User::Free(aObject); + } + +// Sets the value/offset field (four bytes) of this Ifd entry. +void CIfdGeneralEntry::SetValueOffset(const TUint8* aValueOffset) + { + /* + Need to check the type of data, and store accordingly - see Exif2.2 specification pp.14: + "If the value is < 4 bytes, the value is stored in the 4 byte area starting from the left, + i.e. from the lower end of the byte offset. For example, in big endian format, if the + type is SHORT and the value is 1, it is recorded as 00010000.H." + */ + TUint totalSize = KDataFormatSize[Format()] * ComponentCount(); + + switch(totalSize) + { + case (sizeof(TUint8)): // 1 byte in length. + Mem::Copy(iDirEntryData+KValueOffsetFieldPosition, aValueOffset, sizeof(TUint8)); + Mem::FillZ(iDirEntryData+KValueOffsetFieldPosition+sizeof(TUint8), KThreeBytes); // Fill remaining 3 bytes with zeros. + break; + case (sizeof(TUint16)): // 2 bytes in length. + { + const TUint16* shortValue = reinterpret_cast(aValueOffset); + Mem::Copy(iDirEntryData+KValueOffsetFieldPosition, shortValue, sizeof(TUint16)); // Fill remaining 2 bytes with zeros. + Mem::FillZ(iDirEntryData+KValueOffsetFieldPosition+sizeof(TUint16), sizeof(TUint16)); + } + break; + case KThreeBytes: // 3 bytes in length. Fall through. + case (sizeof(TUint32)): // 4 bytes in length. + { + const TUint32* longValue = reinterpret_cast(aValueOffset); + Mem::Copy(iDirEntryData+KValueOffsetFieldPosition, longValue, sizeof(TUint32)); + if(totalSize == KThreeBytes) + { + Mem::FillZ(iDirEntryData+KValueOffsetFieldPosition+KThreeBytes, sizeof(TUint8)); + } + } + break; + } + } + + +// Sets the tag field (two bytes) of this Ifd entry. +void CIfdGeneralEntry::SetTag(const TUint aTag) + { + Mem::Copy(iDirEntryData, &aTag, KSizeOfTagField); + } + +// Sets the format field (two bytes) of this Ifd entry. +void CIfdGeneralEntry::SetFormat(const TUint aFormat) + { + Mem::Copy(iDirEntryData+KFormatFieldPosition, &aFormat, KSizeOfFormatField); + } + +// Sets the component count field (four bytes) of this Ifd entry. +void CIfdGeneralEntry::SetComponentCount(const TUint aComponentCount) + { + Mem::Copy(iDirEntryData+KComponentCountFieldPosition, &aComponentCount, KSizeOfComponentCountField); + } + +// Returns the tag value of this Ifd entry. +TUint CIfdGeneralEntry::Tag() + { + return PtrReadUtil::ReadUint16(iDirEntryData); + } + +// Returns the format of this Ifd entry. +TUint CIfdGeneralEntry::Format() + { + return PtrReadUtil::ReadUint16(iDirEntryData+KFormatFieldPosition); + } + +// Returns the component count of this Ifd entry. +TUint CIfdGeneralEntry::ComponentCount() + { + return PtrReadUtil::ReadUint32(iDirEntryData+KComponentCountFieldPosition); + } + +// Returns the value/offset field of this Ifd entry. +TUint CIfdGeneralEntry::ValueOffset() + { + return PtrReadUtil::ReadUint32(iDirEntryData+KValueOffsetFieldPosition); + } + +// Returns a pointer to the data that the value/offset points to. +const TUint8* CIfdGeneralEntry::ActualValue() + { + // If there is data that the value/offset field points to, then return a pointer to it. + return iActualData; + } + +TInt CIfdGeneralEntry::ExtraSize() + { + return TotalSize() - KMinimumIfdEntrySize; + } + +CIfdGeneralEntry* CIfdGeneralEntry::NewLC() + { + CIfdGeneralEntry* self = new (ELeave) CIfdGeneralEntry; + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + + +CIfdGeneralEntry* CIfdGeneralEntry::NewLC(const TUint& aTag, const TUint& aFormat, const TUint& aComponentCount, const TUint8* aParam, CIfdGeneral* aIfd) + { + TBool ignored; // NewLC is called by functions that don't require checking if the tag is known or not + CIfdGeneralEntry* self = new (ELeave) CIfdGeneralEntry(); + CleanupStack::PushL(self); + self->ConstructL(aTag, aFormat, aComponentCount, aParam, aIfd, ignored); + return self; + } + +CIfdGeneralEntry* CIfdGeneralEntry::NewL(const TUint& aTag, const TUint& aFormat, const TUint& aComponentCount, const TUint8* aParam, CIfdGeneral* aIfd, TBool& aUnknownTag) + { + CIfdGeneralEntry* self = new (ELeave) CIfdGeneralEntry(); + CleanupStack::PushL(self); + self->ConstructL(aTag, aFormat, aComponentCount, aParam, aIfd, aUnknownTag); + CleanupStack::Pop(self); + return self; + } + +CIfdGeneralEntry::CIfdGeneralEntry() + { + } + +void CIfdGeneralEntry::ConstructL() + { + iDirEntryData = static_cast(User::Alloc(KMinimumIfdEntrySize)); + if(iDirEntryData == NULL) + { + User::Leave(KErrNoMemory); + } + } + +void CIfdGeneralEntry::ConstructL(const TUint& aTag, const TUint& aFormat, TUint aComponentCount, const TUint8* aValueOffset, CIfdGeneral* aIfd, TBool& aUnknownTag) + { + // the code here used to check if the tag was invalid and if so leave with KErrArgument + // now if the tag is invalid it just bypasses the further checks + // this is to future proof against versions of exif which introduce additional tags + // to the exif 2.2 spec + TUint expectedComponentCount = 0; + + ASSERT(aIfd); + + iIfd = aIfd; + if(aIfd->FindTag(aTag)) + { + // Known tag + aUnknownTag = EFalse; + + TUint expectedFormat = 0; + + User::LeaveIfError(iIfd->GetFormat(aTag, expectedFormat)); + User::LeaveIfError(iIfd->GetComponentCount(aTag, expectedComponentCount)); + + if ((aTag == KTagA002[ETagValue])|| + (aTag == KTagA003[ETagValue])|| + (aTag == KTag1001[ETagValue]) || + (aTag == KTag1002[ETagValue])) + { + //do nothing Tag A002 A003 can be short or long + // Interop Tag 1001 and 1002 can be unsigned short or long + } + else if(expectedFormat != aFormat) + { + User::Leave(KErrArgument); + } + + if(expectedComponentCount != 0) // If 0, then size is undefined. + { + if(aComponentCount > expectedComponentCount) + { + User::Leave(KErrNotSupported); + } + } + + // Check overflow. + if(aFormat >= KDataFormatSizeLength) + { + User::Leave(KErrOverflow); + } + } + else + { + // Unknown tag + // Create this entry anyway as it may be an extension to the EXIF standard + // but inform the caller + aUnknownTag = ETrue; + } + iDirEntryData = static_cast(User::AllocL(KMinimumIfdEntrySize)); // Alloc standard entry size. + Mem::FillZ(iDirEntryData, KMinimumIfdEntrySize); + SetTag(aTag); // Simply set the tag. + SetFormat(aFormat); // Set the format (associated with the tag). + SetComponentCount(aComponentCount); + + // Determine if we have a value or an offset to a value. + TInt bytes = KDataFormatSize[aFormat]; + TUint size = aComponentCount * bytes; + TUint8* tempValue = NULL; + if(IsStringFormat()) + { + tempValue = static_cast(User::AllocL(size+sizeof(TUint8))); + Mem::Copy(tempValue, aValueOffset, size); + + if (tempValue[size-1] != KNullCharacter) + { + Mem::Copy(tempValue+size, &KNullCharacter, sizeof(KNullCharacter)); + size++; + aComponentCount++; + SetComponentCount(aComponentCount); + } + + aValueOffset = tempValue; + } + else if(IsRationalFormat()) + { + //Since rational default values only store the numerator in the CExifTag constant we + //must set the denominator. + if(expectedComponentCount == 1) + { + tempValue = static_cast(User::AllocL(KSizeOfRational)); + Mem::Copy(tempValue, aValueOffset, sizeof(TUint)); + TUint denominator = 1; + Mem::Copy(tempValue+sizeof(TUint), &denominator, sizeof(TUint)); + aValueOffset = tempValue; + } + } + CleanupStack::PushL(TCleanupItem(Cleanup,tempValue)); + + if(size > KSizeOfValueOffsetField) + { + // We have an Offset, so will set the actual value (i.e. that which the value/offset field points to). + User::LeaveIfError(SetActualData(aValueOffset, aComponentCount, bytes)); + // Will not set the value/offset field now, as will be set later once the whole block of data is needed. + } + else + { + // We have an actual value, so will set this in the ValueOffset. + SetValueOffset(aValueOffset); + // The actual value field will be left blank - no need to store the data twice. + } + CleanupStack::Pop(tempValue); + User::Free(tempValue); + } + +CIfdGeneralEntry::~CIfdGeneralEntry() + { + // from encoder + delete iDirEntryData; + delete iActualData; + } + +// Sets the data that the value/offset field points to. +TInt CIfdGeneralEntry::SetActualData(const TAny* aActualData, const TUint aSize, const TUint aBytes) + { + /* + Pass aSize, since we don't know how many components the value has. + Will need to check the format type, in order to overcome the problems with 'undefined' types. + */ + TInt size = aSize * aBytes; + iActualData = static_cast(User::ReAlloc(iActualData, size)); + + if(iActualData == NULL) + { + return KErrNoMemory; + } + Mem::Copy(iActualData, aActualData, size); + + SetComponentCount(aSize); + return KErrNone; + } + +// Updates a rational that has a component count of 1. +TInt CIfdGeneralEntry::UpdateRational(TInt aNumerator, TInt aDenominator) + { + // Cannot change a rational entry with a component count > 1 or a non-rational entry. + if(ComponentCount() > 1 || !IsRationalFormat()) + { + return KErrArgument; + } + // We're only dealing with a single rational value. + + // A rational is always > 4 bytes long, so we store it in the actual data field. + TUint8* rational = static_cast(User::Alloc(KSizeOfRational)); + if(rational == NULL) + { + return KErrNoMemory; + } + TUint8* tempPtr = Mem::Copy(rational, &aNumerator, sizeof(aNumerator)); + Mem::Copy(tempPtr, &aDenominator, sizeof(aDenominator)); + if(SetActualData(rational, sizeof(TUint8), KSizeOfRational) == KErrNoMemory) + { + User::Free(rational); + return KErrNoMemory; + } + User::Free(rational); + return KErrNone; + } + +// Updates a value of ASCII type when Ifd knowledge is needed. +TInt CIfdGeneralEntry::UpdateString(const HBufC8* aStringValue) + { + if(aStringValue == NULL) + { + return KErrArgument; + } + + //Need to check format type of object. + if(!IsStringFormat()) + { + // Cannot change non-ASCII entry. + return KErrArgument; + } + + TUint legalCompCount = KAnySize; + TInt err = KErrNone; + + err = iIfd->GetComponentCount(Tag(), legalCompCount); + + TUint stringLength=aStringValue->Length(); + const TUint8* ptr = aStringValue->Ptr(); + TBool nullTerminationNeeded = EFalse; + + //Do some string length checks. + if (legalCompCount != KAnySize) + { + // We have a fixed length string type. Only accept strings that equal the + // fixed length when NULL termianted. + if (stringLength == legalCompCount-1 && ptr[stringLength-1] != KNullCharacter) + { + //If we add a NULL termination string will be legal + nullTerminationNeeded = ETrue; + } + else if (stringLength == legalCompCount && ptr[stringLength-1] == KNullCharacter) + { + //Okay as it is. + } + else + { + return KErrArgument; + } + } + else + { + //No length checks needed, but still might have to add a null terminator. + nullTerminationNeeded = (ptr[stringLength-1] != KNullCharacter); + } + + HBufC8* stringValueCopy = NULL; + if (nullTerminationNeeded) + { + stringValueCopy = HBufC8::New(aStringValue->Length()+1); + if(stringValueCopy == NULL) + { + return KErrNoMemory; + } + + *stringValueCopy = *aStringValue; + stringValueCopy->Des().Append(KNullCharacter); + stringLength++; + + ptr = stringValueCopy->Ptr(); + } + + if(stringLength > KSizeOfValueOffsetField) + { + // We have an Offset, so will set the actual value. + err = SetActualData(ptr, stringLength, sizeof(TUint8)); + // Will NOT set the value/offset field now, since it will no-doubt change. + } + else + { + // We have an actual value, so will set this in the ValueOffset. + SetComponentCount(stringLength); + SetValueOffset(ptr); + // The actualvalue field will be left blank - no need to store the data twice. + err=KErrNone; + } + delete stringValueCopy; + return err; + } + +/* + Must have a catch-all update function since there are some anomolies to the standard rules. + Furthermore, this function may also be used to set data of the undefined format. +*/ +TInt CIfdGeneralEntry::UpdateData(TUint aComponentCount, const TUint8* aData) + { + TUint maxSize = 0; + // Get the maximum possible size. + TUint tag = Tag(); + + iIfd->GetComponentCount(tag, maxSize); + + if(maxSize != KAnySize) // If KAnySize, then size is undefined. + { + if(aComponentCount > maxSize) + { + return KErrNotSupported; + } + } + + // Check overflow. Will indicate that the format-type is not recognised. + TUint format = Format(); + if(format == 0) + { + return KErrCorrupt; + } + + if(format >= KDataFormatSizeLength) + { + return KErrNotSupported; + } + + // We are updating existing data, and so will already know the format type. + // Determine if we have a value or an offset to a value. + TInt bytes = KDataFormatSize[format]; + TUint size = aComponentCount * bytes; + + TUint8* tempValue = NULL; + // Add NULL to the end if it's ASCII + if(IsStringFormat()) + { + // verify if the last character is NULL + if(aData[aComponentCount-1]==KNullCharacter) + { + //String already NULL terminated. + if ((maxSize != KAnySize) && (aComponentCount != maxSize)) + { + return KErrNotSupported; + } + } + else + { + // Note: This branch is only executed when reading an Exif source + // that contains a non-NULL terminated ASCII string, which is + // against the Exif 2.2 Spec. + + // Since we will add a terminating NULL to the string, + // must check max size of this particular tag. + if((maxSize != KAnySize) && (aComponentCount != maxSize-1)) + { + return KErrNotSupported; + } + + //Add the NULL terminator + tempValue = static_cast(User::Alloc(size + sizeof(TUint8))); + if(tempValue == NULL) + { + return KErrNoMemory; + } + Mem::Copy(tempValue, aData, size); + Mem::Copy(tempValue+size, &KNullCharacter, sizeof(TUint8)); + aData = tempValue; + size++; + aComponentCount++; + } + } + TInt err=KErrNone; + if(size > KSizeOfValueOffsetField) + { + // We have an Offset, so will set the actual value (i.e. that which the value/offset field points to). + err = SetActualData(aData, aComponentCount, bytes); + // Will not set the value/offset field now, as will be set later once the whole block of data is needed. + } + else + { + // We have an actual value, so will set this in the ValueOffset. + SetComponentCount(aComponentCount); + SetValueOffset(aData); + // The actual value field will be left blank - no need to store the data twice. + } + User::Free(tempValue); + return err; + } + + +// Updates an integer value (including short, integer, long). +TInt CIfdGeneralEntry::UpdateInteger(const TInt aIntegerValue) + { + // Need to check format type of object, to avoid calling this on an entry that is not an integer. + if(!IsIntegerFormat()) + { + //first check if tag is 0xA002 or A003 - this could be short + //but when setting it we can set it as long + TUint16 tag = Tag(); + if ((tag == KTagA002[ETagValue])||(tag == KTagA003[ETagValue])) + { + //tag is A002 or A003 and is short - set entry to long + SetFormat(EUnsignedLong); + } + else + { + // Cannot change non-integer entry. + return KErrArgument; + } + } + + // Check overflow. + TUint format = Format(); + if(format == NULL) + { + return KErrCorrupt; + } + + if(format >= KDataFormatSizeLength) + { + return KErrNotSupported; + } + + // Determine if we have a value or an offset to a value. + TInt bytes = KDataFormatSize[format]; + TUint size = ComponentCount() * bytes; + if(size > KSizeOfValueOffsetField) + { + // We have an Offset, so will set the actual value... + return SetActualData(&aIntegerValue, ComponentCount(), bytes); + // Will NOT set the value/offset field now, since it will no-doubt change. + } + else + { + // We have an actual value, so will set this in the ValueOffset. + SetValueOffset(reinterpret_cast(&aIntegerValue)); + return KErrNone; + // The actualvalue field will be left blank - no need to store the data twice. + } + } + +// Updates a short value. +TInt CIfdGeneralEntry::UpdateShort(const TUint16 aShortValue) + { + // Need to check format type of object, to avoid calling this on an entry that is not a short. + if(!IsShortFormat()) + { + // Cannot change non-short entry. + return KErrArgument; + } + + // Check overflow. + TUint format = Format(); + if(format == NULL) + { + return KErrCorrupt; + } + + if(format >= KDataFormatSizeLength) + { + return KErrNotSupported; + } + + // Determine if we have a value or an offset to a value. + TInt bytes = KDataFormatSize[format]; // value is 2, since it is a short. + TUint size = ComponentCount() * bytes; + if(size > KSizeOfValueOffsetField) + { + // We have an Offset, so will set the actual value... + return SetActualData(&aShortValue, ComponentCount(), bytes); + // Will NOT set the value/offset field now, since it will no-doubt change. + } + else + { + // We have an actual value, so will set this in the ValueOffset. + SetValueOffset(reinterpret_cast(&aShortValue)); + return KErrNone; + // The actualvalue field will be left blank - no need to store the data twice. + } + } + +// Returns the total size of this Ifd entry. The function should never return zero. +// The minimum value returned should be KMinimumIfdEntrySize, in case of any invalidity with +// the entry such as invalid format. +TInt CIfdGeneralEntry::TotalSize() + { + TUint16 format = Format(); + TBool formatValidity = EFalse; + if(format <= KDataFormatSizeLength-1) + { + //formats - 0, 6, 8, are invalid, which will have size 0. + if(KDataFormatSize[format] != 0) + { + formatValidity = ETrue; + } + } + ASSERT(formatValidity); + //in case of invalid format, return minimum size + if (!formatValidity) + { + return KMinimumIfdEntrySize; + } + + TUint size = (KDataFormatSize[format] * ComponentCount()); + if(size > KSizeOfValueOffsetField) + { + // We have an offset value, so include extra data length (i.e. past the KMinimumIfdEntrySize byte limit). + if ((size%2)==1) + { + size++; + } + return KMinimumIfdEntrySize + size; + } + return KMinimumIfdEntrySize; + } + +// Does this entry contain rational data? +TBool CIfdGeneralEntry::IsRationalFormat() + { + TUint format = Format(); + return format == EUnsignedRational || + format == ESignedRational; + } + +// Does this entry contain string data? +TBool CIfdGeneralEntry::IsStringFormat() + { + return Format() == EAscii; + } + +// Does this entry contain 'undefined' data? +TBool CIfdGeneralEntry::IsUndefinedFormat() + { + return Format() == EUndefined; + } + +// Does this entry contain integer data? +TBool CIfdGeneralEntry::IsIntegerFormat() + { + switch(Format()) + { + case EByte: + case EUnsignedLong: + case ESignedLong: + { + return ETrue; + } + default: + { + return EFalse; + } + } + } + +// Does this entry contain short data? +TBool CIfdGeneralEntry::IsShortFormat() + { + return Format() == EUnsignedShort; + } + +// Returns ETrue if the data is Unicode. +TBool CIfdGeneralEntry::IsUnicodeData() + { + TUint tag = Tag(); + //Only the following undefined tags may potentially be Unicode + TBool tagIsPotentiallyUnicode=( KTag9286[ETagValue] == tag || + KTagGPS001B[ETagValue] == tag || + KTagGPS001C[ETagValue] == tag ); + + // Need to ensure that the correct component count is returned for the unicode data. + if (tagIsPotentiallyUnicode && ExtraSize() >= KUnicode().Size()) + { + return (0 == Mem::Compare(iActualData, KUnicode().Length() , KUnicode().Ptr(), KUnicode().Length())); + } + else + { + return EFalse; + } + }