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 sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include 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(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 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 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 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 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 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: