mmfenh/progressivedownload/ProgressiveDownloadSource/src/ProgressiveDownloadSource.cpp
changeset 0 71ca22bcf22a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmfenh/progressivedownload/ProgressiveDownloadSource/src/ProgressiveDownloadSource.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,1810 @@
+/*
+* Copyright (c) 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:  Progressive Download Utility
+*
+*/
+
+
+#include <f32file.h>
+#include <e32std.h>
+#include <mmfdatabuffer.h>
+#include <mmfutilities.h>
+#include <mmf/common/mmfcontroller.h>
+#include <mmfpaniccodes.h>
+//#include "mmffile.h"
+
+#include "MmffilePriv.h"
+#include "FileAccess.h"
+
+
+#include "ProgressiveDownloadSource.h"
+#include <implementationproxy.h>
+
+const TUid KUidProgressiveDlSource	= {KProgressiveDownloadSourceUid};
+
+
+void Panic(TMMFFilePanicCode aPanicCode)
+	{
+ 	_LIT(KMMFFilePanicCategory, "CProgressiveDownloadSource");
+	User::Panic(KMMFFilePanicCategory, aPanicCode);
+	}
+
+
+/**
+ * Constructs a CTransferBufferCopy
+ *
+ * @return CTransferBufferCopy*
+ */
+CTransferBufferCopy* CTransferBufferCopy::NewL(TInt aMaxLength)
+	{
+	CTransferBufferCopy* self = new (ELeave) CTransferBufferCopy(aMaxLength);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/**
+ * Second phase constructor for CTransferBufferCopy
+ *
+ * @return void
+ */
+void CTransferBufferCopy::ConstructL()
+	{
+	iBuffer = static_cast<TUint8*>(User::AllocL(iMaxLength));
+	iBufferDes.Set(iBuffer,0,iMaxLength);
+	}
+
+/**
+Destructor.
+*/
+CProgressiveDownloadSource::~CProgressiveDownloadSource()
+	{
+	delete iFile;
+
+	iHandle.Close();
+	iFsSession.Close();
+	delete iFileName;
+	delete iFileExt;
+	delete iFilePath;
+	delete iFileDrive;
+	delete iMmfFileEventHandler;
+	delete iUniqueId;
+
+	// Get rid of everything in RArray's & close them.
+	iRequests.ResetAndDestroy();
+	iTransferBufferCopies.ResetAndDestroy();
+	}
+
+/**
+Protected constructor.
+
+The default implementation is empty.
+*/
+CProgressiveDownloadSource::CProgressiveDownloadSource() : CMMFClip(KUidProgressiveDlSource/*KUidMmfFileSource*/, KUidMmfFileSink ), iFileSize(-1)
+	{
+	iSinkNotStopped = EFalse;
+	}
+
+/**
+Constructs an CProgressiveDownloadSource MDataSource.
+
+@return A pointer to the new CProgressiveDownloadSource data source.
+*/
+MDataSource* CProgressiveDownloadSource::NewSourceL()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::NewSourceL"));
+    #endif
+	CProgressiveDownloadSource* self = new (ELeave) CProgressiveDownloadSource ;
+	return STATIC_CAST( MDataSource*, self ) ;
+	}
+
+/**
+Constructs a CProgressiveDownloadSource MDataSink
+
+@return A pointer to the new CProgressiveDownloadSource data sink.
+*/
+MDataSink* CProgressiveDownloadSource::NewSinkL()
+	{
+	CProgressiveDownloadSource* self = new (ELeave) CProgressiveDownloadSource ;
+	return STATIC_CAST( MDataSink*, self ) ;
+	}
+
+/**
+Perform source construction dependant on the source construction
+initialisation data aInitData.
+
+@param  aInitData
+        The TPckg<TMMFFileParams> descriptor package containing the file name and full path.
+*/
+void CProgressiveDownloadSource::ConstructSourceL(const TDesC8& aInitData )
+	{
+	ConstructL(aInitData, ESourceMode);
+	}
+
+/**
+Performs sink construction dependant on the sink construction
+initialisation data aInitData.
+
+@param  aInitData
+        The TPckg<TMMFFileParams> descriptor package containing the file name and full path.
+*/
+void CProgressiveDownloadSource::ConstructSinkL(const TDesC8& aInitData)
+	{
+	ConstructL(aInitData, ESinkMode);
+	}
+
+/**
+Protected constructor.
+
+Extracts the initialisation data provided by the calling functions: ConstructSourceL() and
+ConstructSourceL(). Creates a file server session and sets up file name. If there is a file name and
+it cannot be found this function leaves. If there is no file name the function leaves. Does not
+attempt to open the file or check whether the file exists.
+
+@param  aInitData
+        Initialisation data packaged in a TMMFFileParams.
+*/
+void CProgressiveDownloadSource::ConstructL(const TDesC8& aInitData,TMMFileMode aFileMode)
+	{
+	User::LeaveIfError(iFsSession.Connect());
+#ifdef __IPC_V2_PRESENT__
+	// on IPCv2 we auto attach
+	User::LeaveIfError(iFsSession.ShareAuto());
+#else
+	// on IPCv1
+	we use explicit - more efficient
+	User::LeaveIfError(iFsSession.Share(RSessionBase::EExplicitAttach));
+#endif
+
+
+	TBool fileInit = EFalse;
+	HBufC* filename = NULL;
+	TBool filenamePushed = EFalse;
+
+
+	TBool drmContent = EFalse;
+	RDesReadStream stream(aInitData);
+	CleanupClosePushL(stream);
+
+	TUid initUid;
+
+	initUid = TUid::Uid(stream.ReadInt32L());
+
+	if (initUid == KMMFileHandleSourceUid)
+		{
+		TPckgBuf<RFile*> fileptr;
+		stream.ReadL(fileptr);
+
+		iHandle.Duplicate(*fileptr());
+
+		TInt length;
+		length = stream.ReadInt32L();
+		if (length>0)
+			{
+			iUniqueId = HBufC::NewL(length);
+			TPtr16 ptr = iUniqueId->Des();
+			stream.ReadL(ptr, length);
+			}
+		iFileHandle = ETrue;
+		filename = HBufC::NewMaxL(KMaxFileName);
+		TPtr ptr = filename->Des();
+		iHandle.Name(ptr);
+		fileInit = ETrue;
+		drmContent = ETrue;
+		}
+
+	else if (initUid == KMMFileSourceUid)
+		{
+		TInt length;
+		length = stream.ReadInt32L();
+		filename = HBufC::NewMaxLC(length);
+		TPtr ptr = filename->Des();
+		stream.ReadL(ptr, length);
+
+		length = stream.ReadInt32L();
+		if (length>0)
+			{
+			iUniqueId = HBufC::NewMaxL(length);
+			ptr.Set(iUniqueId->Des());
+			stream.ReadL(ptr, length);
+			}
+		CleanupStack::Pop(filename);
+
+		fileInit = ETrue;
+		drmContent = ETrue;
+		}
+	else
+		{
+//		TODO If the UID is unknown we should reject, but  currently
+//		code also used for older calls that just supply filename.
+//		User::Leave(KErrNotSupported);
+		}
+
+	CleanupStack::PopAndDestroy(&stream);
+
+	if (!fileInit && aInitData.Length() == sizeof(TMMFFileHandleParams))
+		{
+		TMMFFileHandleParams params;
+		TPckgC<TMMFFileHandleParams> config(params);
+		config.Set(aInitData);
+		params = config();
+
+
+		if (params.iUid == KFileHandleUid)
+			{
+			fileInit = ETrue;
+			User::LeaveIfError(iHandle.Duplicate(*params.iFile));
+			TInt pos = 0;
+			// make sure the duplicate handle is at the start of the file - the usage of the file handle really requires this
+			User::LeaveIfError(iHandle.Seek(ESeekStart, pos));
+			iFileHandle = ETrue;
+			filename = HBufC::NewMaxLC(KMaxFileName);
+			filenamePushed = ETrue;
+			TPtr ptr = filename->Des();
+			User::LeaveIfError(iHandle.Name(ptr));
+			}
+		}
+
+
+	if (!fileInit) // do old case as last resort
+		{
+		TMMFFileParams params;
+		TPckgC<TMMFFileParams> config(params);
+		config.Set(aInitData);
+		params = config();
+
+		filename = params.iPath.AllocL();
+		fileInit = ETrue;
+		}
+
+	if (!filenamePushed)
+		{
+		// from now on it is assumed pushed.
+		CleanupStack::PushL(filename);
+		}
+
+	TParse parser ;
+	User::LeaveIfError(parser.Set(*filename, NULL, NULL));
+	CleanupStack::PopAndDestroy(filename);
+	if ( !( parser.NamePresent() ) && !( parser.ExtPresent() ) )
+		User::Leave( KErrBadName ) ;
+
+	iFullFileName.Copy( parser.FullName() ) ;
+	iFileName = parser.Name().AllocL() ;
+	iFileExt = parser.Ext().AllocL() ;
+	iFilePath = parser.Path().AllocL() ;
+	iFileDrive = parser.Drive().AllocL() ;
+
+
+	// in order to simulate old behaviour we are not passing error out
+	// but will try to create Content again during PrimeL()
+	if (fileInit && drmContent && aFileMode==ESourceMode)
+		{
+		TInt contentError;
+		if (iFileHandle)
+			{
+			TRAP(contentError,
+				iFile = CContentFile::NewL(iHandle, UniqueId());
+				);
+			}
+		else
+			{
+			// Open for read-only access
+			//rj progressive download needs shared access
+			TRAP(contentError,
+				iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareAny);
+			);
+			}
+		iFileOpen = (contentError==KErrNone);
+		}
+
+	(void)(aFileMode=ESourceMode); // prevent from compiler warning
+
+	}
+
+
+/**
+@deprecated
+
+Returns an RFile handle to the current file.
+
+If there is no current file, one is created. If the file exists then it is opened with read access
+if it is read only, write access otherwise. If the file does not exist then it is opened with
+write access.
+
+@leave KErrNotReady
+       The file is not open.
+
+@return A handle to the current file.
+*/
+RFile& CProgressiveDownloadSource::FileL()
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::FileL"));
+    #endif
+	if (!iFile)
+		User::Leave(KErrNotReady);
+	if (iFileHandle)
+		return iHandle;
+	else
+		return iFile->FileL();
+
+	}
+
+/**
+Returns the file name of the current file.
+
+Note: This will give the wrong answer if the file is renamed!
+
+@return The FileName (without extension).
+*/
+const TDesC& CProgressiveDownloadSource::FileName() const
+	{
+	return *iFileName ;
+	}
+
+/**
+Returns the extension of the current file.
+
+Note: This will give the wrong answer if the file is renamed!
+
+@return The File Extension.
+*/
+const TDesC& CProgressiveDownloadSource::Extension() const
+	{
+	return *iFileExt ;
+	}
+
+/**
+Returns the path of the current file.
+
+Note: This will give the wrong answer if the file is renamed!
+
+@return The FilePath (without filename and extension)
+*/
+const TDesC& CProgressiveDownloadSource::FilePath() const
+	{
+	return *iFilePath ;
+	}
+
+/**
+Returns the drive on which the current file is located.
+
+Note: This will give the wrong answer if the file is renamed!
+
+@return The FileDrive (drive letter only, without path, filename and extension).
+*/
+const TDesC& CProgressiveDownloadSource::FileDrive() const
+	{
+	return *iFileDrive ;
+	}
+
+/**
+Returns the full name of the current file.
+
+Note: This will give the wrong answer if the file is renamed!
+
+@return The file name (full filename including drive letter, without path, filename and extension).
+*/
+const TFileName CProgressiveDownloadSource::FullName() const
+	{
+	return iFullFileName;
+	}
+
+
+/**
+Returns the uniqueID associated with this content. If no uniqueID has been provided, a null
+descriptor will be provided
+
+@return The UniqueID
+*/
+const TDesC& CProgressiveDownloadSource::UniqueId() const
+	{
+	if (iUniqueId)
+		return *iUniqueId;
+	else
+		return KNullDesC;
+	}
+
+
+
+/**
+Deletes the file.
+
+Closes the currently open file, then deletes it. If the file source is accessing a file handle,
+the file is truncated to 0 bytes instead.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::Delete()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::Delete"));
+    #endif
+	if (!iFileHandle)
+		{
+		delete iFile;
+		iFile = NULL;
+		iFileSize=-1;
+		iPosition=0;
+
+		return iFsSession.Delete(iFullFileName);
+		}
+	else
+		{
+		iFileSize=-1;
+		iPosition=0;
+
+		return iFile->SetSize(0);
+		}
+
+	}
+
+/**
+Sets the file size.
+
+@param  aSize
+        The size of the file.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::SetSize(TInt aSize)
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("[%x]CProgressiveDownloadSource::SetSize to %d"),this,aSize);
+    #endif
+
+    iFix = aSize;
+
+	if ( !iFile )
+		return KErrNotReady;
+
+	TInt err =  iFile->SetSize(aSize);
+	if(err == KErrNone)
+		iFileSize = aSize;
+	else
+		iFileSize = -1;
+
+	return err;
+	}
+
+/**
+Obtains a CTransferBufferCopy from iTransferBufferCopies that is
+at least as big as that required.
+
+There is no need to put the pointer returned by this method onto the CleanupStack
+as it will have already been placed into iTransferBufferCopies.
+
+@param  aMaxLength
+        The size required.
+
+@return A pointer to a valid CTransferBufferCopy.
+*/
+CTransferBufferCopy* CProgressiveDownloadSource::ObtainCopyOfTransferBufferL(TInt aMaxLength)
+	{
+	//find a free transfer buffer copy of the right size
+	TInt firstFree = -1;
+	CTransferBufferCopy* transBufCopyToUse = NULL;
+
+	for(TInt cnt=0; cnt < iTransferBufferCopies.Count(); cnt++)
+		{
+		if(!iTransferBufferCopies[cnt]->InUse())
+			{
+			//record the first free entry, we may remove this
+			//if entries in iTransferBufferCopies > KAcceptableTransferBufferCopiesSize
+			if(firstFree == -1)
+				firstFree = cnt;
+
+			if(iTransferBufferCopies[cnt]->MaxLength() >= aMaxLength)
+				{
+				transBufCopyToUse = iTransferBufferCopies[cnt];
+
+				//Set the MaxLength. This will ensure that the copy acts the same as
+				//the original Transfer buffer, eg. file server will throw KErrOverflow
+				transBufCopyToUse->ReUse(aMaxLength);
+				break;
+				}
+			}
+		}
+
+	//If we failed to find a suitable entry, we need to create a new one
+	if(!transBufCopyToUse)
+		{
+		//Firstly, should we re-cycle an existing entry?
+		//There must be entries in the array, a free entry must have been found,
+		//the size of the array must be beyond the water mark where we want to start
+		//cycling free entries.
+		if((iTransferBufferCopies.Count() > 0) &&
+			(firstFree != -1) &&
+			(iTransferBufferCopies.Count() > KAcceptableTransferBufferCopiesSize))
+			{
+			delete iTransferBufferCopies[firstFree];
+			iTransferBufferCopies.Remove(firstFree);
+
+			transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength);
+			CleanupStack::PushL(transBufCopyToUse);
+			User::LeaveIfError(iTransferBufferCopies.Insert(transBufCopyToUse,firstFree));
+
+			CleanupStack::Pop();
+			}
+		else
+			{
+#ifdef _DEBUG
+			if(iTransferBufferCopies.Count() > KMaximumTransferBufferCopiesSize)
+				{
+				User::Panic(_L("iTransferBufferCopies grew too large in CProgressiveDownloadSource"),KErrTooBig);
+				}
+#endif
+
+			transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength);
+			CleanupStack::PushL(transBufCopyToUse);
+			User::LeaveIfError(iTransferBufferCopies.Append(transBufCopyToUse));
+
+			CleanupStack::Pop();
+			}
+		}
+
+	return transBufCopyToUse;
+	}
+
+
+
+/**
+Loads aBuffer from iFile.
+
+The file must already be open for reading. File read is asynchronous. CReadRequest is created to
+respond to completion.
+
+@param  aBuffer
+        The buffer to be filled from the file.
+@param  aConsumer
+        The data sink consumer of the buffer.
+*/
+void CProgressiveDownloadSource::FillBufferL( CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId /*aMediaId*/ )
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::FillBufferL"));
+    #endif
+	// Requires that iFile is open for read.
+	// Reads data from iFile into aBuffer
+	if ((aConsumer == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile || (iMmfFileEventHandler == NULL))
+		User::Leave(KErrNotReady);
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		CTransferBufferCopy* transBufCopy = NULL;
+		CReadRequest* request = NULL;
+
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		TInt requestSize;
+		if(aBuffer->RequestSize())
+			requestSize = aBuffer->RequestSize();
+		else
+			requestSize = aBufferDes.MaxLength();
+
+		//check whether buffer is safe to send to file server
+		//if not, eg for a transfer buffer, then it needs to be copied
+		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+			{
+			//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, iPosition, Size(),iBytesDownloaded, iMmfFileEventHandler);
+			}
+		else
+			{
+			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, iPosition, Size(),iBytesDownloaded, iMmfFileEventHandler);
+			}
+
+		CleanupStack::PushL( request );
+
+		StoreRequestL(request); // transfers ownership
+		CleanupStack::Pop() ; // request
+
+		iFile->Read(request->BufferDes(), requestSize, request->iStatus);
+		iPosition += requestSize;
+
+		if (iPosition >= iFileSize)
+			{
+			aBuffer->SetLastBuffer(ETrue);
+			}
+
+		request->SetActive();
+		}
+	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		User::Leave( KErrNotSupported ) ;
+	}
+
+/**
+Empties aBuffer into iFile. The file must be already open for writing.
+
+@param  aBuffer
+        The buffer to be written to the file.
+@param  aSupplier
+        The data source supplier of the buffer.
+*/
+void CProgressiveDownloadSource::EmptyBufferL( CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/ )
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::EmptyBufferL"));
+    #endif
+	// Requires that iFile is open for write.
+	// Writes data from iFile into aBuffer
+	if ((aSupplier == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile || (iMmfFileEventHandler == NULL))
+		User::Leave(KErrNotReady);
+
+	CTransferBufferCopy* transBufCopy = NULL;
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		CWriteRequest* request = NULL;
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		//check whether buffer is safe to send to file server
+		//if not, eg for a transfer buffer, then it needs to be copied
+		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+			{
+			//Obtain a normal buffer to send to the file server
+			//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+
+			//Copy the data into the buffer we will send to the file server
+			transBufCopy->Des().Copy(aBufferDes);
+
+			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler);
+			}
+		else
+			{
+			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler);
+			}
+
+		CleanupStack::PushL( request );
+
+		StoreRequestL(request);  // transfers ownership
+		CleanupStack::Pop(); // request
+
+		iFile->Write(request->BufferDes(), request->BufferDes().Length(), request->iStatus);
+		request->SetActive();
+		}
+	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		User::Leave( KErrNotSupported ) ;
+		}
+	}
+
+/**
+Loads aLength number of bytes into aBuffer from specified point in iFile.
+
+@param  aLength
+        The number of bytes to be read into buffer.
+@param  aBuffer
+        The buffer to be filled from the file.
+@param  aPosition
+        The offset into the file at which to start reading.
+@param  aConsumer
+        The data sink consumer of the buffer.
+*/
+void CProgressiveDownloadSource::ReadBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::ReadBufferL Async"));
+    #endif
+	// Requires that iFile is open for read.
+	// Reads data from iFile into aBuffer
+	if ((aLength < 0) || (aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile || (iMmfFileEventHandler == NULL))
+		User::Leave(KErrNotReady);
+
+	CTransferBufferCopy* transBufCopy = NULL;
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		CReadRequest* request = NULL;
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		//check whether buffer is safe to send to file server
+		//if not, eg for a transfer buffer, then it needs to be copied
+		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+			{
+			//Obtain a normal buffer to send to the file server
+			//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+
+			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, aPosition, Size(), iBytesDownloaded,iMmfFileEventHandler);
+			}
+		else
+			{
+			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, aPosition, Size(), iBytesDownloaded,iMmfFileEventHandler);
+			}
+
+		CleanupStack::PushL( request );
+
+		StoreRequestL(request) ;  //transfers ownership
+		CleanupStack::Pop() ; //request
+
+
+
+		TInt err = iFile->Seek(ESeekStart, aPosition);
+		if (err==KErrNone)
+			iFile->Read(request->BufferDes(), aLength, request->iStatus);
+		else
+			{
+			TRequestStatus* status = &request->iStatus;
+			User::RequestComplete(status, err);
+			}
+
+		//rj wait until runl is completed
+	//	iPosition = aPosition + aLength;
+       iPosition = aPosition;
+
+	// rj 	if (iPosition >= iFileSize)
+	//		{
+	//		aBuffer->SetLastBuffer(ETrue);
+	//		}
+
+		request->SetActive();
+		}
+	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		User::Leave( KErrNotSupported ) ;
+	}
+
+
+/**
+Loads aBuffer from specified point in iFile.
+
+The file must already be open for reading.
+
+@param  aBuffer
+        The buffer to be filled from the file.
+@param  aPosition
+        The offset into file at which to start reading.
+@param  aConsumer
+        The data sink consumer of the buffer.
+*/
+void CProgressiveDownloadSource::ReadBufferL(CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
+	{
+    #if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::ReadBufferL Async"));
+    #endif
+
+	// Requires that iFile is open for read.
+	// Reads data from iFile into aBuffer
+	if ((aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		TInt requestSize;
+		if(aBuffer->RequestSize())
+			requestSize = aBuffer->RequestSize();
+		else
+			requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().MaxLength();
+
+		ReadBufferL(requestSize, aBuffer, aPosition, aConsumer);
+		}
+	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		User::Leave(KErrNotSupported);
+	}
+
+
+/**
+Loads aBuffer from specified point in iFile.  Note that this is a synchronous read.
+
+@param  aBuffer
+        The buffer to be filled from the file.
+@param  aPosition
+        The offset into file at which to start reading.
+*/
+void CProgressiveDownloadSource::ReadBufferL( CMMFBuffer* aBuffer, TInt aPosition)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::ReadBufferL Sync"));
+    #endif
+	// Requires that iFile is open for read.
+	// Reads data from iFile into aBuffer
+	if ((aPosition<0) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile)
+		User::Leave(KErrNotReady);
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		TInt requestSize;
+		if(aBuffer->RequestSize())
+			requestSize = aBuffer->RequestSize();
+		else
+			requestSize = aBufferDes.MaxLength();
+
+		//check whether buffer is safe to send to file server
+		//if not, eg for a transfer buffer, then it needs to be copied
+		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+			{
+			//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+			CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+
+			User::LeaveIfError(iFile->Seek(ESeekStart, aPosition));
+			User::LeaveIfError(iFile->Read(transBufCopy->Des(), requestSize));
+			aBufferDes.Copy(transBufCopy->Des().Left(aBufferDes.MaxLength()));
+			}
+		else
+			{
+			User::LeaveIfError(iFile->Seek(ESeekStart, aPosition));
+			User::LeaveIfError(iFile->Read(aBufferDes, requestSize));
+			}
+
+		iPosition = aPosition + aBufferDes.Length();
+
+		//check if the buffer is the last buffer and if so set the last buffer flag on the CMMFDataBuffer
+		//NB: setting last buffer is the done by the formatter, but this is a hang over to account for
+		//existing formatters that may fail if this is removed.
+		if (aBufferDes.Length() < requestSize)
+			aBuffer->SetLastBuffer(ETrue);
+		}
+	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		User::Leave(KErrNotSupported);
+	}
+
+/**
+Empties aLength bytes from aBuffer into iFile at specified location.
+
+@param  aLength
+        The number of bytes to be emptied from buffer.
+@param  aBuffer
+        The data buffer containing bytes to be written.
+@param  aPosition
+        The offset into file at which to start writing.
+@param  aSupplier
+        The data source to be notified when the write has been completed.
+
+@leave  KErrNotReady
+        SinkPrimeL() and SinkThreadLogon() have not been called.
+@leave  KErrArgument
+        aLength<0 or aPosition<0 or aSupplier is NULL.
+@leave  KErrNotSupported
+        aBuffer is not a supported CMMFDataBuffer
+*/
+void CProgressiveDownloadSource::WriteBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::WriteBufferL Async"));
+    #endif
+
+	if ((aLength<0) || (aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile || (iMmfFileEventHandler == NULL))
+		User::Leave(KErrNotReady);
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		CWriteRequest* request = NULL;
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		//check whether buffer is safe to send to file server
+		//if not, eg for a transfer buffer, then it needs to be copied
+		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+			{
+			//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+			CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+
+			transBufCopy->Des().Copy(aBufferDes);
+
+			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler);
+			}
+		else
+			{
+			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler);
+			}
+
+		CleanupStack::PushL( request );
+
+		StoreRequestL(request);  // transfers ownership
+		CleanupStack::Pop(); // request
+
+		iFile->Seek(ESeekStart, aPosition);
+		iFile->Write(request->BufferDes(), aLength, request->iStatus);
+		//iFileSize = -1; //reset cached size
+
+		request->SetActive();
+		}
+	else // if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+		{
+		//write bitmap to file
+		User::Leave(KErrNotSupported);
+		}
+	}
+
+/**
+Empties aBuffer into iFile at the specified location.
+
+@param  aBuffer
+        The data buffer containing bytes to be written.
+@param  aPosition
+        The offset into file at which to start writing.
+@param  aSupplier
+        The data source to be notified when the write has been completed.
+
+@leave  KErrNotReady
+        SinkPrimeL() and SinkThreadLogon() have not been called.
+@leave  KErrArgument
+        aSupplier is NULL.
+@leave  KErrNotSupported
+        The aBuffer is not of type KMMFDataBuffer.
+*/
+void CProgressiveDownloadSource::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::WriteBufferL Async"));
+    #endif
+	// Requires that iFile is open for write.
+	// Writes data from iFile into aBuffer
+	if ((aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		TUint requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().Length();
+
+		WriteBufferL(requestSize, aBuffer, aPosition, aSupplier);
+		}
+	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		//write bitmap to file
+		User::Leave( KErrNotSupported ) ;
+		}
+	}
+
+/**
+Empties aBuffer into iFile at specified location.  Note that this is a synchronous write.
+
+@param  aBuffer
+        The data buffer containing bytes to be written.
+@param  aPosition
+        The offset into file at which to start writing.
+
+@return The error code from RFile.
+*/
+void CProgressiveDownloadSource::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition )
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::WriteBufferL Sync"));
+    #endif
+	if ((aPosition<0) || (aBuffer == NULL))
+		User::Leave(KErrArgument);
+
+	if (!iFile)
+		User::Leave(KErrNotReady);
+
+	TInt err(KErrNone) ;
+
+	//check whether buffer is safe to send to file server
+	//if not, eg for a transfer buffer, then it needs to be copied
+	if ((!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
+		&& (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())))
+		{
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		//NB: failure in this method will NOT cause transBufCopy to leak as it will be
+		//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
+		CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
+
+		transBufCopy->Des().Copy(aBufferDes);
+		err = iFile->Seek(ESeekStart, aPosition);
+		if (err==KErrNone)
+			err = iFile->Write(transBufCopy->Des(),transBufCopy->Des().Length());
+		//iFileSize = -1; //reset cached size
+		}
+	else if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
+
+		err = iFile->Seek(ESeekStart, aPosition);
+		if (err==KErrNone)
+			err = iFile->Write(aBufferDes, aBufferDes.Length());
+		//iFileSize = -1; //reset cached size
+		}
+	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
+		{
+		User::Leave(KErrNotSupported);
+		}
+
+	User::LeaveIfError(err);
+	}
+
+/**
+Gets the number of free bytes in the device's file system.
+
+@return The number of free bytes.
+*/
+TInt64 CProgressiveDownloadSource::BytesFree()
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::BytesFree"));
+    #endif
+
+	TVolumeInfo volInfo;
+	if (iFsSession.Volume(volInfo) == KErrNone)
+		return volInfo.iFree;
+	return TInt64(0);
+	}
+
+/**
+Returns the size of the file in bytes.
+
+Note: This is not the maximum length.
+
+@return The size of the file in bytes.
+*/
+TInt CProgressiveDownloadSource::Size()
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::size iFileSize %d"),iFileSize);
+	  RDebug::Print(_L("CProgressiveDownloadSource::size iFixSize %d"),iFix);
+    #endif
+
+  	TInt size = 0;
+	TInt err = KErrNone;
+	TBool fileOpened = EFalse;
+
+
+	 if(iFix != 0)   //rj
+	 	{
+	 	iFileSize = iFix;
+	 	return iFix;
+	 	}
+
+
+	if(iFileSize != -1)
+		return iFileSize;
+
+	if (!iFile)
+		{
+		// Open the file.
+		TRAP(err, SourcePrimeL());
+		if (iFile)
+			fileOpened = ETrue;
+		}
+	if (err == KErrNone && iFile)
+		err = iFile->Size(size);
+	if (err)
+		{
+		size = 0;
+	//	iFileSize = -1; //reset cached size
+		}
+	else
+		iFileSize = size; //cache the filesize
+
+	if (fileOpened)
+		TRAP_IGNORE(SourceStopL());	// Close the file
+
+	return size;
+
+	}
+
+/**
+Source thread logon.
+
+Shares fsSession between threads
+
+@param  aEventHandler
+        This is an MAsyncEventHandler to handle asynchronous events that occur during the
+        transfer of multimedia data.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::SourceThreadLogon(MAsyncEventHandler& aEventHandler)
+	{
+	iEventHandler = &aEventHandler;
+	if(!iMmfFileEventHandler)
+		{
+		iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this);
+		if(!iMmfFileEventHandler)
+			return KErrNoMemory;
+		}
+#ifdef __IPC_V2_PRESENT__
+	return KErrNone; // nothing to do
+#else
+	return iFsSession.Attach();
+#endif // __HIDE_IPC_V1__
+	}
+
+/**
+Logs off source thread.
+*/
+void CProgressiveDownloadSource::SourceThreadLogoff()
+	{
+	delete iMmfFileEventHandler;
+	iMmfFileEventHandler = NULL;
+	iEventHandler = NULL;
+	}
+
+
+/**
+Sink thread logon.
+
+Shares fsSession between threads.
+
+@param  aEventHandler
+        This is an MAsyncEventHandler to handle asynchronous events that occur during the
+        transfer of multimedia data.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::SinkThreadLogon(MAsyncEventHandler& aEventHandler)
+	{
+	iEventHandler = &aEventHandler;
+	if(!iMmfFileEventHandler)
+		{
+		iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this);
+		if(!iMmfFileEventHandler)
+			return KErrNoMemory;
+		}
+#ifdef __IPC_V2_PRESENT__
+	return KErrNone;
+#else
+	return iFsSession.Attach();
+#endif // __HIDE_IPC_V1__
+	}
+
+/**
+Sink thread log off.
+*/
+void CProgressiveDownloadSource::SinkThreadLogoff()
+	{
+	delete iMmfFileEventHandler;
+	iMmfFileEventHandler = NULL;
+	iEventHandler = NULL;
+	}
+
+/**
+Stores a request in an array.
+
+CReadWriteRequests are stored in the array iRequests.
+This function takes ownership and places the request in the array.
+It also checks the array for completed requests and removes them.
+
+@param  aRequest
+        The request to store.
+*/
+void CProgressiveDownloadSource::StoreRequestL( CReadWriteRequest* aRequest )
+	{
+	// add aRequest to iRequests
+	User::LeaveIfError( iRequests.Append( aRequest ) ) ;
+
+	// Clear out any completed requests
+	for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ )
+		{
+		if (iRequests[ii]->Completed())
+			{
+			CReadWriteRequest* request = iRequests[ii];
+			delete request;
+
+			iRequests.Remove(ii);
+			ii--;
+			}
+		}
+	}
+
+
+/**
+Cancels outstanding requests.
+
+CReadWriteRequests are stored in the array iRequests.
+This function cancels any outstanding requests and removes them
+from iRequests.
+*/
+void CProgressiveDownloadSource::CancelRequests()
+	{
+	// Clear out any completed requests
+	for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ )
+		{
+		CReadWriteRequest* request = iRequests[ii];
+		delete request;
+		iRequests.Remove(ii);
+		ii--;
+		}
+	}
+
+
+
+/**
+Returns the data type as a fourCC code of CProgressiveDownloadSource as a data source.
+
+@return The data type fourCC code.
+*/
+TFourCC CProgressiveDownloadSource::SourceDataTypeCode(TMediaId /*aMediaId*/)
+	{
+	return  iSourceFourCC ;
+	}
+
+/**
+Returns the data type as a fourCC code of CProgressiveDownloadSource as a data sink.
+
+@return The data type fourCC code
+*/
+TFourCC CProgressiveDownloadSource::SinkDataTypeCode(TMediaId /*aMediaId*/)
+	{
+	return  iSinkFourCC ;
+	}
+
+
+/**
+CProgressiveDownloadSource as a source is always passive so this function is not supported.
+
+@param  aBuffer
+        The emptied buffer.
+*/
+void CProgressiveDownloadSource::BufferEmptiedL(CMMFBuffer* /* aBuffer */)
+	{
+	Panic(EMMFFilePanicBufferEmptiedLNotSupported);
+	}
+
+/**
+Tests whether a source buffer can be created.
+
+@return	A boolean indicating if if CProgressiveDownloadSource can create its own buffer. EFalse if CProgressiveDownloadSource cannot
+        create it's own buffer.
+*/
+TBool CProgressiveDownloadSource::CanCreateSourceBuffer()
+	{
+	return EFalse;
+	}
+
+/**
+Creates a source buffer.
+
+@param  aMediaId
+        The Media ID.
+@param  aReference
+        A boolean indicating if MDataSource owns the buffer. ETrue if it does, EFalse if the caller
+        owns the buffer.
+
+@return	NULL as a CProgressiveDownloadSource cannot create it's own buffer
+*/
+CMMFBuffer* CProgressiveDownloadSource::CreateSourceBufferL( TMediaId /*aMediaId*/ , TBool& /*aReference*/)
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::CreateSourceBufferL"));
+    #endif
+	User::Leave(KErrNotSupported);
+	return NULL ;
+	}
+
+/**
+CProgressiveDownloadSource as a sink is always passive so this function is not supported.
+
+@param  aBuffer
+        The buffer.
+*/
+void CProgressiveDownloadSource::BufferFilledL(CMMFBuffer* /* aBuffer */)
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::BufferFilledL"));
+    #endif
+	Panic(EMMFFilePanicBufferFilledLNotSupported);
+	}
+
+/**
+Tests whether a sink buffer can be created.
+
+@return	A boolean indicating if the sink buffer can be created. EFalse if CProgressiveDownloadSource cannot create
+        it's own buffer
+*/
+TBool CProgressiveDownloadSource::CanCreateSinkBuffer()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::CanCreateSinkBuffer"));
+    #endif
+	return EFalse ;
+	}
+
+/**
+Creates a sink buffer.
+
+@param  aMediaId
+        The Media ID.
+@param  aReference
+        A boolean indicating if MDataSource owns the buffer. ETrue if MDataSource owns the buffer,
+        EFalse if the caller owns the buffer.
+
+@return	NULL as a CProgressiveDownloadSource cannot create it's own buffer
+*/
+CMMFBuffer* CProgressiveDownloadSource::CreateSinkBufferL(TMediaId /*aMediaId*/ , TBool& /*aReference*/)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::CreateSinkBufferL"));
+    #endif
+	User::Leave(KErrNotSupported);
+	return NULL ;
+	}
+
+
+/**
+Primes the source.
+
+When used as a source, the file prime opens the file as read only.
+*/
+void CProgressiveDownloadSource::SourcePrimeL()
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::SourcePrimeL"));
+    #endif
+
+	// don't reopen file if already open
+	if (!iFile)
+		{
+
+		if (iFileHandle)
+			{
+			iFile = CContentFile::NewL(iHandle, UniqueId());
+			}
+		else
+			{
+			// rj Open for progressive download need to have shared access
+			iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareAny);
+
+			}
+
+		}
+	iFileOpen = ETrue;
+	}
+
+/**
+Primes the sink.
+
+When used as a sink, the file prime opens the file for read/write access.
+*/
+void CProgressiveDownloadSource::SinkPrimeL()
+	{
+	// don't reopen file if already open
+	if (!iFile)
+		{
+
+		if (iFileHandle)
+			iFile = CF32File::NewL(iHandle);
+		else
+			iFile = CF32File::NewL(iFsSession, iFullFileName, EFileRead | EFileWrite);
+
+		iSinkNotStopped = ETrue;
+		}
+	iFileOpen = ETrue;
+	}
+
+/**
+Stops the file source. When stopping close the file.
+*/
+void CProgressiveDownloadSource::SourceStopL()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::SourceStopL"));
+    #endif
+	CancelRequests();
+
+    if(iFile == NULL) //rj
+       return;
+
+	iFileOpen = EFalse;
+	TInt pos = 0;
+	if (!iFileHandle && !iFile->IsProtected())
+		{
+		delete iFile;
+		iFile = NULL;
+	//	iFileSize = -1;
+		}
+	else
+		{
+		User::LeaveIfError(iFile->Seek(ESeekStart, pos));
+
+		}
+
+	iPosition=pos;
+	}
+
+/**
+Stops the file sink.
+
+When stopping close the file.
+*/
+void CProgressiveDownloadSource::SinkStopL()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::SinkStopL"));
+    #endif
+
+	CancelRequests();
+	iFileOpen = EFalse;
+	if (!iFileHandle)
+		{
+		iSinkNotStopped = EFalse;
+		delete iFile;
+		iFile = NULL;
+		}
+	else
+		{
+		TInt pos = 0;
+		User::LeaveIfError(iFile->Seek(ESeekStart, pos));
+		}
+	//iFileSize = -1;
+	iPosition=0;
+	}
+
+/**
+Returns a boolean indicating if the sink has been stopped.
+
+@return A boolean indicating if the sink has stopped.
+ */
+TBool CProgressiveDownloadSource::SinkStopped()
+	{
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::SinkStopped"));
+    #endif
+	if(iSinkNotStopped == EFalse)
+		return ETrue;
+	else
+		return EFalse;
+	}
+
+/**
+Evaluates a given intent against the rights associated with the file.
+
+The rights are not updated by this function call.
+
+@param  aIntent
+        The intent to evaluate.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::EvaluateIntent(ContentAccess::TIntent aIntent) const
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::EvaluateIntent"));
+    #endif
+	if (iFile==NULL)
+		{
+		return KErrNotReady;
+		}
+
+	return iFile->EvaluateIntent(aIntent);
+	}
+
+/**
+Evaluates and executes a given intent against the rights associated with the file.
+
+The rights object is updated after calling this function.
+
+@param  aIntent
+        The intent to evaluate.
+
+@return An error code indicating if the function call was successful. KErrNone on success, otherwise
+        another of the system-wide error codes.
+*/
+TInt CProgressiveDownloadSource::ExecuteIntent(ContentAccess::TIntent aIntent)
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::ExecuteIntent"));
+    #endif
+	if (!iFile)
+		return KErrNotReady;
+
+	return iFile->ExecuteIntent(aIntent);
+	}
+
+/**
+Returns whether the file is protected.
+
+@return A boolean indicating if the file is protected. ETrue if the file is protected.
+*/
+TBool CProgressiveDownloadSource::IsProtectedL() const
+	{
+
+	#if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::IsProtectedL"));
+    #endif
+	if (!iFile)
+		User::Leave(KErrNotReady);
+
+	return iFile->IsProtected();
+	}
+
+
+
+
+
+TInt CProgressiveDownloadSource::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue)
+	{
+	if (iFile==NULL)
+		{
+		return KErrNotReady;
+		}
+
+	return iFile->SetAgentProperty(aProperty, aValue);
+	}
+
+void CProgressiveDownloadSource::SourceCustomCommand(TMMFMessage& aMessage)
+	{
+    #if _DEBUG
+	  RDebug::Print(_L("CProgressiveDownloadSource::SourceCustomCommand"));
+    #endif
+
+    TInt err= KErrNone;
+	switch(aMessage.Function())
+		  {
+		  case EGETFILEPOSITION:
+			  {
+			  //get iPosition;
+			   #if _DEBUG
+	           RDebug::Print(_L("CProgressiveDownloadSource::SrcCustomCommand file position %d"),iPosition);
+               #endif
+              TPckgBuf<TInt> positionPckg(iPosition);
+			  err = aMessage.WriteDataToClient(positionPckg);
+
+			  break;
+			  }
+          case ESETFILESIZE:
+			  {
+			  //set file size;
+			  TPckgBuf<TInt> fileSizePckg;
+			  err = aMessage.ReadData1FromClient(fileSizePckg);
+			  if((err==KErrNone) && (fileSizePckg()>0))
+				  SetSize(fileSizePckg());
+
+			  break;
+
+			  }
+		 case ESETBYTESDOWNLOADED:
+		 	  {
+		      TPckgBuf<TInt> bytesDownloadedPckg;
+		      err = aMessage.ReadData1FromClient(bytesDownloadedPckg);
+
+		      if((err==KErrNone) &&(bytesDownloadedPckg()>0))
+		          iBytesDownloaded = bytesDownloadedPckg();
+		      break;
+		 	  }
+		  default:
+			  err = KErrNotSupported;
+			  break;
+		  }
+
+	aMessage.Complete(err);
+
+	}
+
+/*
+ *	Returns ETrue if the request can safely be deleted.
+ */
+TBool CReadWriteRequest::Completed()
+	{
+	return iCompleted ;
+	}
+
+/*
+ *	Returns the data member of CMMFDataBuffer or CMMFTransferBuffer (as TPtr8)
+ *
+ */
+TDes8& CReadWriteRequest::BufferDes()
+	{
+	if(iTransferBufferCopy)
+		return iTransferBufferCopy->Des();
+	else
+		{
+		//reset iBufferDes in case iBuffer has changed...
+		iBufferDes = &(STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data());
+		return *iBufferDes;
+		}
+	}
+
+const TDesC8& CReadWriteRequest::BufferDesC()
+	{
+	if(iTransferBufferCopy)
+		return iTransferBufferCopy->Des();
+	else
+		return BufferDes();
+	}
+
+
+/*
+ *	Destructor.
+ */
+CReadWriteRequest::~CReadWriteRequest()
+	{
+	Cancel();
+	if(iTransferBufferCopy)
+		iTransferBufferCopy->SetInUse(EFalse);
+	}
+
+/*
+ *	Allows owning class access to SetActive()
+ */
+void CReadWriteRequest::SetActive()
+	{
+	CActive::SetActive() ;
+	}
+
+/*
+ *  For the moment at least...    Canceled requests may be deleted
+ */
+void CReadWriteRequest::DoCancel()
+	{
+	iCompleted = ETrue ;
+	}
+
+/*
+ *	Called when errors in RunL force Leave.  For the moment just mark the request deletable
+ */
+TInt CReadWriteRequest::RunError( TInt aError )
+	{
+	//RunL can leave.
+	iCompleted = ETrue ;
+	iError = aError; //keep this error internally for now
+	return KErrNone ;
+	}
+
+/*
+ *	On completion of read request call back to the MDataSink
+ */
+void CReadRequest::RunL()
+	{
+
+	#if _DEBUG
+	   RDebug::Print(_L("CReadRequest::RunL file byte position %d"),iPosition);
+	   RDebug::Print(_L("CReadRequest::RunL buffer length %d"),BufferDes().Length());
+	#endif
+
+	if (iStatus != KErrNone)
+		{
+		TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int());
+		iEventHandler->SendEventToClient(event);
+		}
+	else
+		{
+		//Copy the data from the normal buffer into the Transfer buffer
+		if(iTransferBufferCopy)
+			{
+			//must specify the size here as the dest may be smaller than the source.
+			TDes8& destDesc = STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data();
+			destDesc.Copy(iTransferBufferCopy->Des().Left(destDesc.MaxLength()));
+
+			iTransferBufferCopy->SetInUse(EFalse);
+			}
+
+	   #if _DEBUG
+	      RDebug::Print(_L("CReadRequest::RunL bytes downloaded %d"),iBytesDownloaded);
+	   #endif
+	   if(iBytesDownloaded > 0 &&
+	      iBytesDownloaded <= iPosition + BufferDes().Length() &&
+	      iBytesDownloaded < iFileSize)
+		 {
+	   	 #if _DEBUG
+	       RDebug::Print(_L("CReadRequest::RunL - OUT OF DATA"));
+	   	 #endif
+
+	     STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data().SetLength(0);
+
+		 }
+	    else
+	     {
+	     iPosition = iPosition + BufferDes().Length();
+	     }
+
+		//has all the files data been read
+		if(iPosition >= iFileSize)
+			{
+        #if _DEBUG
+           RDebug::Print(_L("CReadRequest::RunL filesize %d"),iFileSize);
+		   RDebug::Print(_L("CReadRequest::RunL file position %d"),iPosition);
+		   RDebug::Print(_L("CReadRequest::RunL setlastbuffer "));
+        #endif
+
+			iBuffer->SetLastBuffer(ETrue);
+			}
+
+		REINTERPRET_CAST(MDataSink*, iSinkOrSource)->BufferFilledL(iBuffer) ; // callback to MDataSource/Sink
+		}
+
+	iCompleted = ETrue ;
+	}
+
+/*
+ *  On completion of write request call back to the MDataSource
+ */
+void CWriteRequest::RunL()
+	{
+	if(iTransferBufferCopy)
+		iTransferBufferCopy->SetInUse(EFalse);
+
+	if (iStatus != KErrNone)
+		{
+		TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int());
+		iEventHandler->SendEventToClient(event);
+		}
+	else
+		REINTERPRET_CAST(MDataSource*, iSinkOrSource)->BufferEmptiedL(iBuffer) ; // callback to MDataSource/Sink
+
+	iCompleted = ETrue ;
+	}
+
+CProgressiveDownloadSource::CMMFFileAsyncEventHandler::CMMFFileAsyncEventHandler(CProgressiveDownloadSource* aParent)
+	{
+	iParent = aParent;
+	}
+
+CProgressiveDownloadSource::CMMFFileAsyncEventHandler::~CMMFFileAsyncEventHandler()
+	{
+	}
+
+TInt CProgressiveDownloadSource::CMMFFileAsyncEventHandler::SendEventToClient(const TMMFEvent& aEvent)
+	{
+
+#if _DEBUG
+     RDebug::Print(_L("CProgressiveDownloadSource::CMMFFileAsyncEventHandler::SendEventToClient err=%d"),aEvent.iErrorCode);
+#endif
+
+	if(aEvent.iErrorCode == KErrNotReady)//i.e. MMC removed while recording
+		TRAP_IGNORE(iParent->SinkStopL());
+	return iParent->iEventHandler->SendEventToClient(aEvent);
+	}
+
+
+
+// __________________________________________________________________________
+// Exported proxy for instantiation method resolution
+// Define the interface UIDs
+
+const TImplementationProxy ImplementationTable[] =
+	{
+		IMPLEMENTATION_PROXY_ENTRY(KProgressiveDownloadSourceUid,CProgressiveDownloadSource::NewSourceL)
+	};
+
+EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
+	{
+	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
+
+	return ImplementationTable;
+	}