harvester/composerplugins/imagecomposer/src/imagecomposerao.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:24:24 +0100
branchRCL_3
changeset 21 85f623e1ef41
parent 20 f23c07ec56e2
child 22 29d87345eaeb
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Composer image active object
*
*/


#include <e32base.h>
#include <e32debug.h>

#include <mderelation.h>
#include <mderelationquery.h>
#include <mdelogiccondition.h>

#include "mdeharvestersession.h"
#include "mdeproperty.h"
#include "mdenamespacedef.h"
#include "imagecomposerao.h"
#include "harvesterlog.h"
#include "mdeconstants.h"
#include "mdsutils.h"
#include "mderelationcondition.h"
#include "mdeobjectdef.h"
#include "harvestercommon.h"

using namespace MdeConstants;

_LIT( KJpegMimeType, "image/jpeg" );

// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CImageComposerAO* CImageComposerAO::NewL()
    {
    WRITELOG( "CImageComposerAO::NewL()" );

    CImageComposerAO* self = new (ELeave) CImageComposerAO();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// ~CImageComposerAO
// ---------------------------------------------------------------------------
//
CImageComposerAO::~CImageComposerAO() // destruct
    {   
    WRITELOG( "CImageComposerAO::~CImageComposerAO()" );
    
    Cancel();
    
    iItemQueue.Close();
    
    iForceObjectIds.Close();
    iNextItemsSkip.Close();
    
    if ( iMdeObject )
        {
        delete iMdeObject;
        iMdeObject = NULL;
        }
    if ( iExifUtil )
    	{
    	delete iExifUtil;
    	iExifUtil = NULL;
    	}

    delete iRelationQuery;
    iRelationQuery = NULL;
    iFs.Close();
    
    delete iMdEHarvesterSession;
    iMdEHarvesterSession = NULL;
    }

// ---------------------------------------------------------------------------
// CComposerImagePlugin
// ---------------------------------------------------------------------------
//
CImageComposerAO::CImageComposerAO() : // first-phase C++ constructor
		CActive( KHarvesterPriorityComposerPlugin )
    {
    WRITELOG( "CImageComposerAO::CImageComposerAO()" );
    }

// ---------------------------------------------------------------------------
// ConstructL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::ConstructL() // second-phase constructor
    {
    WRITELOG( "CImageComposerAO::ConstructL()" );
    iMdeObject = NULL;
    iNextRequest = ERequestReady;
    iDefaultNamespace = NULL;
    iImageObjectDef = NULL;
    iObjectDef = NULL;
    iLocationObjectDef = NULL;

    CActiveScheduler::Add( this );
    
    iExifUtil = CHarvesterExifUtil::NewL();
    iFastModeEnabled = EFalse;
    User::LeaveIfError( iFs.Connect() );
    }
    
// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CImageComposerAO::DoCancel()
    {
    WRITELOG( "CImageComposerAO::DoCancel()" );
    }
    
// ---------------------------------------------------------------------------
// AddToQueue
// ---------------------------------------------------------------------------
//
void CImageComposerAO::AddToQueue( const RArray<TItemId>& aItems, TBool aForce )
    {
    WRITELOG( "CImageComposerAO::AddToQueue()" );
    
    // check if we should skip some items
    const TInt itemsCount = aItems.Count();
    for ( TInt i = 0; i < itemsCount; ++i )
        {
        const TInt res = iNextItemsSkip.FindInOrder( aItems[i],
        		TLinearOrder<TItemId>( CImageComposerAO::CompareTItemIds ) );
        if ( res != KErrNotFound && res >= 0 )
            {
            RArray<TItemId> objectId;
            objectId.Append( aItems[i] );
            TRAP_IGNORE( iMdEHarvesterSession->ResetPendingL( objectId ) );
            iNextItemsSkip.Remove( res );
            
            if( iNextItemsSkip.Count() == 0 )
            	{
            	iNextItemsSkip.Compress();
            	}
            objectId.Close();
            }
        else
            {
            iItemQueue.Append( aItems[i] );
            if ( aForce )
            	{
            	iForceObjectIds.Append( aItems[i] );
            	}
            }
        }
    if ( iNextRequest == ERequestReady )
    	{
    	SetNextRequest( ERequestGetObject );
    	}
    }
    
// ---------------------------------------------------------------------------
// IsComposingComplete()
// ---------------------------------------------------------------------------
//
TBool CImageComposerAO::IsComposingComplete()
    {
    WRITELOG( "CImageComposerAO::IsComposingComplete()" );
    return iNextRequest == ERequestReady;
    }

// ---------------------------------------------------------------------------
// SetSession
// ---------------------------------------------------------------------------
//
void CImageComposerAO::SetSession( CMdESession* aSession )
    {
    WRITELOG( "CImageComposerAO::SetSession()" );
    iSession = aSession;
    iExifUtil->SetSession(iSession);
    if( iSession )
    	{
    	iDefaultNamespace = NULL;
    	TRAP_IGNORE( iDefaultNamespace = &iSession->GetDefaultNamespaceDefL() );
    	
    	TRAP_IGNORE( iImageObjectDef = &iDefaultNamespace->GetObjectDefL( 
    			Image::KImageObject ) );
    	TRAP_IGNORE( iObjectDef = &iDefaultNamespace->GetObjectDefL( 
    			Object::KBaseObject ) );
    	TRAP_IGNORE( iLocationObjectDef = &iDefaultNamespace->GetObjectDefL( 
    			Location::KLocationObject ) );
    	
    	
		iMdEHarvesterSession = NULL;
    	TRAP_IGNORE( iMdEHarvesterSession 
    	        = CMdEHarvesterSession::NewL ( *iSession ));
    	}
    }

// ---------------------------------------------------------------------------
// RemoveSession
// ---------------------------------------------------------------------------
//
void CImageComposerAO::RemoveSession()
    {
    iSession = NULL;
    iExifUtil->SetSession( NULL );

    delete iMdEHarvesterSession;
    iMdEHarvesterSession = NULL;
    
    iDefaultNamespace = NULL;
    iImageObjectDef = NULL;
    iObjectDef = NULL;
    iLocationObjectDef = NULL;
    }

// ---------------------------------------------------------------------------
// RunL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::RunL()
    {
    WRITELOG( "CImageComposerAO::RunL()" );
    User::LeaveIfError( iStatus.Int() );
    
    if ( !iDefaultNamespace && iSession )
        {
        iDefaultNamespace = &iSession->GetDefaultNamespaceDefL();
        }
    
    switch ( iNextRequest )
        {
        case ERequestGetObject:
            {
            if( iItemQueue.Count() <= 0 )
            	{
                iItemQueue.Compress();
                if( iFastModeEnabled )
                    {
                    SetPriority( KHarvesterPriorityComposerPlugin );
                    }
            	SetNextRequest( ERequestReady );
            	}
            else
            	{
            	TItemId mdeObjectId = KNoId;
	            TRAPD( err, GetObjectFromMdeL( mdeObjectId ) );
	            
	            if ( err == KErrNone )
	                {    
	                CMdEProperty* prop = NULL;
	                CMdEPropertyDef& originPropDef = iMdeObject->Def().GetPropertyDefL( Object::KOriginProperty );
	                iMdeObject->Property( originPropDef, prop );
	                if( prop && prop->Uint8ValueL() == MdeConstants::Object::ECamera && !iFastModeEnabled )
	                    {
	                    iFastModeEnabled = ETrue;
	                    SetPriority( KHarvesterPriorityMonitorPlugin );
	                    }
	                else if( iFastModeEnabled )
	                    {
	                    iFastModeEnabled = EFalse;
	                    SetPriority( KHarvesterPriorityComposerPlugin );
	                    }
	                
	                SetNextRequest( ERequestCompose );
	                }
	            // if object does not exists, find next
	            else if ( err == KErrNotFound || err == KErrAbort )
	                 {
	                 if ( err == KErrAbort && mdeObjectId != KNoId )
	                	 {
		                 RArray<TItemId> objectId;
		                 objectId.Append( mdeObjectId );
		                 CleanupClosePushL( objectId );
		                 iMdEHarvesterSession->ResetPendingL( objectId );
		                 CleanupStack::PopAndDestroy( &objectId );
	                	 }
	                 SetNextRequest( ERequestGetObject );
	                 }
	                 
	            // something goes really wrong
	            else
	                 {
	                 User::Leave( err );
	                 }
            	}

            }
            break;
            
        case ERequestCompose:
            {
            ComposeL();

            if ( iMdeObject )
                {
                RArray<TItemId> objectId;
                objectId.Append( iMdeObject->Id() );
                TRAP_IGNORE( iMdEHarvesterSession->ResetPendingL( objectId ) );
                objectId.Close();

                delete iMdeObject;
                iMdeObject = NULL;
                }
            }
            break;
            
        case ERequestReady:
            {
            iForceObjectIds.Compress();
            }
            break;
            
        default:
            {
            User::Leave( KErrUnknown );
            }
            break;
        }
    }
    
// ---------------------------------------------------------------------------
// RunError
// ---------------------------------------------------------------------------
//
#ifdef _DEBUG
TInt CImageComposerAO::RunError( TInt aError )
#else
TInt CImageComposerAO::RunError( TInt )
#endif
    {
    WRITELOG1( "CImageComposerAO::RunError() - error code: %d", aError );
    if ( iMdeObject && iSession )
    	{
    	TRAP_IGNORE( iSession->CancelObjectL( *iMdeObject ) );
    	}
    SetNextRequest( ERequestGetObject );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// GetObjectFromMde
// ---------------------------------------------------------------------------
//
void CImageComposerAO::GetObjectFromMdeL(TItemId& aMdEObjectId)
    {
#ifdef _DEBUG
    _LIT( KPanicCategoryNsd, "NSD=NULL" );
    _LIT( KPanicCategoryOd,  "OD=NULL" );
    _LIT( KPanicCategoryId,  "ID=NULL" );
    _LIT( KPanicCategoryLd,  "LD=NULL" );
    __ASSERT_DEBUG( iDefaultNamespace, User::Panic( KPanicCategoryNsd, KErrBadHandle ) );
    __ASSERT_DEBUG( iObjectDef, User::Panic( KPanicCategoryOd,  KErrBadHandle ) );
    __ASSERT_DEBUG( iImageObjectDef, User::Panic( KPanicCategoryId,  KErrBadHandle ) );
    __ASSERT_DEBUG( iLocationObjectDef, User::Panic( KPanicCategoryLd,  KErrBadHandle ) );
#endif    
    
    WRITELOG( "CImageComposerAO::GetObjectFromMdeL() - start" );
    
    if ( !iSession )
    	{
    	WRITELOG( "CImageComposerAO::GetObjectFromMdeL() - iSession is NULL" );
    	User::Leave( KErrSessionClosed );
    	}

    TItemId objectId = KNoId;
    
    // get the object id from queue
    if( iItemQueue.Count() > 0 )
    	{
    	objectId = iItemQueue[0];
    	aMdEObjectId = objectId;
    	iItemQueue.Remove( 0 );
    	}
    
    // get object from db (NULL if not found)
    CMdEObject* mdeObject = iSession->GetObjectL( objectId, *iImageObjectDef );

    CleanupStack::PushL( mdeObject );
    
    if ( !mdeObject )
        {
        WRITELOG1( "CImageComposerAO::GetObjectFromMdeL() - could not find object id %d", objectId );
        User::Leave( KErrNotFound );
        }

    TInt force;
    force = iForceObjectIds.Find( objectId );
    if ( force != KErrNotFound )
    	{
    	iForceObjectIds.Remove( force );
    	
    	if( iForceObjectIds.Count() == 0 )
    		{
    		iForceObjectIds.Compress();
    		}
    	}
    else
    	{
	    // check if file's and object's last modified dates are equal
	    CMdEPropertyDef& lastModifiedDatePropDef = mdeObject->Def().GetPropertyDefL( 
	    		Object::KLastModifiedDateProperty );
	    CMdEProperty* lastModifiedDateProp = NULL;
	    mdeObject->Property( lastModifiedDatePropDef, lastModifiedDateProp );
	    if( lastModifiedDateProp )
	    	{
	    	TTime time = ((CMdETimeProperty*)lastModifiedDateProp)->Value();
	
	    	TEntry entry;
	    	TInt error = iFs.Entry( mdeObject->Uri(), entry );
	
	    	if( error != KErrNone || entry.iModified == time )
	    		{
	    		User::Leave( KErrAbort );
	    		}
	    	}
	    else
	    	{
	    	User::Leave( KErrNotFound );
	    	}   
    	}
    
    CleanupStack::Pop( mdeObject );
    iMdeObject = mdeObject;
    
    WRITELOG( "CImageComposerAO::GetObjectFromMdeL() - end" );
    }

// ---------------------------------------------------------------------------
// ComposeL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::ComposeL()
    {
#ifdef _DEBUG
    _LIT( KPanicCategoryNsd, "NSD=NULL" );
    _LIT( KPanicCategoryOd,  "OD=NULL" );
    _LIT( KPanicCategoryId,  "ID=NULL" );
    _LIT( KPanicCategoryLd,  "LD=NULL" );
    __ASSERT_DEBUG( iDefaultNamespace, User::Panic( KPanicCategoryNsd, KErrBadHandle ) );
    __ASSERT_DEBUG( iObjectDef, User::Panic( KPanicCategoryOd,  KErrBadHandle ) );
    __ASSERT_DEBUG( iImageObjectDef, User::Panic( KPanicCategoryId,  KErrBadHandle ) );
    __ASSERT_DEBUG( iLocationObjectDef, User::Panic( KPanicCategoryLd,  KErrBadHandle ) );
#endif    
    
#ifdef _DEBUG    
    WRITELOG( "CImageComposerAO::ComposeL()" );
    WRITELOG1( "CImageComposerAO::ComposeL() - Compose Start Object ID: %d", iMdeObject->Id() );
#endif

    if ( !iSession )
    	{
    	WRITELOG( "CImageComposerAO::ComposeL() - iSession is NULL!" );
    	User::Leave( KErrSessionClosed );
    	}

    // 1. Read Exif image from the file to a buffer...
    RFile64 file;
    CleanupClosePushL( file );
    WRITELOG( "CImageComposerAO::ComposeL() - open file for reading" );
    User::LeaveIfError( file.Open( iFs, iMdeObject->Uri(), EFileRead ) );

    TInt64 dataSize = 0;
    file.Size( dataSize );
    HBufC8* exif = HBufC8::NewL( dataSize );
    CleanupStack::PushL( exif );
    TPtr8 exifPtr = exif->Des();
    User::LeaveIfError( file.Read( exifPtr ) );
    CleanupStack::Pop( exif );             // exif needs to be popped and pushed again
    CleanupStack::PopAndDestroy( &file );  // to get file out of CleanupStack
    CleanupStack::PushL( exif );
    
    HBufC8* modifiedExif = NULL;
    
    iExifUtil->ComposeExifDataL(*iMdeObject, exifPtr, modifiedExif);
   
    // modifiedExif is NULL if no changes were made
    if ( modifiedExif )
        {
        CleanupStack::PushL( modifiedExif );
        
        if ( !iMdeObject->OpenForModifications() )
            {
            const TItemId objectId = iMdeObject->Id();
            delete iMdeObject;
            iMdeObject = NULL;
            iMdeObject = iSession->OpenObjectL( objectId, *iImageObjectDef );
            if ( !iMdeObject )
                {
                User::Leave( KErrAccessDenied );
                }
            }

    	// set position to begin of file
        WRITELOG( "CImageComposerAO::ComposeL() - open file for writing" );
        User::LeaveIfError( file.Open( iFs, iMdeObject->Uri(), EFileWrite ) );
        CleanupClosePushL( file );

        TInt64 pos = 0;
        WRITELOG( "CImageComposerAO::ComposeL() - seek to position 0" );
        User::LeaveIfError( file.Seek( ESeekStart, pos ) );

        WRITELOG( "CImageComposerAO::ComposeL() - write buffer (exif) to file" );
        User::LeaveIfError( file.Write( modifiedExif->Des(), modifiedExif->Des().Length() ) );

        CleanupStack::PopAndDestroy( 2, modifiedExif ); // file, modifiedExif
        TEntry fileEntry;
        iFs.Entry( iMdeObject->Uri(), fileEntry );

        WRITELOG( "CImageComposerAO::ComposeL() - store Size and LastModifiedDate properties to MDE" );
        CMdEPropertyDef& sizePropDef = iImageObjectDef->GetPropertyDefL( Object::KSizeProperty );
            {
            CMdEProperty* sizeProp = NULL;
            iMdeObject->Property( sizePropDef, sizeProp, 0 );

            if ( sizeProp )
                {
                sizeProp->SetUint32ValueL( fileEntry.iSize );
                }
            else
                {
                iMdeObject->AddUint32PropertyL( sizePropDef, fileEntry.iSize );
                }
            }

        CMdEPropertyDef& lastModDatePropDef = iImageObjectDef->GetPropertyDefL(
        		Object::KLastModifiedDateProperty );
        
        CMdEProperty* lastModDateProp = NULL;
        iMdeObject->Property( lastModDatePropDef, lastModDateProp, 0 );

        if ( lastModDateProp )
            {
            lastModDateProp->SetTimeValueL( fileEntry.iModified );
            }
        else
            {
            iMdeObject->AddTimePropertyL( lastModDatePropDef, fileEntry.iModified );
            }
        iSession->CommitObjectL( *iMdeObject );
        iNextItemsSkip.InsertInOrder( iMdeObject->Id(),
        		TLinearOrder<TItemId>( CImageComposerAO::CompareTItemIds ) );
        }

    CleanupStack::PopAndDestroy( exif );

    WRITELOG( "CImageComposerAO::ComposeL() - Start writing GPS tags" );
    
    WriteGPSTagsL( iMdeObject->Id() );

#ifdef _DEBUG
    WRITELOG1( "CImageComposerAO::ComposeL() - Compose End Object ID: %d", iMdeObject->Id() );
#endif
    }

// ---------------------------------------------------------------------------
// WriteGPSTagsL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::WriteGPSTagsL( TItemId aObjectId )
    {
#ifdef _DEBUG
    _LIT( KPanicCategoryNsd, "NSD=NULL" );
    _LIT( KPanicCategoryOd,  "OD=NULL" );
    _LIT( KPanicCategoryId,  "ID=NULL" );
    _LIT( KPanicCategoryLd,  "LD=NULL" );
    __ASSERT_DEBUG( iDefaultNamespace, User::Panic( KPanicCategoryNsd, KErrBadHandle ) );
    __ASSERT_DEBUG( iObjectDef, User::Panic( KPanicCategoryOd,  KErrBadHandle ) );
    __ASSERT_DEBUG( iImageObjectDef, User::Panic( KPanicCategoryId,  KErrBadHandle ) );
    __ASSERT_DEBUG( iLocationObjectDef, User::Panic( KPanicCategoryLd,  KErrBadHandle ) );
#endif    
    
    delete iRelationQuery;
    iRelationQuery = NULL;
    
    if ( !iSession )
    	{
    	User::Leave( KErrSessionClosed );
    	}
    
    iRelationQuery = iSession->NewRelationQueryL( *iDefaultNamespace, this );
    
    iRelationQuery->SetResultMode( EQueryResultModeItem );
    iRelationQuery->Conditions().SetOperator( ELogicConditionOperatorAnd );
    
    CMdERelationCondition& filterCond = iRelationQuery->Conditions().
    		AddRelationConditionL( ERelationConditionSideRight );
    
    // Left object in relation must have this ID.
    filterCond.LeftL().AddObjectConditionL( aObjectId );
    
    // Right object in relation must be a location object.
    filterCond.RightL().AddObjectConditionL( *iLocationObjectDef );
    
    iRelationQuery->FindL( 1, 1 ); // results to a call to HandleQueryCompleted()
    }
    
// ---------------------------------------------------------------------------
// SetNextRequest
// ---------------------------------------------------------------------------
//
void CImageComposerAO::SetNextRequest( TRequestType aNextRequest )
    {
    iNextRequest = aNextRequest;
    
    if ( !IsActive() )
        {
        iStatus = KRequestPending;
        SetActive();
        TRequestStatus* ptrStatus = &iStatus;
        User::RequestComplete( ptrStatus, KErrNone );
        }
    }
    
// ---------------------------------------------------------------------------
// HandleQueryNewResults
// ---------------------------------------------------------------------------
//
void CImageComposerAO::HandleQueryNewResults( CMdEQuery& /*aQuery*/,
	TInt /*aFirstNewItemIndex*/, TInt /*aNewItemCount*/ )
    {
    }
    
// ---------------------------------------------------------------------------
// HandleQueryNewResults
// ---------------------------------------------------------------------------
//
void CImageComposerAO::HandleQueryNewResults( CMdEQuery& /*aQuery*/,
	TInt /*aNewObjectItemCount*/, TInt /*aNewRelationItemCount*/,
	TInt /*aNewEventItemCount*/ )
    {
    }

// ---------------------------------------------------------------------------
// HandleQueryCompleted
// ---------------------------------------------------------------------------
//
void CImageComposerAO::HandleQueryCompleted( CMdEQuery& aQuery, TInt aError )
    {
    if ( aError != KErrNone )
    	{
    	WRITELOG1( "CImageComposerAO::HandleQueryCompleted() - query error: %d", aError );
    	SetNextRequest( ERequestGetObject );
    	return;
    	}
    if ( aQuery.Count() == 0 )
        {
        WRITELOG( "CImageComposerAO::HandleQueryCompleted() - no gps items found" );
        SetNextRequest( ERequestGetObject );
        return;
        }

#ifdef _DEBUG        
    TRAPD( error, StartWritingGPSTagsL( aQuery ) );
    WRITELOG1( "CImageComposerAO::HandleQueryCompleted() - error code from StartWritingGPSTagsL: %d", error );
#else
    TRAP_IGNORE( StartWritingGPSTagsL( aQuery ) );
#endif
    
    SetNextRequest( ERequestGetObject );
    }

// ---------------------------------------------------------------------------
// StartWritingGPSTagsL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::StartWritingGPSTagsL( CMdEQuery& aQuery )
    {
#ifdef _DEBUG
    _LIT( KPanicCategoryNsd, "NSD=NULL" );
    _LIT( KPanicCategoryOd,  "OD=NULL" );
    _LIT( KPanicCategoryId,  "ID=NULL" );
    _LIT( KPanicCategoryLd,  "LD=NULL" );
    __ASSERT_DEBUG( iDefaultNamespace, User::Panic( KPanicCategoryNsd, KErrBadHandle ) );
    __ASSERT_DEBUG( iObjectDef, User::Panic( KPanicCategoryOd,  KErrBadHandle ) );
    __ASSERT_DEBUG( iImageObjectDef, User::Panic( KPanicCategoryId,  KErrBadHandle ) );
    __ASSERT_DEBUG( iLocationObjectDef, User::Panic( KPanicCategoryLd,  KErrBadHandle ) );
#endif    
    
    if ( !iSession )
    	{
    	WRITELOG( "CImageComposerAO::StartWritingGPSTagsL - iSession is NULL!" );
    	User::Leave( KErrSessionClosed );
    	}
    
    CMdERelation& result = static_cast<CMdERelation&>( aQuery.ResultItem( 0 ) );
    TItemId rightId = result.RightObjectId();
    CMdEObject* location = iSession->GetObjectL( rightId, *iLocationObjectDef );
    CleanupStack::PushL( location );
    
    TItemId leftId = result.LeftObjectId();
    CMdEObject* mdeObject = iSession->GetObjectL( leftId, *iObjectDef );
    CleanupStack::PushL( mdeObject );
    
    DoWriteExifL( mdeObject, location );
    
    CleanupStack::PopAndDestroy( mdeObject );
    CleanupStack::PopAndDestroy( location );
    }


// ---------------------------------------------------------------------------
// DoWriteExifL
// ---------------------------------------------------------------------------
//
void CImageComposerAO::DoWriteExifL( CMdEObject* aMdEObject, CMdEObject* aLocationObject )
    {
#ifdef _DEBUG
    _LIT( KPanicCategoryNsd, "NSD=NULL" );
    _LIT( KPanicCategoryOd,  "OD=NULL" );
    _LIT( KPanicCategoryId,  "ID=NULL" );
    _LIT( KPanicCategoryLd,  "LD=NULL" );
    __ASSERT_DEBUG( iDefaultNamespace, User::Panic( KPanicCategoryNsd, KErrBadHandle ) );
    __ASSERT_DEBUG( iObjectDef, User::Panic( KPanicCategoryOd,  KErrBadHandle ) );
    __ASSERT_DEBUG( iImageObjectDef, User::Panic( KPanicCategoryId,  KErrBadHandle ) );
    __ASSERT_DEBUG( iLocationObjectDef, User::Panic( KPanicCategoryLd,  KErrBadHandle ) );
#endif
    
    WRITELOG( "CImageComposerAO::DoWriteExifL()" );
    if ( !aMdEObject || !aLocationObject )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - null parameter(s)!" );
        User::Leave( KErrArgument );
        }

    CMdEProperty* itemTypeProperty = NULL;
    CMdEProperty* latitudeProperty = NULL;
    CMdEProperty* longitudeProperty = NULL;
    CMdEProperty* altitudeProperty = NULL;
    CMdEProperty* qualityProperty = NULL;

    aMdEObject->Property( iObjectDef->GetPropertyDefL(
    		Object::KItemTypeProperty ), itemTypeProperty, 0 );
    aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
    		Location::KLatitudeProperty ), latitudeProperty, 0 );
    aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
    		Location::KLongitudeProperty ), longitudeProperty, 0 );
    aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
    		Location::KAltitudeProperty ), altitudeProperty, 0 );
    aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
    		Location::KQualityProperty ), qualityProperty, 0 );

    if ( !itemTypeProperty )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - NULL item type property!" );
        User::Leave( KErrBadHandle );
        }
    const TDesC& uri = aMdEObject->Uri();

    const TDesC& mimeType = itemTypeProperty->TextValueL();

    if ( !IsJpeg( const_cast<TDesC&>(mimeType) ) )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - object mimetype is not image/jpeg!" );
        User::Leave( KErrNotSupported );
        }

    // Check whether the file is open
    TBool isOpen( EFalse );
    const TInt openError = iFs.IsFileOpen( uri, isOpen );
    if( openError != KErrNone )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - check for open file failed!" );
        User::Leave( openError );
        }
    else if ( isOpen )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - file handle is open!" );
        User::Leave( KErrInUse );
        }

    TInt64 imageFileSize = 0;
    RFile64 file;
    User::LeaveIfError( file.Open( iFs, uri, EFileRead ) );
    CleanupClosePushL( file );

    User::LeaveIfError( file.Size( imageFileSize ) );
    HBufC8* imageData = HBufC8::NewL( imageFileSize );
    CleanupStack::PushL( imageData );
    TPtr8 myImagePtr = imageData->Des();

    WRITELOG( "CImageComposerAO::DoWriteExifL() - reading IMAGE file" );
    const TInt readError = file.Read( myImagePtr ) ;
    if ( readError != KErrNone )
        {
        WRITELOG( "CImageComposerAO::DoWriteExifL() - error while reading image file!" );
        User::Leave( KErrGeneral );
        }

    WRITELOG( "CImageComposerAO::DoWriteExifL() - reading IMAGE file - DONE! - closing file" );
    CleanupStack::Pop( imageData );
    CleanupStack::PopAndDestroy( &file );
    CleanupStack::PushL( imageData );

    HBufC8* modifiedExif = NULL;
    iExifUtil->ComposeLocationL( aLocationObject, myImagePtr, modifiedExif );

    // write the EXIF data to the image

    if ( modifiedExif )
        {
        CleanupStack::PushL( modifiedExif );

        CMdEObject* mdeObject = iSession->OpenObjectL( aMdEObject->Id(), 
        		*iImageObjectDef );
        if ( !mdeObject )
            {
            User::Leave( KErrAccessDenied );
            }
        CleanupStack::PushL( mdeObject );

        User::LeaveIfError( file.Open( iFs, mdeObject->Uri(), EFileWrite ) );
        CleanupClosePushL( file );

        // set position to begin of file
        TInt64 pos = 0;
        User::LeaveIfError( file.Seek( ESeekStart, pos ) );

        User::LeaveIfError( file.Write( modifiedExif->Des(), modifiedExif->Des().Length() ) );

        CleanupStack::PopAndDestroy( &file );
        TEntry fileEntry;
        iFs.Entry( mdeObject->Uri(), fileEntry );

        CMdEPropertyDef& sizePropDef = iImageObjectDef->GetPropertyDefL( Object::KSizeProperty );
        CMdEProperty* sizeProp = NULL;
        mdeObject->Property( sizePropDef, sizeProp, 0 );

        if ( sizeProp )
            {
            sizeProp->SetUint32ValueL( fileEntry.iSize );
            }
        else
            {
            mdeObject->AddUint32PropertyL( sizePropDef, fileEntry.iSize );
            }

        CMdEPropertyDef& lastModDatePropDef = iImageObjectDef->GetPropertyDefL(
        		Object::KLastModifiedDateProperty );
        CMdEProperty* lastModDateProp = NULL;
        mdeObject->Property( lastModDatePropDef, lastModDateProp, 0 );

        if ( lastModDateProp )
            {
            lastModDateProp->SetTimeValueL( fileEntry.iModified );
            }
        else
            {
            mdeObject->AddTimePropertyL( lastModDatePropDef, fileEntry.iModified );
            }

        iSession->CommitObjectL( *mdeObject );
        iNextItemsSkip.InsertInOrder( mdeObject->Id(),
        		TLinearOrder<TItemId>( CImageComposerAO::CompareTItemIds ) );
        CleanupStack::PopAndDestroy( mdeObject );
        CleanupStack::PopAndDestroy( modifiedExif );
        }

    // remove empty (=unneeded) location objects
    if ( !latitudeProperty && !longitudeProperty && !altitudeProperty ) // && !satellitesProperty ) // check these first...
        {
        // get the rest of the properties
        CMdEProperty* cellIdProperty = NULL;
        CMdEProperty* countryCodeProperty = NULL;
        CMdEProperty* networkCodeProperty = NULL;
        CMdEProperty* locationAreaCodeProperty = NULL;
        CMdEProperty* speedProperty = NULL;
        CMdEProperty* directionProperty = NULL;
        CMdEProperty* qualityProperty = NULL;

        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KCellIdProperty ), cellIdProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KCountryCodeProperty ), countryCodeProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KNetworkCodeProperty ), networkCodeProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KLocationAreaCodeProperty ), locationAreaCodeProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KSpeedProperty ), speedProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KDirectionProperty ), directionProperty, 0 );
        aLocationObject->Property( iLocationObjectDef->GetPropertyDefL(
        		Location::KQualityProperty ), qualityProperty, 0 );

        // if object doesn't contain any properties, remove it
        if ( !cellIdProperty && !countryCodeProperty && !networkCodeProperty
            && !locationAreaCodeProperty && !speedProperty && !directionProperty && !qualityProperty )
            {
            // Ignore return value - if operation does not succeed, there is no much that can be done here
            iSession->RemoveObjectL( aLocationObject->Id(), iDefaultNamespace );
            }
        }
    
    CleanupStack::PopAndDestroy( imageData );

    }

// ---------------------------------------------------------------------------
// IsJpeg
// ---------------------------------------------------------------------------
//
TBool CImageComposerAO::IsJpeg( const TDesC& aMimeType )
    {
    WRITELOG( "CImageComposerAO::IsJpeg()" );

    if ( MdsUtils::Compare( KJpegMimeType, aMimeType ) == 0 )
        {
        WRITELOG( "CImageComposerAO::IsJpeg() - image is Jpeg" );
        return ETrue;        
        }

    return EFalse;
    }