imagingmodules/exiflib/src/ExifCore.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:22:31 +0200
changeset 0 469c91dae73b
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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;
    }