imagingmodules/exiflib/src/ExifCore.cpp
changeset 0 469c91dae73b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingmodules/exiflib/src/ExifCore.cpp	Thu Dec 17 09:22:31 2009 +0200
@@ -0,0 +1,1631 @@
+/*
+* Copyright (c) 2003, 2004 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:  The core service class for handling Exif v2.2 File Format.
+*
+*/
+
+
+// INCLUDE FILES
+#include "ExifIfd.h"
+#include "ExifCore.h"
+#include "ExifReadImpl.h"
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CExifCore::CExifCore
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CExifCore::CExifCore()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::ConstructL()
+    {
+    CreateIfdL( EIfd0 );
+    CreateIfdL( EIfdExif);
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CExifCore* CExifCore::NewL()
+    {
+    CExifCore* self = new( ELeave ) CExifCore();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();    
+    return self;
+    }
+
+// Destructor
+CExifCore::~CExifCore()
+    {
+    for ( TUint i = 0; i < KIfdNo; ++i )
+        {
+        if ( iIfdArray[i] )
+            {
+            delete iIfdArray[i];
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::InsertTagL
+// Inserts the given tag into the specified IFD structure.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::InsertTagL( TExifIfdType aIfdType, CExifTagImpl* aExifTag, TBool aCheckValidity )
+    {
+    LOGTEXT3( _L( "ExifLib: CExifCore::InsertTagL() entering: aIfdType=0x%x, aCheckValidity=%d" ), aIfdType, aCheckValidity);
+    switch ( aIfdType )
+        {
+        case EIfd0:
+        case EIfdExif:
+        case EIfd1:
+        case EIfdGps:
+        case EIfdIntOp:
+            if ( aCheckValidity && ( !TagIsValid( aExifTag->TagInfo(), aIfdType ) ) )
+                {
+                LOGTEXT( _L( "ExifLib: CExifCore::InsertTagL() Leaving: KErrNotSupported" ));
+                User::Leave( KErrNotSupported );
+                }
+            if ( !iIfdArray[aIfdType] )
+                {
+                // Since a new IFD should be created, 6 bytes more than tag
+                // size is required. 
+                // Check if it exceeds 64K bytes after insertion.
+                if ( App1Size() + aExifTag->Size() + 6 > KMaxApp1Size )
+                    {
+                    LOGTEXT( _L( "ExifLib: CExifCore::InsertTagL() Leaving: KErrOverflow (>KMaxApp1Size)1" ));
+                    User::Leave( KErrOverflow );
+                    }
+                CreateIfdL( aIfdType ); 
+                TRAPD( error, iIfdArray[aIfdType]->InsertTagL( aExifTag, aCheckValidity ) );
+                if ( error != KErrNone )
+                    {
+                    delete( iIfdArray[aIfdType] );
+                    iIfdArray[aIfdType] = 0;
+                    LOGTEXT2( _L( "ExifLib: CExifCore::InsertTagL() Leaving: error=%d" ), error );
+                    User::Leave( error );
+                    }
+                }
+            else
+                {
+                // Check if it exceeds 64K bytes after insertion.
+                if ( !( TagExists( aExifTag->Id(), aIfdType ) ) && 
+                    ( App1Size() + aExifTag->Size() > KMaxApp1Size ) )
+                    {
+                    LOGTEXT( _L( "ExifLib: CExifCore::InsertTagL() Leaving: KErrOverflow (>KMaxApp1Size)2" ));
+                    User::Leave( KErrOverflow );
+                    }
+                iIfdArray[aIfdType]->InsertTagL( aExifTag, aCheckValidity );
+                }
+            break;
+        default:
+            {
+            LOGTEXT( _L( "ExifLib: CExifCore::InsertTagL() Leaving: KErrArgument" ));
+            User::Leave( KErrArgument );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given 8-bit integer to the data of tag specified by the given tag ID
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( TUint16 aTagId, TInt8 aTagData )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagUndefined;
+    // Total tag data size = 1 bytes.
+    TUint32 tagCount = 1;
+    TExifIfdType ifdType = EIfdExif;
+    HBufC8* buffer = HBufC8::NewL( 1 );
+    CleanupStack::PushL( buffer );
+    buffer->Des().SetLength( 1 );
+    switch ( aTagId )
+        {
+        case KIdFileSource:
+            break;
+        default:
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::SetTagDataL() Leave( KErrNotSupported ) aTagId=0x%x" ), aTagId);
+            User::Leave( KErrNotSupported );
+            }
+        }
+    *REINTERPRET_CAST( TInt8*, CONST_CAST( TUint8*, buffer->Ptr() ) ) 
+        = aTagData;
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given 16-bit unsigned integer to the data of a tag specified by the 
+// given tag ID.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( TUint16 aTagId, TUint16 aTagData )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagShort;
+    // Total tag data size = 2 bytes.
+    // Since tag data type is 2-byte type, tagCount = 1.
+    TUint32 tagCount = 1;
+    TExifIfdType ifdType = EIfdExif;
+    HBufC8* buffer = HBufC8::NewL( 2 );
+    buffer->Des().SetLength( 2 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdCompression:
+        case KIdOrientation:
+        case KIdResolutionUnit:
+        case KIdYCbCrPositioning:
+            ifdType = EIfd0;
+            break;
+        case KIdFlash:
+        case KIdColorSpace:
+        case KIdExposureMode:
+        case KIdWhiteBalance:
+        case KIdSceneCaptureType:
+        case KIdExposureProgram:
+        case KIdMeteringMode:
+        case KIdLightSource:
+        case KIdContrast:
+        case KIdSaturation:
+        case KIdSharpness:
+        case KIdCustomRendered:
+        case KIdGainControl:
+            break;
+        default:
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::SetTagDataL() Leave( KErrNotSupported ) 16 aTagId=0x%x" ), aTagId);
+            User::Leave( KErrNotSupported );
+            }
+        }
+    TExifCommon::SetUint16( CONST_CAST( TUint8*, buffer->Ptr() ), aTagData );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given 32-bit integer to the data of tag specified by given tag ID
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( TUint16 aTagId, TUint32 aTagData )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagLong;
+
+    // Total tag data size = 4 bytes.
+    // If the tag data type is one of 4-byte types, tagCount = 1.
+    // If the tag data type is one of 1-byte types, tagCount = 4.
+    TUint32 tagCount = 1;
+    TExifIfdType ifdType = EIfdExif;
+    HBufC8* buffer = HBufC8::NewL(4 ); 
+    buffer->Des().SetLength(4 );
+    
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdExifIfdPointer:
+        case KIdGpsIfdPointer:
+            ifdType = EIfd0;
+            break;
+        case KIdIntOpIfdPointer:
+        case KIdPixelXDimension:
+        case KIdPixelYDimension:
+            break;
+        case KIdComponentsConfiguration:
+        case KIdExifVersion:
+        case KIdFlashPixVersion:
+            tagType = CExifTag::ETagUndefined;
+            tagCount = 4;
+            break;
+        case KIdGpsVersion:
+            tagType = CExifTag::ETagByte;
+            tagCount = 4;
+            ifdType = EIfdGps;
+            break;
+        default:
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::SetTagDataL() Leave( KErrNotSupported ) 32 aTagId=0x%x" ), aTagId);
+            User::Leave( KErrNotSupported );
+            }
+        }
+    TExifCommon::SetUint32( CONST_CAST( TUint8*, buffer->Ptr() ), aTagData );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given data buffer to the data of a tag specified by the given tag ID
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( TUint16 aTagId, const TDesC8& aTagData )
+    {
+    if ( !aTagData.Length() )
+        {
+        User::Leave( KErrArgument );
+        }
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagAscii;
+    TUint32 tagCount = aTagData.Length();
+    TExifIfdType ifdType = EIfd0;
+    switch ( aTagId )
+        {
+        case KIdImageDescription:
+        case KIdMake:
+        case KIdModel:
+        case KIdSoftware:
+        case KIdCopyright:
+            break;
+        case KIdTransferFunction:
+            tagType = CExifTag::ETagShort;
+            tagCount /= 2;
+            break;
+        case KIdDateTime:
+            break;
+        case KIdIsoSpeedRatings:
+            tagType = CExifTag::ETagShort;
+            tagCount /= 2;
+            ifdType = EIfdExif;
+            break;
+        case KIdDateTimeOriginal:
+        case KIdDateTimeDigitized:
+        case KIdRelatedSoundFile:
+            ifdType = EIfdExif;
+            break;
+        case KIdMakerNote:
+        case KIdUserComment:
+            tagType = CExifTag::ETagUndefined;
+            ifdType = EIfdExif;
+            break;
+        default:
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::SetTagDataL() Leave( KErrNotSupported ) C8 aTagId=0x%x" ), aTagId);
+            User::Leave( KErrNotSupported );
+            }
+        }
+    // Check if ASCII string terminates with NULL character.
+    // If not add NULL.
+    HBufC8* buffer = NULL;
+    if ( ( tagType == CExifTag::ETagAscii ) && 
+        ( aTagData.Ptr()[aTagData.Length() - 1] ) )
+        {
+        ++tagCount;
+        buffer = HBufC8::NewL( aTagData.Length() + 1 );
+        buffer->Des().Copy( aTagData );
+        *( CONST_CAST( TUint8*, buffer->Des().Ptr() ) + 
+            aTagData.Length() ) = NULL;
+        buffer->Des().SetLength( aTagData.Length() + 1 );
+        }
+    else
+        {
+        buffer = aTagData.AllocL();
+        }
+    CleanupStack::PushL( buffer );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop();
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given 64-bit (2 x 32-bit ) unsigned integers to the data of a tag 
+// specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( 
+    TUint16 aTagId, 
+    TUint32 aNumerator, 
+    TUint32 aDenominator )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagRational;
+
+    // Total tag data size = 8 bytes.
+    // Since tag data type is 8-byte type, tagCount = 1.
+    TUint32 tagCount = 1;
+    TExifIfdType ifdType = EIfd0;
+    HBufC8* buffer = HBufC8::NewL( 8 );
+    buffer->Des().SetLength( 8 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdXResolution:
+        case KIdYResolution:
+            break;
+        case KIdExposureTime:
+        case KIdApertureValue:
+        case KIdDigitalZoomRatio:
+            ifdType = EIfdExif;
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    TExifCommon::SetUint32( CONST_CAST( TUint8*, buffer->Ptr() ), aNumerator );
+    TExifCommon::SetUint32( 
+        CONST_CAST( TUint8*, buffer->Ptr() + 4 ), aDenominator );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetTagDataL
+// Sets the given 64-bit (2 x 32-bit ) integers to the data of a tag specified 
+// by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetTagDataL( 
+    TUint16 aTagId, 
+    TInt32 aNumerator, 
+    TInt32 aDenominator )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagSrational;
+    // Total tag data size = 8 bytes.
+    // Since tag data type is 8-byte type, tagCount = 1.
+    TUint32 tagCount = 1;
+    TExifIfdType ifdType = EIfdExif;
+    HBufC8* buffer = HBufC8::NewL( 8 );
+    buffer->Des().SetLength( 8 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdExposureBiasValue:
+        case KIdShutterSpeedValue:
+        case KIdBrightnessValue:
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    TExifCommon::SetUint32( CONST_CAST( TUint8*, buffer->Ptr() ), aNumerator );
+    TExifCommon::SetUint32( 
+        CONST_CAST( TUint8*, buffer->Ptr() + 4 ), aDenominator );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( ifdType, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetThumbnailTagDataL
+// Sets the given 16-bit unsigned integer to the data of a thumbnail (IFD1) tag 
+// specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetThumbnailTagDataL( TUint16 aTagId, TUint16 aTagData )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagShort;
+    TUint32 tagCount = 1;
+    HBufC8* buffer = HBufC8::NewL( 2 );
+    buffer->Des().SetLength( 2 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdCompression:
+        case KIdResolutionUnit:
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    TExifCommon::SetUint16( CONST_CAST( TUint8*, buffer->Ptr() ), aTagData );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( EIfd1, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetThumbnailTagDataL
+// Sets the given 32-bit unsigned integer to the data of a thumbnail (IFD1) tag 
+// specified by the given tag ID,
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetThumbnailTagDataL( TUint16 aTagId, TUint32 aTagData )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagLong;
+    TUint32 tagCount = 1;
+    HBufC8* buffer = HBufC8::NewL( 4 );
+    buffer->Des().SetLength( 4 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdJpegInterchangeFormat:
+        case KIdJpegInterchangeFormatLength:
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    TExifCommon::SetUint32( CONST_CAST( TUint8*, buffer->Ptr() ), aTagData );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( EIfd1, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetThumbnailTagDataL
+// Sets the given 64-bit (2 x 32-bit ) unsigned integers to the data of a 
+// thumbnail (IFD1) tag specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetThumbnailTagDataL( 
+    TUint16 aTagId, 
+    TUint32 aNumerator, 
+    TUint32 aDenominator )
+    {
+    CExifTag::TExifTagDataType tagType = CExifTag::ETagRational;
+    TUint32 tagCount = 1;
+    HBufC8* buffer = HBufC8::NewL( 8 );
+    buffer->Des().SetLength( 8 );
+    CleanupStack::PushL( buffer );
+    switch ( aTagId )
+        {
+        case KIdXResolution:
+        case KIdYResolution:
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    TExifCommon::SetUint32( CONST_CAST( TUint8*, buffer->Ptr() ), aNumerator );
+    TExifCommon::SetUint32( 
+        CONST_CAST( TUint8*, buffer->Ptr() + 4 ), aDenominator );
+    CExifTagImpl* tag = CExifTagImpl::NewL( aTagId, tagType, tagCount, buffer, ETrue );
+    CleanupStack::Pop( buffer );
+    CleanupStack::PushL( tag );
+    InsertTagL( EIfd1, tag, ETrue );
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagData
+// Gets the 8-bit integer data of a tag specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetTagData( TUint16 aTagId, TInt8& aTagData ) const
+    {
+    TExifIfdType ifdType = EIfdExif;
+    switch ( aTagId )
+        {
+        case KIdFileSource:
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    TPtrC8 tagData = tag->Data();
+    aTagData = *REINTERPRET_CAST( TInt8*, CONST_CAST( TUint8*, tagData.Ptr() ) );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagData
+// Gets the 16-bit unsigned integer data of a tag specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetTagData( TUint16 aTagId, TUint16& aTagData ) const
+    {
+    TExifIfdType ifdType = EIfdExif;
+    switch ( aTagId )
+        {
+        case KIdFlash:
+        case KIdColorSpace:
+        case KIdExposureMode:
+        case KIdWhiteBalance:
+        case KIdSceneCaptureType:
+        case KIdExposureProgram:
+        case KIdMeteringMode:
+        case KIdLightSource:
+        case KIdContrast:
+        case KIdSaturation:
+        case KIdSharpness:
+        case KIdCustomRendered:
+        case KIdGainControl:
+            break;
+        case KIdOrientation:
+        case KIdResolutionUnit:
+        case KIdYCbCrPositioning:
+            ifdType = EIfd0;
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aTagData = TExifCommon::Uint16L( 
+        CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagData
+// Gets the 32-bit unsigned integer data of a tag specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetTagData( TUint16 aTagId, TUint32& aTagData ) const
+    {
+    TExifIfdType ifdType = EIfdExif;
+    switch ( aTagId )
+        {
+        case KIdComponentsConfiguration:
+        case KIdPixelXDimension:
+        case KIdPixelYDimension:
+        case KIdExifVersion:
+        case KIdFlashPixVersion:
+        case KIdIntOpIfdPointer:
+            break;
+        case KIdGpsVersion:
+            ifdType = EIfdGps;
+            break;
+        case KIdExifIfdPointer:
+        case KIdGpsIfdPointer:
+            ifdType = EIfd0;
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = 
+        CONST_CAST( CExifTagImpl*, GetTagL( ifdType, aTagId ) ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    TPtrC8 tagData = tag->Data();
+    if ( tagData.Length() == 2)
+        {
+        TRAP( error, aTagData = STATIC_CAST( TUint32, 
+            TExifCommon::Uint16L( CONST_CAST( TUint8*, tagData.Ptr() ) ) ) );
+        }
+    else
+        {
+        TRAP( error, aTagData = TExifCommon::Uint32L( 
+            CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+        }
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagDataL
+// Gets the data buffer of a tag specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+HBufC8* CExifCore::GetTagDataL( TUint16 aTagId ) const
+    {
+    TExifIfdType ifdType = EIfd0;
+    switch ( aTagId )
+        {
+        case KIdImageDescription:
+        case KIdMake:
+        case KIdModel:
+        case KIdTransferFunction:
+        case KIdDateTime:
+        case KIdSoftware:
+        case KIdCopyright:
+            break;
+        case KIdIsoSpeedRatings:
+        case KIdDateTimeOriginal:
+        case KIdDateTimeDigitized:
+        case KIdMakerNote:
+        case KIdUserComment:
+        case KIdRelatedSoundFile:
+            ifdType = EIfdExif;
+            break;
+        default:
+            User::Leave( KErrNotSupported );
+        }
+    const CExifTagImpl* tag = GetTagL( ifdType, aTagId );
+    
+    return tag->Data().AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagData
+// Gets the 64-bit (2 x 32-bit) unsigned integer data of a tag specified by the 
+// given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetTagData( 
+    TUint16 aTagId, 
+    TUint32& aNumerator, 
+    TUint32& aDenominator ) const
+    {
+    TExifIfdType ifdType = EIfd0;
+    switch ( aTagId )
+        {
+        case KIdXResolution:
+        case KIdYResolution:
+            break;
+        case KIdExposureTime:
+        case KIdApertureValue:
+        case KIdDigitalZoomRatio:
+            ifdType = EIfdExif;
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aNumerator = TExifCommon::Uint32L( 
+        CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    if ( error )
+        {
+        return error;
+        }
+    TRAP( error, aDenominator = TExifCommon::Uint32L( 
+        CONST_CAST( TUint8*, tagData.Ptr() + 4 ) ) );
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagData
+// Gets the 64-bit (2 x 32-bit) integer data of tag specified by the given tag 
+// ID
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetTagData( 
+    TUint16 aTagId, 
+    TInt32& aNumerator, 
+    TInt32& aDenominator ) const
+    {
+    TExifIfdType ifdType = EIfdExif;
+    switch ( aTagId )
+        {
+        case KIdExposureBiasValue:
+        case KIdShutterSpeedValue:
+        case KIdBrightnessValue:
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aNumerator = TExifCommon::Int32L( 
+        CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    if ( error ) 
+        {
+        return error;
+        }
+    TRAP( error, aDenominator = TExifCommon::Int32L( 
+        CONST_CAST( TUint8*, tagData.Ptr() + 4 ) ));
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetThumbnailTagData
+// Gets the 16-bit unsigned integer data of a thumbnail (IFD1) tag specified by 
+// the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetThumbnailTagData( TUint16 aTagId, TUint16& aTagData ) const
+    {
+    LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData TUint16 entering" ));
+    TExifIfdType ifdType = EIfd1;
+    switch ( aTagId )
+        {
+        case KIdResolutionUnit:
+        case KIdCompression:
+            break;
+        default:
+            LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: KErrNotSupported" ));
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: KErrNotFound" ));
+        return KErrNotFound;
+        }
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aTagData = TExifCommon::Uint16L( 
+        CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    LOGTEXT2( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: error=%d" ), error);
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetThumbnailTagData
+// Gets the 32-bit unsigned integer data of a thumbnail (IFD1) tag specified by 
+// the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetThumbnailTagData( TUint16 aTagId, TUint32& aTagData ) const
+    {
+    LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData TUint32 entering" ));
+    TExifIfdType ifdType = EIfd1;
+    switch ( aTagId )
+        {
+        case KIdJpegInterchangeFormat:
+        case KIdJpegInterchangeFormatLength:
+            break;
+        default:
+            LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: KErrNotSupported" ));
+            return KErrNotSupported;
+        }
+    CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = CONST_CAST( CExifTagImpl*, GetTagL( ifdType, aTagId ) ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        LOGTEXT( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: KErrNotFound" ));
+        return KErrNotFound;
+        }
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aTagData = TExifCommon::Uint32L( 
+        CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    LOGTEXT2( _L( "ExifLib: CExifCore::GetThumbnailTagData returning: error=%d" ), error);
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetThumbnailTagData
+// Gets the 64-bit (2 x 32-bit) unsigned integer data of a thumbnail (IFD1) tag 
+// specified by the given tag ID.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetThumbnailTagData( 
+    TUint16 aTagId, 
+    TUint32& aNumerator, 
+    TUint32& aDenominator ) const
+    {
+    TExifIfdType ifdType = EIfd1;
+    switch ( aTagId )
+        {
+        case KIdXResolution:
+        case KIdYResolution:
+            break;
+        default:
+            return KErrNotSupported;
+        }
+    const CExifTagImpl* tag = NULL;
+    TRAPD( error, tag = GetTagL( ifdType, aTagId ) );
+    if ( ( error ) || ( !tag ) )
+        {
+        return KErrNotFound;
+        }
+    
+    TPtrC8 tagData = tag->Data();
+    TRAP( error, aNumerator = 
+        TExifCommon::Uint32L( CONST_CAST( TUint8*, tagData.Ptr() ) ) );
+    if ( error )
+        {
+        return error;
+        }
+    TRAP( error, aDenominator = 
+        TExifCommon::Uint32L( CONST_CAST( TUint8*, tagData.Ptr() + 4 ) ) );
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagL
+// Gets the tag instance having the given tag ID from the specified IFD 
+// structure
+// -----------------------------------------------------------------------------
+//
+const CExifTagImpl* CExifCore::GetTagL( 
+    TExifIfdType aIfdType, TUint16 aTagId ) const
+    {
+    switch ( aIfdType )
+        {
+        case EIfd0:
+        case EIfdExif:
+        case EIfd1:
+        case EIfdGps:
+        case EIfdIntOp:
+            if ( !iIfdArray[aIfdType] )
+                {
+                User::Leave( KErrNotFound );
+                }
+            return iIfdArray[aIfdType]->GetTagL( aTagId );
+        default:
+            User::Leave( KErrArgument );
+        }
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::DeleteTag
+// Removes the tag instance having the given tag ID from the specified IFD 
+// structure
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::DeleteTag( TExifIfdType aIfdType, TUint16 aTagId )
+    {
+    switch ( aIfdType )
+        {
+        case EIfd0:
+        case EIfdExif:
+        case EIfd1:
+        case EIfdGps:
+        case EIfdIntOp:
+            {
+            if ( !iIfdArray[aIfdType] )
+                {
+                return KErrNotFound;
+                }
+            TInt error = iIfdArray[aIfdType]->DeleteTag( aTagId );
+            if ( error )
+                {
+                return error;
+                }
+            if ( iIfdArray[aIfdType]->Size() )
+                {
+                return KErrNone;
+                }
+            return DeleteIfd( aIfdType );
+            }
+        default:
+            return KErrArgument;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetTagIdsL
+// Gets the tag IDs and the number of tags in the specified IFD structure.
+// -----------------------------------------------------------------------------
+//
+TUint16* CExifCore::GetTagIdsL( TExifIfdType aIfdType, TInt& aNoTags ) const
+    {
+    switch ( aIfdType )
+        {
+        case EIfd0:
+        case EIfdExif:
+        case EIfd1:
+        case EIfdGps:
+        case EIfdIntOp:
+            if ( !iIfdArray[aIfdType] )
+                {
+                User::Leave( KErrNotFound );
+                }
+            return iIfdArray[aIfdType]->GetTagIdsL( aNoTags );
+        default:
+            User::Leave( KErrArgument );
+        }
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::iExifCore->CreateIfdL
+// Instantiates the specified IFD structure.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::CreateIfdL( TExifIfdType aIfdType )
+    {
+    if ( App1Size() > ( KMaxApp1Size - 6 ) )
+        {
+        User::Leave( KErrOverflow );
+        }
+    switch ( aIfdType )
+        {
+        case EIfd0:
+        case EIfdExif:
+        case EIfd1:
+        case EIfdGps:
+        case EIfdIntOp:
+            iIfdArray[aIfdType] = CExifIfd::NewBaseL( aIfdType );
+            break;
+        default:
+            User::Leave( KErrArgument );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::DeleteIfd
+// Removes the specified IFD structure and all its tags.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::DeleteIfd( TExifIfdType aIfdType )
+    {
+    switch ( aIfdType )
+        {
+        case EIfd0:
+            break;
+        case EIfdExif:
+            break;
+        case EIfd1:
+            iIfdArray[EIfd0]->SetNextIfdOffset( 0 );
+            break;
+        case EIfdGps:
+            iIfdArray[EIfd0]->DeleteTag( KIdGpsIfdPointer );
+            break;
+        case EIfdIntOp:
+            iIfdArray[EIfdExif]->DeleteTag( KIdIntOpIfdPointer );
+            break;
+        default:
+            return KErrArgument;
+        }
+    if ( iIfdArray[aIfdType] )
+        {
+        delete ( iIfdArray[aIfdType] );
+        iIfdArray[aIfdType] = 0;
+        return KErrNone;
+        }
+    else
+        {
+        return KErrNotFound;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetIfdTypesL
+// Gets the IFD types and number of IFDs in the file format.
+// -----------------------------------------------------------------------------
+//
+TExifIfdType* CExifCore::GetIfdTypesL( TInt& aNoIfd ) const
+    {
+    TInt noIfd = 0;
+    TUint i = 0;
+    for ( i = 0; i < KIfdNo; ++i )
+        {
+        if ( iIfdArray[i] )
+            {
+            ++noIfd;
+            }
+        }
+    if ( !noIfd )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    TExifIfdType* ifdTypes = STATIC_CAST( TExifIfdType*, 
+        User::AllocL( sizeof( TExifIfdType ) * noIfd ) );
+    aNoIfd = noIfd;
+    noIfd = 0;
+    for ( i=EIfd0; i<=EIfdIntOp; ++i )
+        {
+        if ( iIfdArray[i] )
+            {
+            ifdTypes[noIfd] = STATIC_CAST( TExifIfdType, i );
+            ++noIfd;
+            }
+        }
+    return ifdTypes;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetThumbnailL
+// Gets the Exif thumbnail image data from the IFD1 structure.
+// -----------------------------------------------------------------------------
+//
+HBufC8* CExifCore::GetThumbnailL() const
+    {
+    if ( !iIfdArray[EIfd1] )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    TDesC8* thumbnailData = NULL;
+    User::LeaveIfError( ( STATIC_CAST( CExifIfd1*, iIfdArray[EIfd1] ) )->
+        GetThumbnailData( thumbnailData ) );
+
+    // Next check needed when option ENoTagChecking is used
+    if ( !thumbnailData )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    return thumbnailData->AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::InsertThumbnailL
+// Inserts/Updates the given Exif thumbnail image data in the IFD1 structure.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::InsertThumbnailL( TDesC8* aThumbnailData )
+    {
+    if ( STATIC_CAST( TUint, App1Size() + aThumbnailData->Length() ) > 
+        KMaxApp1Size )
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    TUint8* jpgStartPtr = CONST_CAST( TUint8*, aThumbnailData->Ptr() );
+    TUint8* jpgEndPtr = jpgStartPtr + aThumbnailData->Length();
+
+    jpgStartPtr = TExifCommon::LocateJpegMarkerPtr( 
+        KSoi, jpgStartPtr, jpgEndPtr );
+    if( !jpgStartPtr )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    jpgStartPtr = TExifCommon::LocateJpegMarkerPtr( 
+        KSof0, jpgStartPtr, jpgEndPtr );
+    if( !jpgStartPtr )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    jpgStartPtr = TExifCommon::LocateJpegMarkerPtr( 
+        KEoi, jpgStartPtr, jpgEndPtr );
+    if( !jpgStartPtr )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    if ( !iIfdArray[EIfd1] )
+        {
+        CreateIfdL( EIfd1 );
+        }
+    User::LeaveIfError( ( STATIC_CAST( CExifIfd1*, iIfdArray[EIfd1] ) )->
+        SetThumbnailData( aThumbnailData ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::RemoveThumbnail
+// Removes the Exif thumbnail image data from the IFD1 structure.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::RemoveThumbnail()
+    {
+    if ( !iIfdArray[EIfd1] )
+        {
+        return KErrNotFound;
+        }
+    return 
+        ( STATIC_CAST( CExifIfd1*, iIfdArray[EIfd1] ) )->RemoveThumbnailData();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CExifCore::WriteExifDataL
+// Writes the Exif data to the given descriptor starting from the specified 
+// position/offset.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::WriteExifDataL( HBufC8*& aExifData, TUint& aPos )
+    {
+    // Ensure byte alignment
+    if ( ( aExifData->Length() - aPos ) % 2 > 0 )
+        {
+        User::Leave( KErrGeneral );
+        }
+    TUint16* exifDataPtr = REINTERPRET_CAST( TUint16*, 
+        CONST_CAST( TUint8*, aExifData->Ptr() ) + aPos );
+    WriteExifHeaderL( exifDataPtr, aPos );
+    WriteIfdL( exifDataPtr, EIfd0, aPos );
+    WriteIfdL( exifDataPtr, EIfdExif, aPos );
+    WriteIfdL( exifDataPtr, EIfdGps, aPos );
+    WriteIfdL( exifDataPtr, EIfdIntOp, aPos );
+    WriteIfdL( exifDataPtr, EIfd1, aPos );
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::WriteJpegHeaderL
+// Writes the Jpeg header to the given descriptor starting from the specified 
+// position/offset.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::WriteJpegHeaderL( HBufC8*& aExifData, TUint& aPos )
+    {
+    if ( ( aExifData->Length() - aPos ) % 2 > 0 )
+        {
+        User::Leave( KErrGeneral );
+        }
+    TUint16* exifDataPtr = REINTERPRET_CAST( TUint16*, 
+        CONST_CAST( TUint8*, aExifData->Ptr() ) + aPos );
+    *exifDataPtr = KSoiRev;
+    aPos+=2;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::Finalize
+// Finalizes the Exif data to ensure the validity, updates the internal offsets.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::Finalize()
+    {
+    TInt error = 0;
+    TUint32 ifdOffset = FindIfdOffset( EIfdExif );
+    TRAP( error, SetTagDataL( KIdExifIfdPointer, ifdOffset ) );
+    if ( error )
+        {
+        return error;
+        }
+
+    ifdOffset = FindIfdOffset( EIfdGps );
+    if ( ifdOffset )
+        {
+        TRAP( error, SetTagDataL( KIdGpsIfdPointer, ifdOffset ) );
+        if ( error )
+            {
+            return error;
+            }
+        }
+    else
+        {
+        DeleteTag( EIfd0, KIdGpsIfdPointer );
+        }
+    
+    ifdOffset = FindIfdOffset( EIfdIntOp );
+    if ( ifdOffset )
+        {
+        TRAP( error, SetTagDataL( KIdIntOpIfdPointer, ifdOffset ) );
+        if ( error )
+            {
+            return error;
+            }
+        }
+    else
+        {
+        DeleteTag( EIfdExif, KIdIntOpIfdPointer );
+        }
+    
+    if ( iIfdArray[EIfd1] )
+        {
+        if ( !STATIC_CAST( CExifIfd1*, iIfdArray[EIfd1] )->ThumbnailSize() )
+            {
+            DeleteIfd( EIfd1 );
+            iIfdArray[EIfd0]->SetNextIfdOffset( 0 );
+            }
+        else
+            {
+            ifdOffset = FindIfdOffset( EIfd1 );
+            iIfdArray[EIfd0]->SetNextIfdOffset( ifdOffset );
+            TRAP( error, SetThumbnailTagDataL( KIdJpegInterchangeFormat, 
+                STATIC_CAST( TUint32, ifdOffset + iIfdArray[EIfd1]->Size() ) ) );
+            if ( error )
+                {
+                return error;
+                }
+            TRAP( error, SetThumbnailTagDataL( KIdJpegInterchangeFormatLength, 
+                STATIC_CAST( TUint32, STATIC_CAST( CExifIfd1*, 
+                iIfdArray[EIfd1] )->ThumbnailSize() ) ) );
+            if ( error )
+                {
+                return error;
+                }
+            TRAP( error, SetThumbnailTagDataL( KIdCompression, KCompressed ) );
+            if ( error )
+                {
+                return error;
+                }
+            }
+        }
+        
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::TotalSize
+// Returns the total size of the Exif file format in bytes.
+// -----------------------------------------------------------------------------
+//
+TUint CExifCore::TotalSize() const
+    {
+    return ( App1Size() + 4 + JpegSize() );
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::JpegSize
+// Returns the size of the Jpeg image in the Exif file format, excluding SOI 
+// and APP markers in bytes.
+// -----------------------------------------------------------------------------
+//
+TUint CExifCore::JpegSize() const
+    {
+    return iJpgEndOffset - iJpgStartOffset;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::App1Size
+// Returns the size of the APP1 marker, which includes the Exif-specific data 
+// in bytes
+// -----------------------------------------------------------------------------
+//
+TUint16 CExifCore::App1Size() const
+    {
+    TUint16 app1Size = 0;
+    if ( iIfdArray[EIfd0] )
+        {
+        app1Size = STATIC_CAST( TUint16, app1Size + iIfdArray[EIfd0]->Size() );
+        }
+    if ( iIfdArray[EIfdExif] )
+        {
+        app1Size = 
+            STATIC_CAST( TUint16, app1Size + iIfdArray[EIfdExif]->Size() );
+        }
+    if ( iIfdArray[EIfd1] )
+        {
+        app1Size = STATIC_CAST( TUint16, app1Size + iIfdArray[EIfd1]->Size() );
+        app1Size = STATIC_CAST( TUint16, app1Size + ( STATIC_CAST( CExifIfd1*, 
+            iIfdArray[EIfd1] )->ThumbnailSize() ) );
+        }
+    if ( iIfdArray[EIfdGps] )
+        {
+        app1Size  = 
+            STATIC_CAST( TUint16, app1Size + iIfdArray[EIfdGps]->Size() );
+        }
+    if ( iIfdArray[EIfdIntOp] )
+        {
+        app1Size = 
+            STATIC_CAST( TUint16, app1Size + iIfdArray[EIfdIntOp]->Size() );
+        }
+    return STATIC_CAST( TUint16, app1Size + 16 );
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::IsValid
+// Checks if the Exif data is in valid Exif v2.2 format and contains all 
+// mandatory information.
+// -----------------------------------------------------------------------------
+//
+TBool CExifCore::IsValid() const
+    {
+    if ( (!iIfdArray[EIfd0] ) || (!iIfdArray[EIfdExif] ) )
+        {
+        return EFalse;
+        }
+
+    if ( !iIfdArray[EIfd0]->IsValid() )
+        {
+        return EFalse;
+        }
+
+    if ( !iIfdArray[EIfdExif]->IsValid() )
+        {
+        return EFalse;
+        }
+
+    if ( iIfdArray[EIfd1] )
+        {
+        if ( !iIfdArray[EIfd1]->IsValid() )
+            {
+            return EFalse;
+            }
+        }
+    if ( iIfdArray[EIfdGps] )
+        {
+        if ( !iIfdArray[EIfdGps]->IsValid() )
+            {
+            return EFalse;
+            }
+        TRAPD( error, GetTagL( EIfd0, KIdGpsIfdPointer ) );
+        if ( error )
+            {
+            return EFalse;
+            }
+        }
+
+    if ( iIfdArray[EIfdIntOp] )
+        {
+        if ( !iIfdArray[EIfdIntOp]->IsValid() )
+            {
+            return EFalse;
+            }
+        TRAPD( error, GetTagL( EIfdExif, KIdIntOpIfdPointer ) );
+        if ( error )
+            {
+            return EFalse;
+            }
+        }
+
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::TagIsValid
+// Checks if the specified tag information conforms to the Full Validity 
+// characteristics (Data count is correct, data type matches tag ID and data 
+// value falls into the predefined range).
+// -----------------------------------------------------------------------------
+//
+TBool CExifCore::TagIsValid( TExifTagInfo aTagInfo, TExifIfdType aIfdType ) const
+    {
+    LOGTEXT3( _L( "ExifLib: CExifCore::TagIsValid() entering: aIfdType=0x%x, aTagInfo.iId=0x%x" ), aIfdType, aTagInfo.iId );
+    TInt noTags = 0;
+    const TReferenceTag* tags = NULL;
+    switch ( aIfdType )
+        {
+        case EIfd0:
+            noTags = KNoIfd0Tags;
+            tags = ifd0Tags;
+            break;
+        case EIfdExif:
+            noTags = KNoIfdExifTags;
+            tags = ifdExifTags;
+            break;
+        case EIfd1:
+            noTags = KNoIfd1Tags;
+            tags = ifd1Tags;
+            break;
+        case EIfdGps:
+            noTags = KNoIfdGpsTags;
+            tags = ifdGpsTags;
+            break;
+        case EIfdIntOp:
+            noTags = KNoIfdIntOpTags;
+            tags = ifdIntOpTags;
+            break;
+        default:
+            return EFalse;
+        }
+
+    TInt k = 0;
+    TBool found = EFalse;
+    for ( k = 0; ( k < noTags ) && ( !found ); ++k )
+        {
+        if ( tags[k].iId == aTagInfo.iId )
+            {
+            found = ETrue;
+            }
+        }
+
+    if ( !found )
+        {
+        LOGTEXT( _L( "ExifLib: CExifCore::TagIsValid() returning EFalse (tag not found)" ));
+        return EFalse;
+        }
+    // k locates the item next to the found item. Make it locate the found.
+    --k;
+
+    if ( tags[k].iDataType != TReferenceTag::ETagLongOrShort )
+        {
+        if ( tags[k].iDataType != aTagInfo.iDataType )
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::TagIsValid() returning EFalse 1 aTagInfo.iDataType=0x%x" ), aTagInfo.iDataType );
+            return EFalse;
+            }
+        }
+    else if ( ( aTagInfo.iDataType != CExifTag::ETagShort ) && 
+        ( aTagInfo.iDataType != CExifTag::ETagLong ) )
+        {
+        LOGTEXT2( _L( "ExifLib: CExifCore::TagIsValid() returning EFalse 2 aTagInfo.iDataType=0x%x" ), aTagInfo.iDataType );
+        return EFalse;
+        }
+    else
+        {
+        // Nothing to check for this case!
+        }
+
+    if ( tags[k].iDataCount != KAny )
+        {
+        if ( tags[k].iDataCount != aTagInfo.iDataCount )
+            {
+            LOGTEXT2( _L( "ExifLib: CExifCore::TagIsValid() returning EFalse aTagInfo.iDataCount=0x%x" ), aTagInfo.iDataCount );
+            return EFalse;
+            }
+        }
+
+    LOGTEXT( _L( "ExifLib: CExifCore::TagIsValid() returning ETrue" ));
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::IfdExists
+// Checks if the specified IFD structure exists in the Exif data.
+// -----------------------------------------------------------------------------
+//
+TBool CExifCore::IfdExists( TExifIfdType aIfdType ) const
+    {
+    if ( iIfdArray[aIfdType] )
+        {
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::TagExists
+// Checks if the tag having the given tag ID exists in the specified IFD 
+// structure
+// -----------------------------------------------------------------------------
+//
+TBool CExifCore::TagExists( TUint16 aTagId, TExifIfdType aIfdType ) const
+    {
+    if ( iIfdArray[aIfdType] )
+        {
+        return iIfdArray[aIfdType]->TagExists( aTagId );
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetJpgOffsets
+// Sets the given Jpeg data start and end offsets.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetJpgOffsets( TUint32 aJpgStartOffset, TUint32 aJpgEndOffset )
+    {
+    iJpgStartOffset = aJpgStartOffset;
+    iJpgEndOffset = aJpgEndOffset;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::GetJpegData
+// Gets the pure Jpeg image data excluding the SOI and APP1 markers.
+// -----------------------------------------------------------------------------
+//
+TInt CExifCore::GetJpegData( TPtr8 aJpgPointer ) const
+    {
+    if ( !iJpgStartOffset )
+        {
+        return KErrGeneral;
+        }
+
+    TUint8* jpgStartPtr = CONST_CAST( TUint8*, iDataStartPtr + iJpgStartOffset );
+    if ( *jpgStartPtr != KMarkerStart )
+        {
+        return KErrGeneral;
+        }
+    aJpgPointer.Copy( jpgStartPtr, JpegSize() );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::SetDataStartPtr
+// Sets the Exif data start pointer.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::SetDataStartPtr( const TUint8* aPtr )
+    {
+    iDataStartPtr = aPtr;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::WriteExifHeaderL
+// Writes the Exif header to the location, which is defined by the given pointer 
+// and the offset.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::WriteExifHeaderL( TUint16*& aExifDataPtr, TUint& aPos )
+    {
+    if ( !aExifDataPtr )
+        {
+        User::Leave( KErrGeneral );
+        }
+    *aExifDataPtr++ = KApp1Rev;
+    TUint16 app1Size = App1Size();
+    *REINTERPRET_CAST( TUint8*, aExifDataPtr ) = STATIC_CAST( TUint8, 
+        app1Size >> 8 ); 
+    *( REINTERPRET_CAST( TUint8*, aExifDataPtr ) + 1 ) = STATIC_CAST( 
+        TUint8, app1Size ); 
+    ++aExifDataPtr;
+    TExifCommon::SetUint32( REINTERPRET_CAST( TUint8*, aExifDataPtr ), 
+        KExifIdentifierRev );
+    aExifDataPtr+=2;
+    *aExifDataPtr++ = KExifPad;
+    *aExifDataPtr++ = KLittleEndian;
+    *aExifDataPtr++ = KExifDummyRev;
+    TExifCommon::SetUint32( REINTERPRET_CAST( TUint8*, aExifDataPtr ), 
+        KHeaderOffset );
+    aExifDataPtr+=2;
+    aPos = 20;
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::WriteIfdl
+// Writes the specified IFD data to the location, which is defined by the given 
+// pointer and the offset.
+// -----------------------------------------------------------------------------
+//
+void CExifCore::WriteIfdL( 
+    TUint16*& aExifDataPtr, 
+    TExifIfdType aIfdType, 
+    TUint& aPos )
+    {
+    if ( !aExifDataPtr )
+        {
+        User::Leave( KErrGeneral );
+        }
+    if ( iIfdArray[aIfdType] )
+        {
+        iIfdArray[aIfdType]->WriteTagsL( aExifDataPtr, aPos );
+        if ( aIfdType == EIfd1 )
+            {
+            (STATIC_CAST( CExifIfd1*, iIfdArray[aIfdType] ) )->WriteThumbnailL( 
+                REINTERPRET_CAST( TUint8*&, aExifDataPtr ), aPos );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CExifCore::FindIfdOffset
+// Returns the offset of the specified IFD structure in the Exif data.
+// -----------------------------------------------------------------------------
+//
+TUint32 CExifCore::FindIfdOffset( TExifIfdType aIfdType ) const
+    {
+    if ( !iIfdArray[aIfdType] )
+        {
+        return 0;
+        }
+    TUint32 offset = 8;
+    switch ( aIfdType )
+        {
+        case EIfd0:
+            break;
+        case EIfdExif:
+            offset += ( iIfdArray[EIfd0]->Size() );
+            break;
+        case EIfd1:
+            offset += ( iIfdArray[EIfd0]->Size() + iIfdArray[EIfdExif]->Size() );
+            if ( iIfdArray[EIfdGps] )
+                {
+                offset += iIfdArray[EIfdGps]->Size();
+                }
+            if ( iIfdArray[EIfdIntOp] )
+                {
+                offset += iIfdArray[EIfdIntOp]->Size();
+                }
+            break;
+        case EIfdGps:
+            offset += ( iIfdArray[EIfd0]->Size() + iIfdArray[EIfdExif]->Size() );
+            break;
+        case EIfdIntOp:
+            offset += ( iIfdArray[EIfd0]->Size() + iIfdArray[EIfdExif]->Size() );
+            if ( iIfdArray[EIfdGps] )
+                {
+                offset += iIfdArray[EIfdGps]->Size();
+                }
+            break;
+        default:
+            return 0;
+        }
+    return offset;
+    }
+