harvester/composerplugins/imagecomposer/src/imagecomposerao.cpp
changeset 0 c53acadfccc6
child 1 acef663c1218
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/harvester/composerplugins/imagecomposer/src/imagecomposerao.cpp	Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,903 @@
+/*
+* 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;
+        }
+    if ( iExifUtil )
+    	{
+    	delete iExifUtil;
+    	}
+
+    delete iRelationQuery;
+    iFs.Close();
+    
+    delete iMdEHarvesterSession;
+    }
+
+// ---------------------------------------------------------------------------
+// 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();
+    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 )
+        {
+        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 )
+            	{
+            	SetNextRequest( ERequestReady );
+            	}
+            else
+            	{
+            	TItemId mdeObjectId = KNoId;
+	            TRAPD( err, GetObjectFromMdeL( mdeObjectId ) );
+	            
+	            if ( err == KErrNone )
+	                {    
+	                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:
+            {
+            }
+            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 );
+    	}
+    else
+    	{
+    	iItemQueue.Compress();
+    	}
+    
+    // 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() )
+            {
+            // we have get version
+            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 );
+    iFs.IsFileOpen( uri, isOpen );
+    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 )
+            {
+            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;
+    }
+
+