sl@0: // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: #include <f32file.h>
sl@0: #include <e32std.h>
sl@0: #include <mmf/server/mmfdatabuffer.h>
sl@0: #include <mmf/common/mmfutilities.h>
sl@0: #include <mmf/common/mmfcontroller.h>
sl@0: #include <mmf/common/mmfpaniccodes.h>
sl@0: #include <mmf/server/mmffile.h>
sl@0: #include "MmffilePriv.h"
sl@0: #include "FileAccess.h"
sl@0: 
sl@0: void Panic(TMMFFilePanicCode aPanicCode)
sl@0: 	{
sl@0: 	_LIT(KMMFFilePanicCategory, "MMFFile");
sl@0: 	User::Panic(KMMFFilePanicCategory, aPanicCode);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0:  * Constructs a CTransferBufferCopy
sl@0:  *
sl@0:  * @return CTransferBufferCopy*
sl@0:  */
sl@0: CTransferBufferCopy* CTransferBufferCopy::NewL(TInt aMaxLength)
sl@0: 	{
sl@0: 	CTransferBufferCopy* self = new (ELeave) CTransferBufferCopy(aMaxLength);
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL();
sl@0: 	CleanupStack::Pop(self);
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0:  * Second phase constructor for CTransferBufferCopy
sl@0:  *
sl@0:  * @return void
sl@0:  */
sl@0: void CTransferBufferCopy::ConstructL()
sl@0: 	{
sl@0: 	iBuffer = static_cast<TUint8*>(User::AllocL(iMaxLength));
sl@0: 	iBufferDes.Set(iBuffer,0,iMaxLength);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Destructor.
sl@0: */
sl@0: CMMFFile::~CMMFFile() 
sl@0: 	{
sl@0: 	delete iFile;
sl@0: 	
sl@0: 	
sl@0: 	iHandle.Close();
sl@0: 	iFsSession.Close();
sl@0: 	delete iFileName;
sl@0: 	delete iFileExt;
sl@0: 	delete iFilePath;
sl@0: 	delete iFileDrive;
sl@0: 	delete iMmfFileEventHandler;
sl@0: 	delete iCAFParameters;
sl@0: 
sl@0: 	// Get rid of everything in RArray's & close them.
sl@0: 	iRequests.ResetAndDestroy();
sl@0: 	iTransferBufferCopies.ResetAndDestroy();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Protected constructor.
sl@0: 
sl@0: The default implementation is empty.
sl@0: */
sl@0: CMMFFile::CMMFFile() : CMMFClip( KUidMmfFileSource, KUidMmfFileSink ), iFileSize(-1)
sl@0: 	{
sl@0: 	iSinkNotStopped = EFalse;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Constructs an CMMFFile MDataSource.
sl@0: 
sl@0: @return A pointer to the new CMMFFile data source.
sl@0: */
sl@0: MDataSource* CMMFFile::NewSourceL() 
sl@0: 	{
sl@0: 	CMMFFile* self = new (ELeave) CMMFFile ;
sl@0: 	return STATIC_CAST( MDataSource*, self ) ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Constructs a CMMFFile MDataSink
sl@0: 
sl@0: @return A pointer to the new CMMFFile data sink.
sl@0: */
sl@0: MDataSink* CMMFFile::NewSinkL()
sl@0: 	{
sl@0: 	CMMFFile* self = new (ELeave) CMMFFile ;
sl@0: 	return STATIC_CAST( MDataSink*, self ) ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Perform source construction dependant on the source construction
sl@0: initialisation data aInitData.
sl@0: 
sl@0: @param  aInitData
sl@0:         The TPckg<TMMFFileParams> descriptor package containing the file name and full path.
sl@0: */
sl@0: void CMMFFile::ConstructSourceL(const TDesC8& aInitData ) 
sl@0: 	{
sl@0: 	ConstructL(aInitData, ESourceMode);
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Performs sink construction dependant on the sink construction
sl@0: initialisation data aInitData.
sl@0: 
sl@0: @param  aInitData
sl@0:         The TPckg<TMMFFileParams> descriptor package containing the file name and full path.
sl@0: */
sl@0: void CMMFFile::ConstructSinkL(const TDesC8& aInitData)
sl@0: 	{
sl@0: 	ConstructL(aInitData, ESinkMode);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Protected constructor.
sl@0: 
sl@0: Extracts the initialisation data provided by the calling functions: ConstructSourceL() and 
sl@0: ConstructSinkL(). Creates a file server session and sets up file name. If there is a file name and 
sl@0: it cannot be found this function leaves. If there is no file name the function leaves. Does not 
sl@0: attempt to open the file or check whether the file exists.
sl@0: 
sl@0: If aInitData contains a TMMFFileHandleParams instead of TMMFFileParams, the source/sink is constructed from 
sl@0: the file handle provided by the caller
sl@0: 
sl@0: @param  aInitData
sl@0:         Initialisation data packaged in a TMMFFileParams or in a TMMFFileHandleParams (File Handle)
sl@0: */
sl@0: void CMMFFile::ConstructL(const TDesC8& aInitData,TMMFileMode aFileMode)
sl@0: 	{
sl@0: 	User::LeaveIfError(iFsSession.Connect());
sl@0: #ifdef __IPC_V2_PRESENT__
sl@0: 	// on IPCv2 we auto attach
sl@0: 	User::LeaveIfError(iFsSession.ShareAuto());
sl@0: #else
sl@0: 	// on IPCv1 we use explicit - more efficient
sl@0: 	User::LeaveIfError(iFsSession.Share(RSessionBase::EExplicitAttach));
sl@0: #endif
sl@0: 
sl@0: 	User::LeaveIfError(iFsSession.ShareProtected());
sl@0: 	
sl@0: 	HBufC* filename = NULL; 
sl@0: 	
sl@0: 	iCAFParameters = new (ELeave) CCAFParameters;
sl@0: 	TBool drmContent = EFalse;
sl@0: 	RDesReadStream stream(aInitData);
sl@0: 	CleanupClosePushL(stream);
sl@0: 	
sl@0: 	TUid initUid = TUid::Uid(stream.ReadInt32L());
sl@0: 
sl@0: 	if (initUid == KMMFileHandleSourceUid)
sl@0: 		{
sl@0: 		TPckgBuf<RFile*> fileptr;
sl@0: 		stream.ReadL(fileptr);
sl@0: 		
sl@0: 		iHandle.Duplicate(*fileptr());
sl@0: 
sl@0: 		TInt length = stream.ReadInt32L();
sl@0: 		if (length>0)
sl@0: 			{
sl@0: 			iCAFParameters->iUniqueId = HBufC::NewL(length);
sl@0: 			TPtr16 ptr = iCAFParameters->iUniqueId->Des();
sl@0: 			stream.ReadL(ptr, length);
sl@0: 			}
sl@0: 		iFileHandle = ETrue;
sl@0: 
sl@0: 		filename = HBufC::NewMaxLC(KMaxFileName);
sl@0: 		TPtr ptr = filename->Des();
sl@0: 		User::LeaveIfError(iHandle.FullName(ptr));
sl@0: 		drmContent = ETrue;
sl@0: 		
sl@0: 		iCAFParameters->iEnableUI = stream.ReadInt32L();
sl@0: 		}
sl@0: 		
sl@0: 	else if (initUid == KMMFileSourceUid)
sl@0: 		{
sl@0: 		TInt length = stream.ReadInt32L();
sl@0: 		filename = HBufC::NewMaxLC(length);
sl@0: 		TPtr ptr = filename->Des();
sl@0: 		stream.ReadL(ptr, length);
sl@0: 
sl@0: 		length = stream.ReadInt32L();
sl@0: 		if (length>0)
sl@0: 			{
sl@0: 			iCAFParameters->iUniqueId = HBufC::NewMaxL(length);
sl@0: 			ptr.Set(iCAFParameters->iUniqueId->Des());
sl@0: 			stream.ReadL(ptr, length);
sl@0: 			}
sl@0: 		drmContent = ETrue;
sl@0: 		iCAFParameters->iEnableUI = stream.ReadInt32L();
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: //		XXX If the UID is unknown we should reject, but  currently
sl@0: //		code also used for older calls that just supply filename.
sl@0: //		User::Leave(KErrNotSupported);
sl@0: 		}
sl@0: 	
sl@0: 	if ((filename == NULL) && aInitData.Length() == sizeof(TMMFFileHandleParams))
sl@0: 		{
sl@0: 		TMMFFileHandleParams params;
sl@0: 		TPckgC<TMMFFileHandleParams> config(params);
sl@0: 		config.Set(aInitData);
sl@0: 		params = config();
sl@0: 
sl@0: 		
sl@0: 		if (params.iUid == KFileHandleUid)
sl@0: 			{
sl@0: 			User::LeaveIfError(iHandle.Duplicate(*params.iFile));
sl@0: 			TInt pos = 0;
sl@0: 			// make sure the duplicate handle is at the start of the file - the usage of the file handle really requires this
sl@0: 			User::LeaveIfError(iHandle.Seek(ESeekStart, pos));
sl@0: 			iFileHandle = ETrue;
sl@0: 			ASSERT(filename == NULL);
sl@0: 			filename = HBufC::NewMaxLC(KMaxFileName);
sl@0: 			TPtr ptr = filename->Des();
sl@0: 			User::LeaveIfError(iHandle.FullName(ptr));
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	if (filename == NULL) // do old case as last resort
sl@0: 		{
sl@0: 		TMMFFileParams params;
sl@0: 		TPckgC<TMMFFileParams> config(params);
sl@0: 		config.Set(aInitData);
sl@0: 		params = config();
sl@0: 		
sl@0: 		filename = params.iPath.AllocLC();
sl@0: 		}
sl@0: 	
sl@0: 	ASSERT(filename != NULL);
sl@0: 	
sl@0: 	TParse parser ;
sl@0: 	User::LeaveIfError(parser.Set(*filename, NULL, NULL));
sl@0: 	CleanupStack::PopAndDestroy(2, &stream); //filename, stream
sl@0: 	if ( !( parser.NamePresent() ) && !( parser.ExtPresent() ) )
sl@0: 		{
sl@0: 		User::Leave( KErrBadName ) ;
sl@0: 		}
sl@0: 	
sl@0: 	iFullFileName.Copy( parser.FullName() ) ;	
sl@0: 	iFileName = parser.Name().AllocL() ;
sl@0: 	iFileExt = parser.Ext().AllocL() ;
sl@0: 	iFilePath = parser.Path().AllocL() ;
sl@0: 	iFileDrive = parser.Drive().AllocL() ;
sl@0: 	
sl@0: 	// in order to simulate old behaviour we are not passing error out
sl@0: 	// but will try to create Content again during PrimeL()
sl@0: 	if (drmContent && aFileMode==ESourceMode)
sl@0: 		{
sl@0: 		TInt contentError;
sl@0: 		if (iFileHandle)
sl@0: 			{
sl@0: 			TRAP(contentError, 
sl@0: 				iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI);
sl@0: 				);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			// Open for read-only access
sl@0: 			TRAP(contentError,
sl@0: 				iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareReadersOnly, iCAFParameters->iEnableUI);
sl@0: 			);
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 	
sl@0: 
sl@0: /**
sl@0: @deprecated - Replaced by CMMFFile::Data()
sl@0: 
sl@0: Returns an RFile handle to the current file.
sl@0: 
sl@0: If there is no current file, one is created. If the file exists then it is opened with read access 
sl@0: if it is read only, write access otherwise. If the file does not exist then it is opened with
sl@0: write access.
sl@0: 
sl@0: @leave KErrNotReady
sl@0:        The file is not open.
sl@0: 
sl@0: @return A handle to the current file.
sl@0: @see CMMFFile::Data()
sl@0: */
sl@0: RFile& CMMFFile::FileL()
sl@0: 	{
sl@0: 	if (!iFile)
sl@0: 		User::Leave(KErrNotReady);
sl@0: 	if (iFileHandle)
sl@0: 		return iHandle;
sl@0: 	else
sl@0: 		return iFile->FileL();
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Returns the file name of the current file.
sl@0: 
sl@0: Note: This will give the wrong answer if the file is renamed!
sl@0: 
sl@0: @return The FileName (without extension).
sl@0: */
sl@0: const TDesC& CMMFFile::FileName() const
sl@0: 	{
sl@0: 	return *iFileName ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns the extension of the current file.
sl@0: 
sl@0: Note: This will give the wrong answer if the file is renamed!
sl@0: 
sl@0: @return The File Extension.
sl@0: */
sl@0: const TDesC& CMMFFile::Extension() const 
sl@0: 	{
sl@0: 	return *iFileExt ;
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Returns the path of the current file.
sl@0: 
sl@0: Note: This will give the wrong answer if the file is renamed!
sl@0: 
sl@0: @return The FilePath (without filename and extension)
sl@0: */
sl@0: const TDesC& CMMFFile::FilePath() const 
sl@0: 	{
sl@0: 	return *iFilePath ;
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Returns the drive on which the current file is located.
sl@0: 
sl@0: Note: This will give the wrong answer if the file is renamed!
sl@0: 
sl@0: @return The FileDrive (drive letter only, without path, filename and extension).
sl@0: */
sl@0: const TDesC& CMMFFile::FileDrive() const 
sl@0: 	{
sl@0: 	return *iFileDrive ;
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Returns the full name of the current file.
sl@0: 
sl@0: Note: This will give the wrong answer if the file is renamed!
sl@0: 
sl@0: @return The file name (full filename including drive letter, without path, filename and extension).
sl@0: */
sl@0: const TFileName CMMFFile::FullName() const
sl@0: 	{
sl@0: 	return iFullFileName;
sl@0: 	}
sl@0: 	
sl@0: /** 
sl@0: Returns the uniqueID associated with this content. If no uniqueID has been provided, a null
sl@0: descriptor will be provided
sl@0: 
sl@0: @return The UniqueID
sl@0: */
sl@0: const TDesC& CMMFFile::UniqueId() const
sl@0: 	{
sl@0: 	if (iCAFParameters->iUniqueId)
sl@0: 		return *(iCAFParameters->iUniqueId);
sl@0: 	else
sl@0: 		return KNullDesC;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /**
sl@0: Deletes the file.
sl@0: 
sl@0: Closes the currently open file, then deletes it. If the file source is accessing a file handle, 
sl@0: the file is truncated to 0 bytes instead.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::Delete()				
sl@0: 	{
sl@0: 	TInt result = KErrNone;
sl@0: 	if (!iFileHandle)
sl@0: 		{
sl@0: 		delete iFile;
sl@0: 		iFile = NULL;
sl@0: 		iFileSize=-1;
sl@0: 		iPosition=0;
sl@0: 
sl@0: 		result = iFsSession.Delete(iFullFileName);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		iFileSize=-1;
sl@0: 		iPosition=0;
sl@0: 		
sl@0: 		if (iFile)
sl@0: 			{
sl@0: 			result = iFile->SetSize(0);
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	return result;
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Sets the file size.
sl@0: 
sl@0: @param  aSize
sl@0:         The size of the file.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::SetSize(TInt aSize)
sl@0: 	{
sl@0: 	if ( !iFile )
sl@0: 		return KErrNotReady;
sl@0: 	TInt err =  iFile->SetSize(aSize);
sl@0: 	if(err == KErrNone)
sl@0: 		iFileSize = aSize;
sl@0: 	else
sl@0: 		iFileSize = -1;
sl@0: 
sl@0: 	return err;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Obtains a CTransferBufferCopy from iTransferBufferCopies that is
sl@0: at least as big as that required.
sl@0: 
sl@0: There is no need to put the pointer returned by this method onto the CleanupStack
sl@0: as it will have already been placed into iTransferBufferCopies.
sl@0: 
sl@0: @param  aMaxLength
sl@0:         The size required.
sl@0: 
sl@0: @return A pointer to a valid CTransferBufferCopy.
sl@0: */
sl@0: CTransferBufferCopy* CMMFFile::ObtainCopyOfTransferBufferL(TInt aMaxLength)
sl@0: 	{
sl@0: 	//find a free transfer buffer copy of the right size
sl@0: 	TInt firstFree = -1;
sl@0: 	CTransferBufferCopy* transBufCopyToUse = NULL;
sl@0: 
sl@0: 	for(TInt cnt=0; cnt < iTransferBufferCopies.Count(); cnt++)
sl@0: 		{
sl@0: 		if(!iTransferBufferCopies[cnt]->InUse())
sl@0: 			{
sl@0: 			//record the first free entry, we may remove this
sl@0: 			//if entries in iTransferBufferCopies > KAcceptableTransferBufferCopiesSize
sl@0: 			if(firstFree == -1) 
sl@0: 				firstFree = cnt;
sl@0: 
sl@0: 			if(iTransferBufferCopies[cnt]->MaxLength() >= aMaxLength)
sl@0: 				{
sl@0: 				transBufCopyToUse = iTransferBufferCopies[cnt];
sl@0: 
sl@0: 				//Set the MaxLength. This will ensure that the copy acts the same as
sl@0: 				//the original Transfer buffer, eg. file server will throw KErrOverflow
sl@0: 				transBufCopyToUse->ReUse(aMaxLength);
sl@0: 				break;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	//If we failed to find a suitable entry, we need to create a new one
sl@0: 	if(!transBufCopyToUse)
sl@0: 		{
sl@0: 		//Firstly, should we re-cycle an existing entry?
sl@0: 		//There must be entries in the array, a free entry must have been found,
sl@0: 		//the size of the array must be beyond the water mark where we want to start
sl@0: 		//cycling free entries.
sl@0: 		if((iTransferBufferCopies.Count() > 0) &&
sl@0: 			(firstFree != -1) &&
sl@0: 			(iTransferBufferCopies.Count() > KAcceptableTransferBufferCopiesSize))
sl@0: 			{
sl@0: 			delete iTransferBufferCopies[firstFree];
sl@0: 			iTransferBufferCopies.Remove(firstFree);
sl@0: 
sl@0: 			transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength);
sl@0: 			CleanupStack::PushL(transBufCopyToUse);
sl@0: 			User::LeaveIfError(iTransferBufferCopies.Insert(transBufCopyToUse,firstFree));
sl@0: 				
sl@0: 			CleanupStack::Pop();
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: #ifdef _DEBUG
sl@0: 			if(iTransferBufferCopies.Count() > KMaximumTransferBufferCopiesSize)
sl@0: 				{
sl@0: 				User::Panic(_L("iTransferBufferCopies grew too large in CMMFFile"),KErrTooBig);
sl@0: 				}
sl@0: #endif
sl@0: 
sl@0: 			transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength);
sl@0: 			CleanupStack::PushL(transBufCopyToUse);
sl@0: 			User::LeaveIfError(iTransferBufferCopies.Append(transBufCopyToUse));
sl@0: 
sl@0: 			CleanupStack::Pop();
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	return transBufCopyToUse;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: /** 
sl@0: Loads aBuffer from iFile.
sl@0: 
sl@0: The file must already be open for reading. File read is asynchronous. CReadRequest is created to 
sl@0: respond to completion.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The buffer to be filled from the file.
sl@0: @param  aConsumer
sl@0:         The data sink consumer of the buffer.
sl@0: */
sl@0: void CMMFFile::FillBufferL( CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId /*aMediaId*/ )
sl@0: 	{
sl@0: 	// Requires that iFile is open for read.
sl@0: 	// Reads data from iFile into aBuffer
sl@0: 	if ((aConsumer == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile || (iMmfFileEventHandler == NULL))
sl@0: 		User::Leave(KErrNotReady);
sl@0: 
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		CTransferBufferCopy* transBufCopy = NULL;
sl@0: 		CReadRequest* request = NULL;
sl@0: 
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		TInt requestSize;
sl@0: 		if(aBuffer->RequestSize())
sl@0: 			requestSize = aBuffer->RequestSize();
sl@0: 		else
sl@0: 			requestSize = aBufferDes.MaxLength();
sl@0: 
sl@0: 		//check whether buffer is safe to send to file server
sl@0: 		//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 			{
sl@0: 			//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, iPosition, Size(), iMmfFileEventHandler);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, iPosition, Size(), iMmfFileEventHandler);
sl@0: 			}
sl@0: 
sl@0: 		CleanupStack::PushL( request );
sl@0: 
sl@0: 		StoreRequestL(request); // transfers ownership
sl@0: 		CleanupStack::Pop() ; // request
sl@0: 
sl@0: 		iFile->Read(request->BufferDes(), requestSize, request->iStatus);
sl@0: 		iPosition += requestSize;
sl@0: 		
sl@0: 		if (iPosition >= iFileSize)
sl@0: 			{
sl@0: 			aBuffer->SetLastBuffer(ETrue);
sl@0: 			}
sl@0: 
sl@0: 		request->SetActive();
sl@0: 		}
sl@0: 	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		User::Leave( KErrNotSupported ) ;
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Empties aBuffer into iFile. The file must be already open for writing.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The buffer to be written to the file.
sl@0: @param  aSupplier
sl@0:         The data source supplier of the buffer.
sl@0: */
sl@0: void CMMFFile::EmptyBufferL( CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/ )
sl@0: 	{
sl@0: 	// Requires that iFile is open for write.
sl@0: 	// Writes data from iFile into aBuffer
sl@0: 	if ((aSupplier == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile || (iMmfFileEventHandler == NULL))
sl@0: 		User::Leave(KErrNotReady);
sl@0: 
sl@0: 	CTransferBufferCopy* transBufCopy = NULL;
sl@0: 	
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		CWriteRequest* request = NULL;
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		//check whether buffer is safe to send to file server
sl@0: 		//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 			{
sl@0: 			//Obtain a normal buffer to send to the file server
sl@0: 			//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 
sl@0: 			//Copy the data into the buffer we will send to the file server
sl@0: 			transBufCopy->Des().Copy(aBufferDes);
sl@0: 
sl@0: 			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler);
sl@0: 			}
sl@0: 
sl@0: 		CleanupStack::PushL( request );
sl@0: 
sl@0: 		StoreRequestL(request);  // transfers ownership
sl@0: 		CleanupStack::Pop(); // request
sl@0: 
sl@0: 		iFile->Write(request->BufferDes(), request->BufferDes().Length(), request->iStatus);
sl@0: 		request->SetActive();
sl@0: 		}
sl@0: 	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		User::Leave( KErrNotSupported ) ;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Loads aLength number of bytes into aBuffer from specified point in iFile.
sl@0: 
sl@0: @param  aLength
sl@0:         The number of bytes to be read into buffer.
sl@0: @param  aBuffer
sl@0:         The buffer to be filled from the file.
sl@0: @param  aPosition
sl@0:         The offset into the file at which to start reading.
sl@0: @param  aConsumer
sl@0:         The data sink consumer of the buffer.
sl@0: */
sl@0: void CMMFFile::ReadBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
sl@0: 	{
sl@0: 	// Requires that iFile is open for read.
sl@0: 	// Reads data from iFile into aBuffer
sl@0: 	if ((aLength < 0) || (aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile || (iMmfFileEventHandler == NULL))
sl@0: 		User::Leave(KErrNotReady);
sl@0: 
sl@0: 	CTransferBufferCopy* transBufCopy = NULL;
sl@0: 
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		CReadRequest* request = NULL;
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 		
sl@0: 		//check whether buffer is safe to send to file server
sl@0: 		//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 			{
sl@0: 			//Obtain a normal buffer to send to the file server
sl@0: 			//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 			transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 
sl@0: 			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, aPosition, Size(), iMmfFileEventHandler);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, aPosition, Size(), iMmfFileEventHandler);
sl@0: 			}
sl@0: 
sl@0: 		CleanupStack::PushL( request );
sl@0: 
sl@0: 		StoreRequestL(request) ;  //transfers ownership
sl@0: 		CleanupStack::Pop() ; //request
sl@0: 
sl@0: 		TInt err = iFile->Read(aPosition, request->BufferDes(), aLength, request->iStatus);
sl@0: 		if (err == KErrCANotSupported)
sl@0: 			{
sl@0: 			err = KErrNone;
sl@0: 			if (aPosition != iPosition)
sl@0: 				{
sl@0: 				err = iFile->Seek(ESeekStart, aPosition);
sl@0: 				}
sl@0: 			if (err==KErrNone)
sl@0: 				{
sl@0: 				iFile->Read(request->BufferDes(), aLength, request->iStatus);
sl@0: 				}
sl@0: 			}
sl@0: 		
sl@0: 		if (err != KErrNone)
sl@0: 			{
sl@0: 			TRequestStatus* status = &request->iStatus;
sl@0: 			User::RequestComplete(status, err);
sl@0: 			}
sl@0: 
sl@0: 		iPosition = aPosition + aLength;
sl@0: 		
sl@0: 		if (iPosition >= iFileSize)
sl@0: 			{
sl@0: 			aBuffer->SetLastBuffer(ETrue);
sl@0: 			}
sl@0: 
sl@0: 		request->SetActive();
sl@0: 		}
sl@0: 	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		User::Leave( KErrNotSupported ) ;
sl@0: 	}
sl@0: 	
sl@0: 	
sl@0: /**
sl@0: Loads aBuffer from specified point in iFile.
sl@0: 
sl@0: The file must already be open for reading.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The buffer to be filled from the file.
sl@0: @param  aPosition
sl@0:         The offset into file at which to start reading.
sl@0: @param  aConsumer
sl@0:         The data sink consumer of the buffer.
sl@0: */
sl@0: void CMMFFile::ReadBufferL(CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
sl@0: 	{
sl@0: 	// Requires that iFile is open for read.
sl@0: 	// Reads data from iFile into aBuffer
sl@0: 	if ((aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		TInt requestSize;
sl@0: 		if(aBuffer->RequestSize())
sl@0: 			requestSize = aBuffer->RequestSize();
sl@0: 		else
sl@0: 			requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().MaxLength();
sl@0: 
sl@0: 		ReadBufferL(requestSize, aBuffer, aPosition, aConsumer);
sl@0: 		}
sl@0: 	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		User::Leave(KErrNotSupported);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /**
sl@0: Loads aBuffer from specified point in iFile.  Note that this is a synchronous read.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The buffer to be filled from the file.
sl@0: @param  aPosition
sl@0:         The offset into file at which to start reading.
sl@0: */
sl@0: void CMMFFile::ReadBufferL( CMMFBuffer* aBuffer, TInt aPosition)
sl@0: 	{
sl@0: 	// Requires that iFile is open for read.
sl@0: 	// Reads data from iFile into aBuffer
sl@0: 	if ((aPosition<0) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile)
sl@0: 		User::Leave(KErrNotReady);
sl@0: 
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		TInt requestSize;
sl@0: 		if(aBuffer->RequestSize())
sl@0: 			requestSize = aBuffer->RequestSize();
sl@0: 		else
sl@0: 			requestSize = aBufferDes.MaxLength();
sl@0: 
sl@0: 		//check whether buffer is safe to send to file server
sl@0: 		//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 			{
sl@0: 			//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 			CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 
sl@0: 			User::LeaveIfError(iFile->Seek(ESeekStart, aPosition));
sl@0: 			User::LeaveIfError(iFile->Read(transBufCopy->Des(), requestSize));
sl@0: 			aBufferDes.Copy(transBufCopy->Des().Left(aBufferDes.MaxLength()));
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			User::LeaveIfError(iFile->Seek(ESeekStart, aPosition));
sl@0: 			User::LeaveIfError(iFile->Read(aBufferDes, requestSize));
sl@0: 			}
sl@0: 
sl@0: 		iPosition = aPosition + aBufferDes.Length();
sl@0: 		
sl@0: 		//check if the buffer is the last buffer and if so set the last buffer flag on the CMMFDataBuffer
sl@0: 		//NB: setting last buffer is the done by the formatter, but this is a hang over to account for 
sl@0: 		//existing formatters that may fail if this is removed.
sl@0: 		if (iPosition >= Size())
sl@0: 			{
sl@0: 			aBuffer->SetLastBuffer(ETrue);
sl@0: 			}
sl@0: 		}
sl@0: 	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		User::Leave(KErrNotSupported); 
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Empties aLength bytes from aBuffer into iFile at specified location.
sl@0: 
sl@0: @param  aLength
sl@0:         The number of bytes to be emptied from buffer.
sl@0: @param  aBuffer
sl@0:         The data buffer containing bytes to be written.
sl@0: @param  aPosition
sl@0:         The offset into file at which to start writing.
sl@0: @param  aSupplier
sl@0:         The data source to be notified when the write has been completed.
sl@0: 
sl@0: @leave  KErrNotReady 
sl@0:         SinkPrimeL() and SinkThreadLogon() have not been called.
sl@0: @leave  KErrArgument 
sl@0:         aLength<0 or aPosition<0 or aSupplier is NULL.
sl@0: @leave  KErrNotSupported 
sl@0:         aBuffer is not a supported CMMFDataBuffer
sl@0: */
sl@0: void CMMFFile::WriteBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier)
sl@0: 	{
sl@0: 	if ((aLength<0) || (aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile || (iMmfFileEventHandler == NULL))
sl@0: 		User::Leave(KErrNotReady);
sl@0: 	
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		CWriteRequest* request = NULL;
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		//check whether buffer is safe to send to file server
sl@0: 		//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 		if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 			{
sl@0: 			//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 			//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 			CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 
sl@0: 			transBufCopy->Des().Copy(aBufferDes);
sl@0: 
sl@0: 			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler);
sl@0: 			}
sl@0: 
sl@0: 		CleanupStack::PushL( request );
sl@0: 
sl@0: 		StoreRequestL(request);  // transfers ownership
sl@0: 		CleanupStack::Pop(); // request
sl@0: 
sl@0: 		User::LeaveIfError(iFile->Seek(ESeekStart, aPosition));		
sl@0: 		iFile->Write(request->BufferDes(), aLength, request->iStatus);
sl@0: 		iFileSize = -1; //reset cached size
sl@0: 
sl@0: 		request->SetActive();
sl@0: 		}
sl@0: 	else // if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 		{
sl@0: 		//write bitmap to file
sl@0: 		User::Leave(KErrNotSupported);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Empties aBuffer into iFile at the specified location.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The data buffer containing bytes to be written.
sl@0: @param  aPosition
sl@0:         The offset into file at which to start writing.
sl@0: @param  aSupplier
sl@0:         The data source to be notified when the write has been completed.
sl@0: 
sl@0: @leave  KErrNotReady 
sl@0:         SinkPrimeL() and SinkThreadLogon() have not been called.
sl@0: @leave  KErrArgument 
sl@0:         aSupplier is NULL.
sl@0: @leave  KErrNotSupported 
sl@0:         The aBuffer is not of type KMMFDataBuffer.
sl@0: */
sl@0: void CMMFFile::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier)
sl@0: 	{
sl@0: 	// Requires that iFile is open for write.
sl@0: 	// Writes data from iFile into aBuffer
sl@0: 	if ((aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		TUint requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().Length();
sl@0: 
sl@0: 		WriteBufferL(requestSize, aBuffer, aPosition, aSupplier);
sl@0: 		}
sl@0: 	else  // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		//write bitmap to file
sl@0: 		User::Leave( KErrNotSupported ) ;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Empties aBuffer into iFile at specified location.  Note that this is a synchronous write.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The data buffer containing bytes to be written.
sl@0: @param  aPosition
sl@0:         The offset into file at which to start writing.
sl@0: 
sl@0: @return The error code from RFile.
sl@0: */
sl@0: void CMMFFile::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition ) 
sl@0: 	{
sl@0: 	if ((aPosition<0) || (aBuffer == NULL))
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	if (!iFile)
sl@0: 		User::Leave(KErrNotReady);
sl@0: 
sl@0: 	TInt err(KErrNone) ;
sl@0: 
sl@0: 	//check whether buffer is safe to send to file server
sl@0: 	//if not, eg for a transfer buffer, then it needs to be copied
sl@0: 	if ((!CMMFBuffer::IsFileServerSafe(aBuffer->Type()))
sl@0: 		&& (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())))
sl@0: 		{
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		//NB: failure in this method will NOT cause transBufCopy to leak as it will be 
sl@0: 		//inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL.
sl@0: 		CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength());
sl@0: 
sl@0: 		transBufCopy->Des().Copy(aBufferDes);
sl@0: 		err = iFile->Seek(ESeekStart, aPosition);
sl@0: 		if (err==KErrNone)
sl@0: 			err = iFile->Write(transBufCopy->Des(),transBufCopy->Des().Length()); 
sl@0: 		iFileSize = -1; //reset cached size
sl@0: 		}
sl@0: 	else if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data();
sl@0: 
sl@0: 		err = iFile->Seek(ESeekStart, aPosition);
sl@0: 		if (err==KErrNone)
sl@0: 			err = iFile->Write(aBufferDes, aBufferDes.Length()); 
sl@0: 		iFileSize = -1; //reset cached size
sl@0: 		}
sl@0: 	else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
sl@0: 		{
sl@0: 		User::Leave(KErrNotSupported);
sl@0: 		}
sl@0: 
sl@0: 	User::LeaveIfError(err);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Gets the number of free bytes in the device's file system.
sl@0: 
sl@0: @return The number of free bytes.
sl@0: */
sl@0: TInt64 CMMFFile::BytesFree()
sl@0: 	{
sl@0: 	TInt driveNumber = KDefaultDrive;
sl@0: 	
sl@0: 	if (FileDrive().Length() > 0)
sl@0:  		{
sl@0:  		TChar driveLetter = FileDrive()[0];
sl@0:  		RFs::CharToDrive(driveLetter, driveNumber);
sl@0:  		}
sl@0: 	
sl@0: 	TVolumeInfo volInfo;
sl@0: 	if (iFsSession.Volume(volInfo, driveNumber) == KErrNone)
sl@0: 		{
sl@0: 		return volInfo.iFree;
sl@0: 		}
sl@0: 	return TInt64(0);
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Returns the size of the file in bytes.
sl@0: 
sl@0: Note: This is not the maximum length.
sl@0: 
sl@0: @return The size of the file in bytes.
sl@0: */
sl@0: TInt CMMFFile::Size()
sl@0: 	{
sl@0: 	TInt size = 0;
sl@0: 	TInt err = KErrNone;
sl@0: 	TBool fileOpened = EFalse;
sl@0: 
sl@0: 	if(iFileSize != -1)
sl@0: 		return iFileSize;
sl@0: 
sl@0: 	if (!iFile)
sl@0: 		{
sl@0: 		// Open the file. We only need read access, so SourcePrimeL will open the file with read flag
sl@0: 		TRAP(err, SourcePrimeL());
sl@0: 		if (iFile)
sl@0: 			fileOpened = ETrue;
sl@0: 		}
sl@0: 	if (err == KErrNone)
sl@0: 	    {
sl@0: 	    __ASSERT_DEBUG(iFile != NULL,Panic(EMMFFileHandleNULL));
sl@0: 		err = iFile->Size(size);
sl@0: 	    }
sl@0: 	if (err)
sl@0: 		{
sl@0: 		size = 0;
sl@0: 		iFileSize = -1; //reset cached size
sl@0: 		}
sl@0: 	else 
sl@0: 		iFileSize = size; //cache the filesize
sl@0: 
sl@0: 	if (fileOpened)
sl@0: 		{
sl@0: 		__ASSERT_DEBUG(iFile != NULL,Panic(EMMFFileHandleNULL));
sl@0: 		delete iFile;
sl@0: 		iFile = NULL;
sl@0: 		iFileSize = -1;
sl@0: 		}
sl@0: 
sl@0: 	return size;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Source thread logon.
sl@0: 
sl@0: Shares fsSession between threads
sl@0: 
sl@0: @param  aEventHandler
sl@0:         This is an MAsyncEventHandler to handle asynchronous events that occur during the
sl@0:         transfer of multimedia data.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::SourceThreadLogon(MAsyncEventHandler& aEventHandler)
sl@0: 	{
sl@0: 	iEventHandler = &aEventHandler;
sl@0: 	if(!iMmfFileEventHandler)
sl@0: 		{
sl@0: 		iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this);
sl@0: 		if(!iMmfFileEventHandler)
sl@0: 			return KErrNoMemory;
sl@0: 		}
sl@0: #ifdef __IPC_V2_PRESENT__
sl@0: 	return KErrNone; // nothing to do
sl@0: #else
sl@0: 	return iFsSession.Attach();
sl@0: #endif // __HIDE_IPC_V1__
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Logs off source thread.
sl@0: */
sl@0: void CMMFFile::SourceThreadLogoff()
sl@0: 	{
sl@0: 	delete iMmfFileEventHandler;
sl@0: 	iMmfFileEventHandler = NULL;
sl@0: 	iEventHandler = NULL;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /**
sl@0: Sink thread logon.
sl@0: 
sl@0: Shares fsSession between threads.
sl@0: 
sl@0: @param  aEventHandler
sl@0:         This is an MAsyncEventHandler to handle asynchronous events that occur during the
sl@0:         transfer of multimedia data.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::SinkThreadLogon(MAsyncEventHandler& aEventHandler)
sl@0: 	{
sl@0: 	iEventHandler = &aEventHandler;
sl@0: 	if(!iMmfFileEventHandler)
sl@0: 		{
sl@0: 		iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this);
sl@0: 		if(!iMmfFileEventHandler)
sl@0: 			return KErrNoMemory;
sl@0: 		}
sl@0: #ifdef __IPC_V2_PRESENT__
sl@0: 	return KErrNone;
sl@0: #else
sl@0: 	return iFsSession.Attach();
sl@0: #endif // __HIDE_IPC_V1__
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: Sink thread log off.
sl@0: */
sl@0: void CMMFFile::SinkThreadLogoff() 
sl@0: 	{
sl@0: 	delete iMmfFileEventHandler;
sl@0: 	iMmfFileEventHandler = NULL;
sl@0: 	iEventHandler = NULL;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Stores a request in an array.
sl@0: 
sl@0: CReadWriteRequests are stored in the array iRequests.
sl@0: This function takes ownership and places the request in the array.
sl@0: It also checks the array for completed requests and removes them.
sl@0: 
sl@0: @param  aRequest
sl@0:         The request to store.
sl@0: */
sl@0: void CMMFFile::StoreRequestL( CReadWriteRequest* aRequest )
sl@0: 	{
sl@0: 	// add aRequest to iRequests
sl@0: 	User::LeaveIfError( iRequests.Append( aRequest ) ) ;
sl@0: 
sl@0: 	// Clear out any completed requests
sl@0: 	for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ )
sl@0: 		{
sl@0: 		if (iRequests[ii]->Completed())
sl@0: 			{
sl@0: 			CReadWriteRequest* request = iRequests[ii];
sl@0: 			delete request;
sl@0: 
sl@0: 			iRequests.Remove(ii);
sl@0: 			ii--;
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /**
sl@0: Cancels outstanding requests.
sl@0: 
sl@0: CReadWriteRequests are stored in the array iRequests.
sl@0: This function cancels any outstanding requests and removes them
sl@0: from iRequests.
sl@0: */
sl@0: void CMMFFile::CancelRequests()
sl@0: 	{
sl@0: 	// Clear out any completed requests
sl@0: 	for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ )
sl@0: 		{
sl@0: 		CReadWriteRequest* request = iRequests[ii];
sl@0: 		delete request;
sl@0: 		iRequests.Remove(ii);
sl@0: 		ii--;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: /**
sl@0: Returns the data type as a fourCC code of CMMFFile as a data source.
sl@0: 
sl@0: @return The data type fourCC code.
sl@0: */
sl@0: TFourCC CMMFFile::SourceDataTypeCode(TMediaId /*aMediaId*/) 
sl@0: 	{
sl@0: 	return  iSourceFourCC ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns the data type as a fourCC code of CMMFFile as a data sink.
sl@0: 
sl@0: @return The data type fourCC code
sl@0: */
sl@0: TFourCC CMMFFile::SinkDataTypeCode(TMediaId /*aMediaId*/) 
sl@0: 	{
sl@0: 	return  iSinkFourCC ;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /**
sl@0: CMMFFile as a source is always passive so this function is not supported.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The emptied buffer.
sl@0: */
sl@0: void CMMFFile::BufferEmptiedL(CMMFBuffer* /* aBuffer */)
sl@0: 	{
sl@0: 	Panic(EMMFFilePanicBufferEmptiedLNotSupported);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Tests whether a source buffer can be created.
sl@0: 
sl@0: @return	A boolean indicating if if CMMFFile can create its own buffer. EFalse if CMMFFile cannot 
sl@0:         create it's own buffer.
sl@0: */
sl@0: TBool CMMFFile::CanCreateSourceBuffer()
sl@0: 	{
sl@0: 	return EFalse ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Creates a source buffer.
sl@0: 
sl@0: @param  aMediaId
sl@0:         The Media ID.
sl@0: @param  aReference
sl@0:         A boolean indicating if MDataSource owns the buffer. ETrue if it does, EFalse if the caller
sl@0:         owns the buffer.
sl@0: 
sl@0: @return	NULL as a CMMFFile cannot create it's own buffer
sl@0: */
sl@0: CMMFBuffer* CMMFFile::CreateSourceBufferL( TMediaId /*aMediaId*/ , TBool& /*aReference*/)
sl@0: 	{
sl@0: 	User::Leave(KErrNotSupported);
sl@0: 	return NULL ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: CMMFFile as a sink is always passive so this function is not supported.
sl@0: 
sl@0: @param  aBuffer
sl@0:         The buffer.
sl@0: */
sl@0: void CMMFFile::BufferFilledL(CMMFBuffer* /* aBuffer */)
sl@0: 	{
sl@0: 	Panic(EMMFFilePanicBufferFilledLNotSupported);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Tests whether a sink buffer can be created.
sl@0: 
sl@0: @return	A boolean indicating if the sink buffer can be created. EFalse if CMMFFile cannot create 
sl@0:         it's own buffer
sl@0: */
sl@0: TBool CMMFFile::CanCreateSinkBuffer() 
sl@0: 	{
sl@0: 	return EFalse ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Creates a sink buffer.
sl@0: 
sl@0: @param  aMediaId
sl@0:         The Media ID.
sl@0: @param  aReference 
sl@0:         A boolean indicating if MDataSource owns the buffer. ETrue if MDataSource owns the buffer,
sl@0:         EFalse if the caller owns the buffer.
sl@0: 
sl@0: @return	NULL as a CMMFFile cannot create it's own buffer
sl@0: */
sl@0: CMMFBuffer* CMMFFile::CreateSinkBufferL(TMediaId /*aMediaId*/ , TBool& /*aReference*/) 
sl@0: 	{
sl@0: 	User::Leave(KErrNotSupported);
sl@0: 	return NULL ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Primes the source.
sl@0: 
sl@0: When used as a source, the file prime opens the file as read only.
sl@0: */
sl@0: void CMMFFile::SourcePrimeL()
sl@0: 	{
sl@0: 	// don't reopen file if already open
sl@0: 	if (!iFile)
sl@0: 		{
sl@0: 		if (iFileHandle)
sl@0: 			{
sl@0: 			iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			// Open for read-only access
sl@0: 			iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareReadersOnly, iCAFParameters->iEnableUI);
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Primes the sink.
sl@0: 
sl@0: When used as a sink, the file prime opens the file for read/write access.
sl@0: */
sl@0: void CMMFFile::SinkPrimeL() 
sl@0: 	{
sl@0: 	// don't reopen file if already open
sl@0: 	if (!iFile)
sl@0: 		{
sl@0: 		if (iFileHandle)
sl@0: 			iFile = CF32File::NewL(iHandle);
sl@0: 		else
sl@0: 			iFile = CF32File::NewL(iFsSession, iFullFileName, EFileRead | EFileWrite);
sl@0: 		}
sl@0: 		iSinkNotStopped = ETrue;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Stops the file source. When stopping close the file. If the source is a file handle, the position is reset, but the 
sl@0: file handle remains open.
sl@0: */
sl@0: void CMMFFile::SourceStopL()
sl@0: 	{
sl@0: 	TInt pos = 0;
sl@0: 
sl@0: 	CancelRequests();
sl@0: 	
sl@0: 	// It is possible the file could have disappeared at this point (MMC/SD Card)
sl@0: 	//
sl@0: 	if (!iFile)
sl@0: 		{
sl@0: 		iPosition=pos;
sl@0: 		return;
sl@0: 		}
sl@0: 
sl@0: 	if (!iFileHandle && !iFile->IsProtected())
sl@0: 		{
sl@0: 		delete iFile;
sl@0: 		iFile = NULL;
sl@0: 		iFileSize = -1;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		User::LeaveIfError(iFile->Seek(ESeekStart, pos));
sl@0: 		}
sl@0: 	iPosition=pos;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Stops the file sink. 
sl@0: 
sl@0: When stopping close the file. When the file sink is a file handle, the position is reset, but the file handle
sl@0: remains open
sl@0: */
sl@0: void CMMFFile::SinkStopL()
sl@0: 	{
sl@0: 	iFileSize = -1;
sl@0: 	iPosition=0;
sl@0: 
sl@0: 	CancelRequests();
sl@0: 	iSinkNotStopped = EFalse;
sl@0: 	if (!iFileHandle)
sl@0: 		{		
sl@0: 		delete iFile;
sl@0: 		iFile = NULL;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		TInt pos = 0;
sl@0: 		User::LeaveIfError(iFile->Seek(ESeekStart, pos));
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Pauses the file source
sl@0: */
sl@0: void CMMFFile::SourcePauseL()
sl@0: 	{
sl@0: 	CancelRequests();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns a boolean indicating if the sink has been stopped.
sl@0: 
sl@0: @return A boolean indicating if the sink has stopped.
sl@0:  */
sl@0: TBool CMMFFile::SinkStopped()
sl@0: 	{
sl@0: 	if(iSinkNotStopped == EFalse)
sl@0: 		return ETrue;
sl@0: 	else
sl@0: 		return EFalse;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Evaluates a given intent against the rights associated with the file.
sl@0: 
sl@0: The rights are not updated by this function call.
sl@0: 
sl@0: @param  aIntent
sl@0:         The intent to evaluate.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::EvaluateIntent(ContentAccess::TIntent aIntent) const
sl@0: 	{
sl@0: 	if (iFile==NULL)
sl@0: 		{
sl@0: 		return KErrNotReady;
sl@0: 		}
sl@0: 
sl@0: 	return iFile->EvaluateIntent(aIntent);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Evaluates and executes a given intent against the rights associated with the file.
sl@0: 
sl@0: The rights object is updated after calling this function.
sl@0: 
sl@0: @param  aIntent
sl@0:         The intent to evaluate.
sl@0: 
sl@0: @return An error code indicating if the function call was successful. KErrNone on success, otherwise
sl@0:         another of the system-wide error codes.
sl@0: */
sl@0: TInt CMMFFile::ExecuteIntent(ContentAccess::TIntent aIntent)
sl@0: 	{
sl@0: 	if (iFile==NULL)
sl@0: 		{
sl@0: 		return KErrNotReady;
sl@0: 		}
sl@0: 
sl@0: 	return iFile->ExecuteIntent(aIntent);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns whether the file is protected.
sl@0: 
sl@0: @return A boolean indicating if the file is protected. ETrue if the file is protected.
sl@0: */
sl@0: TBool CMMFFile::IsProtectedL() const
sl@0: 	{
sl@0: 	if (iFile==NULL)
sl@0: 		{
sl@0: 		User::Leave(KErrNotReady);
sl@0: 		}
sl@0: 
sl@0: 	return iFile->IsProtected();
sl@0: 	}
sl@0: 
sl@0: TInt CMMFFile::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue)
sl@0: 	{
sl@0: 	if (iFile==NULL)
sl@0: 		{
sl@0: 		return KErrNotReady;
sl@0: 		}
sl@0: 
sl@0: 	return iFile->SetAgentProperty(aProperty, aValue);
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *	Returns ETrue if the request can safely be deleted.
sl@0:  */
sl@0: TBool CReadWriteRequest::Completed() 
sl@0: 	{
sl@0: 	return iCompleted ;
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *	Returns the data member of CMMFDataBuffer or CMMFTransferBuffer (as TPtr8)
sl@0:  *  
sl@0:  */
sl@0: TDes8& CReadWriteRequest::BufferDes()
sl@0: 	{
sl@0: 	if(iTransferBufferCopy)
sl@0: 		return iTransferBufferCopy->Des();
sl@0: 	else
sl@0: 		{
sl@0: 		//reset iBufferDes in case iBuffer has changed...
sl@0: 		iBufferDes = &(STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data());
sl@0: 		return *iBufferDes;
sl@0: 		}
sl@0: 	}
sl@0: 	
sl@0: const TDesC8& CReadWriteRequest::BufferDesC()
sl@0: 	{
sl@0: 	if(iTransferBufferCopy)
sl@0: 		return iTransferBufferCopy->Des();
sl@0: 	else
sl@0: 		return BufferDes();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /*
sl@0:  *	Destructor.
sl@0:  */
sl@0: CReadWriteRequest::~CReadWriteRequest() 
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	if(iTransferBufferCopy)
sl@0: 		iTransferBufferCopy->SetInUse(EFalse);
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *	Allows owning class access to SetActive()
sl@0:  */
sl@0: void CReadWriteRequest::SetActive() 
sl@0: 	{
sl@0: 	CActive::SetActive() ;
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *  For the moment at least...    Canceled requests may be deleted
sl@0:  */
sl@0: void CReadWriteRequest::DoCancel() 
sl@0: 	{
sl@0: 	iCompleted = ETrue ;
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *	Called when errors in RunL force Leave.  For the moment just mark the request deletable
sl@0:  */
sl@0: TInt CReadWriteRequest::RunError( TInt aError ) 
sl@0: 	{
sl@0: 	//RunL can leave.
sl@0: 	iCompleted = ETrue ;
sl@0: 	iError = aError; //keep this error internally for now
sl@0: 	return KErrNone ;
sl@0: 	}
sl@0: 
sl@0: /*
sl@0:  *	On completion of read request call back to the MDataSink
sl@0:  */
sl@0: void CReadRequest::RunL() 
sl@0: 	{
sl@0: 	if (iStatus != KErrNone)
sl@0: 		{
sl@0: 		TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int());
sl@0: 		iEventHandler->SendEventToClient(event);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		//Copy the data from the normal buffer into the Transfer buffer
sl@0: 		if(iTransferBufferCopy)
sl@0: 			{
sl@0: 			//must specify the size here as the dest may be smaller than the source.
sl@0: 			TDes8& destDesc = STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data();
sl@0: 			destDesc.Copy(iTransferBufferCopy->Des().Left(destDesc.MaxLength()));
sl@0: 
sl@0: 			iTransferBufferCopy->SetInUse(EFalse);
sl@0: 			}
sl@0: 
sl@0: 		// removed checking EOF from here, it should be checked in CMMFFile
sl@0: 
sl@0: 		REINTERPRET_CAST(MDataSink*, iSinkOrSource)->BufferFilledL(iBuffer) ; // callback to MDataSource/Sink
sl@0: 		}
sl@0: 	
sl@0: 	iCompleted = ETrue ;
sl@0: 	}
sl@0: 
sl@0: /* 
sl@0:  *  On completion of write request call back to the MDataSource
sl@0:  */
sl@0: void CWriteRequest::RunL() 
sl@0: 	{
sl@0: 	if(iTransferBufferCopy)
sl@0: 		iTransferBufferCopy->SetInUse(EFalse);
sl@0: 
sl@0: 	if (iStatus != KErrNone)
sl@0: 		{
sl@0: 		TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int());
sl@0: 		iEventHandler->SendEventToClient(event);
sl@0: 		}
sl@0: 	else
sl@0: 		REINTERPRET_CAST(MDataSource*, iSinkOrSource)->BufferEmptiedL(iBuffer) ; // callback to MDataSource/Sink
sl@0: 
sl@0: 	iCompleted = ETrue ;
sl@0: 	}
sl@0: 
sl@0: CMMFFile::CMMFFileAsyncEventHandler::CMMFFileAsyncEventHandler(CMMFFile* aParent)
sl@0: 	{
sl@0: 	iParent = aParent;
sl@0: 	}
sl@0: 
sl@0: CMMFFile::CMMFFileAsyncEventHandler::~CMMFFileAsyncEventHandler()
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: TInt CMMFFile::CMMFFileAsyncEventHandler::SendEventToClient(const TMMFEvent& aEvent)
sl@0: 	{
sl@0: 	if(aEvent.iErrorCode == KErrNotReady)//i.e. MMC removed while recording
sl@0: 		{
sl@0: 		TRAPD(err, iParent->SinkStopL() );
sl@0: 		if (err != KErrNone)
sl@0: 			{
sl@0: 			return err;	
sl@0: 			}
sl@0: 		}
sl@0: 	return iParent->iEventHandler->SendEventToClient(aEvent);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns access to internal CData property
sl@0: 
sl@0: @param aData
sl@0:        On return, set to the internal CData property used to access file for reading.
sl@0: 
sl@0: Returns:
sl@0:   * KErrNotReady if the file is not open/data object has not been created. 
sl@0:   * KErrNotSupported if not supported (e.g. on data sink)
sl@0: 
sl@0: @return Standard error code
sl@0: */
sl@0: TInt CMMFFile::Data(ContentAccess::CData*& aData)
sl@0: 	{
sl@0: 	if (!iFile)
sl@0: 		{
sl@0: 		return KErrNotReady;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		return iFile->Data(aData);
sl@0: 		}
sl@0: 	}
sl@0: