|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <f32file.h> |
|
17 #include <e32std.h> |
|
18 #include <mmf/server/mmfdatabuffer.h> |
|
19 #include <mmf/common/mmfutilities.h> |
|
20 #include <mmf/common/mmfcontroller.h> |
|
21 #include <mmf/common/mmfpaniccodes.h> |
|
22 #include <mmf/server/MmfFile.h> |
|
23 #include "MmffilePriv.h" |
|
24 #include "FileAccess.h" |
|
25 |
|
26 void Panic(TMMFFilePanicCode aPanicCode) |
|
27 { |
|
28 _LIT(KMMFFilePanicCategory, "MMFFile"); |
|
29 User::Panic(KMMFFilePanicCategory, aPanicCode); |
|
30 } |
|
31 |
|
32 /** |
|
33 * Constructs a CTransferBufferCopy |
|
34 * |
|
35 * @return CTransferBufferCopy* |
|
36 */ |
|
37 CTransferBufferCopy* CTransferBufferCopy::NewL(TInt aMaxLength) |
|
38 { |
|
39 CTransferBufferCopy* self = new (ELeave) CTransferBufferCopy(aMaxLength); |
|
40 CleanupStack::PushL(self); |
|
41 self->ConstructL(); |
|
42 CleanupStack::Pop(self); |
|
43 return self; |
|
44 } |
|
45 |
|
46 /** |
|
47 * Second phase constructor for CTransferBufferCopy |
|
48 * |
|
49 * @return void |
|
50 */ |
|
51 void CTransferBufferCopy::ConstructL() |
|
52 { |
|
53 iBuffer = static_cast<TUint8*>(User::AllocL(iMaxLength)); |
|
54 iBufferDes.Set(iBuffer,0,iMaxLength); |
|
55 } |
|
56 |
|
57 /** |
|
58 Destructor. |
|
59 */ |
|
60 CMMFFile::~CMMFFile() |
|
61 { |
|
62 delete iFile; |
|
63 |
|
64 |
|
65 iHandle.Close(); |
|
66 iFsSession.Close(); |
|
67 delete iFileName; |
|
68 delete iFileExt; |
|
69 delete iFilePath; |
|
70 delete iFileDrive; |
|
71 delete iMmfFileEventHandler; |
|
72 delete iCAFParameters; |
|
73 |
|
74 // Get rid of everything in RArray's & close them. |
|
75 iRequests.ResetAndDestroy(); |
|
76 iTransferBufferCopies.ResetAndDestroy(); |
|
77 } |
|
78 |
|
79 /** |
|
80 Protected constructor. |
|
81 |
|
82 The default implementation is empty. |
|
83 */ |
|
84 CMMFFile::CMMFFile() : CMMFClip( KUidMmfFileSource, KUidMmfFileSink ), iFileSize(-1) |
|
85 { |
|
86 iSinkNotStopped = EFalse; |
|
87 } |
|
88 |
|
89 /** |
|
90 Constructs an CMMFFile MDataSource. |
|
91 |
|
92 @return A pointer to the new CMMFFile data source. |
|
93 */ |
|
94 MDataSource* CMMFFile::NewSourceL() |
|
95 { |
|
96 CMMFFile* self = new (ELeave) CMMFFile ; |
|
97 return STATIC_CAST( MDataSource*, self ) ; |
|
98 } |
|
99 |
|
100 /** |
|
101 Constructs a CMMFFile MDataSink |
|
102 |
|
103 @return A pointer to the new CMMFFile data sink. |
|
104 */ |
|
105 MDataSink* CMMFFile::NewSinkL() |
|
106 { |
|
107 CMMFFile* self = new (ELeave) CMMFFile ; |
|
108 return STATIC_CAST( MDataSink*, self ) ; |
|
109 } |
|
110 |
|
111 /** |
|
112 Perform source construction dependant on the source construction |
|
113 initialisation data aInitData. |
|
114 |
|
115 @param aInitData |
|
116 The TPckg<TMMFFileParams> descriptor package containing the file name and full path. |
|
117 */ |
|
118 void CMMFFile::ConstructSourceL(const TDesC8& aInitData ) |
|
119 { |
|
120 ConstructL(aInitData, ESourceMode); |
|
121 } |
|
122 |
|
123 /** |
|
124 Performs sink construction dependant on the sink construction |
|
125 initialisation data aInitData. |
|
126 |
|
127 @param aInitData |
|
128 The TPckg<TMMFFileParams> descriptor package containing the file name and full path. |
|
129 */ |
|
130 void CMMFFile::ConstructSinkL(const TDesC8& aInitData) |
|
131 { |
|
132 ConstructL(aInitData, ESinkMode); |
|
133 } |
|
134 |
|
135 /** |
|
136 Protected constructor. |
|
137 |
|
138 Extracts the initialisation data provided by the calling functions: ConstructSourceL() and |
|
139 ConstructSinkL(). Creates a file server session and sets up file name. If there is a file name and |
|
140 it cannot be found this function leaves. If there is no file name the function leaves. Does not |
|
141 attempt to open the file or check whether the file exists. |
|
142 |
|
143 If aInitData contains a TMMFFileHandleParams instead of TMMFFileParams, the source/sink is constructed from |
|
144 the file handle provided by the caller |
|
145 |
|
146 @param aInitData |
|
147 Initialisation data packaged in a TMMFFileParams or in a TMMFFileHandleParams (File Handle) |
|
148 */ |
|
149 void CMMFFile::ConstructL(const TDesC8& aInitData,TMMFileMode aFileMode) |
|
150 { |
|
151 User::LeaveIfError(iFsSession.Connect()); |
|
152 #ifdef __IPC_V2_PRESENT__ |
|
153 // on IPCv2 we auto attach |
|
154 User::LeaveIfError(iFsSession.ShareAuto()); |
|
155 #else |
|
156 // on IPCv1 we use explicit - more efficient |
|
157 User::LeaveIfError(iFsSession.Share(RSessionBase::EExplicitAttach)); |
|
158 #endif |
|
159 |
|
160 User::LeaveIfError(iFsSession.ShareProtected()); |
|
161 |
|
162 HBufC* filename = NULL; |
|
163 |
|
164 iCAFParameters = new (ELeave) CCAFParameters; |
|
165 TBool drmContent = EFalse; |
|
166 RDesReadStream stream(aInitData); |
|
167 CleanupClosePushL(stream); |
|
168 |
|
169 TUid initUid = TUid::Uid(stream.ReadInt32L()); |
|
170 |
|
171 if (initUid == KMMFileHandleSourceUid) |
|
172 { |
|
173 TPckgBuf<RFile*> fileptr; |
|
174 stream.ReadL(fileptr); |
|
175 |
|
176 iHandle.Duplicate(*fileptr()); |
|
177 |
|
178 TInt length = stream.ReadInt32L(); |
|
179 if (length>0) |
|
180 { |
|
181 iCAFParameters->iUniqueId = HBufC::NewL(length); |
|
182 TPtr16 ptr = iCAFParameters->iUniqueId->Des(); |
|
183 stream.ReadL(ptr, length); |
|
184 } |
|
185 iFileHandle = ETrue; |
|
186 |
|
187 filename = HBufC::NewMaxLC(KMaxFileName); |
|
188 TPtr ptr = filename->Des(); |
|
189 User::LeaveIfError(iHandle.FullName(ptr)); |
|
190 drmContent = ETrue; |
|
191 |
|
192 iCAFParameters->iEnableUI = stream.ReadInt32L(); |
|
193 } |
|
194 |
|
195 else if (initUid == KMMFileSourceUid) |
|
196 { |
|
197 TInt length = stream.ReadInt32L(); |
|
198 filename = HBufC::NewMaxLC(length); |
|
199 TPtr ptr = filename->Des(); |
|
200 stream.ReadL(ptr, length); |
|
201 |
|
202 length = stream.ReadInt32L(); |
|
203 if (length>0) |
|
204 { |
|
205 iCAFParameters->iUniqueId = HBufC::NewMaxL(length); |
|
206 ptr.Set(iCAFParameters->iUniqueId->Des()); |
|
207 stream.ReadL(ptr, length); |
|
208 } |
|
209 drmContent = ETrue; |
|
210 iCAFParameters->iEnableUI = stream.ReadInt32L(); |
|
211 } |
|
212 else |
|
213 { |
|
214 // TODO If the UID is unknown we should reject, but currently |
|
215 // code also used for older calls that just supply filename. |
|
216 // User::Leave(KErrNotSupported); |
|
217 } |
|
218 |
|
219 if ((filename == NULL) && aInitData.Length() == sizeof(TMMFFileHandleParams)) |
|
220 { |
|
221 TMMFFileHandleParams params; |
|
222 TPckgC<TMMFFileHandleParams> config(params); |
|
223 config.Set(aInitData); |
|
224 params = config(); |
|
225 |
|
226 |
|
227 if (params.iUid == KFileHandleUid) |
|
228 { |
|
229 User::LeaveIfError(iHandle.Duplicate(*params.iFile)); |
|
230 TInt pos = 0; |
|
231 // make sure the duplicate handle is at the start of the file - the usage of the file handle really requires this |
|
232 User::LeaveIfError(iHandle.Seek(ESeekStart, pos)); |
|
233 iFileHandle = ETrue; |
|
234 ASSERT(filename == NULL); |
|
235 filename = HBufC::NewMaxLC(KMaxFileName); |
|
236 TPtr ptr = filename->Des(); |
|
237 User::LeaveIfError(iHandle.FullName(ptr)); |
|
238 } |
|
239 } |
|
240 |
|
241 if (filename == NULL) // do old case as last resort |
|
242 { |
|
243 TMMFFileParams params; |
|
244 TPckgC<TMMFFileParams> config(params); |
|
245 config.Set(aInitData); |
|
246 params = config(); |
|
247 |
|
248 filename = params.iPath.AllocLC(); |
|
249 } |
|
250 |
|
251 ASSERT(filename != NULL); |
|
252 |
|
253 TParse parser ; |
|
254 User::LeaveIfError(parser.Set(*filename, NULL, NULL)); |
|
255 CleanupStack::PopAndDestroy(2, &stream); //filename, stream |
|
256 if ( !( parser.NamePresent() ) && !( parser.ExtPresent() ) ) |
|
257 { |
|
258 User::Leave( KErrBadName ) ; |
|
259 } |
|
260 |
|
261 iFullFileName.Copy( parser.FullName() ) ; |
|
262 iFileName = parser.Name().AllocL() ; |
|
263 iFileExt = parser.Ext().AllocL() ; |
|
264 iFilePath = parser.Path().AllocL() ; |
|
265 iFileDrive = parser.Drive().AllocL() ; |
|
266 |
|
267 // in order to simulate old behaviour we are not passing error out |
|
268 // but will try to create Content again during PrimeL() |
|
269 if (drmContent && aFileMode==ESourceMode) |
|
270 { |
|
271 TInt contentError; |
|
272 if (iFileHandle) |
|
273 { |
|
274 TRAP(contentError, |
|
275 iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI); |
|
276 ); |
|
277 } |
|
278 else |
|
279 { |
|
280 // Open for read-only access |
|
281 TRAP(contentError, |
|
282 iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareReadersOnly, iCAFParameters->iEnableUI); |
|
283 ); |
|
284 } |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 /** |
|
290 @deprecated - Replaced by CMMFFile::Data() |
|
291 |
|
292 Returns an RFile handle to the current file. |
|
293 |
|
294 If there is no current file, one is created. If the file exists then it is opened with read access |
|
295 if it is read only, write access otherwise. If the file does not exist then it is opened with |
|
296 write access. |
|
297 |
|
298 @leave KErrNotReady |
|
299 The file is not open. |
|
300 |
|
301 @return A handle to the current file. |
|
302 @see CMMFFile::Data() |
|
303 */ |
|
304 RFile& CMMFFile::FileL() |
|
305 { |
|
306 if (!iFile) |
|
307 User::Leave(KErrNotReady); |
|
308 if (iFileHandle) |
|
309 return iHandle; |
|
310 else |
|
311 return iFile->FileL(); |
|
312 } |
|
313 |
|
314 /** |
|
315 Returns the file name of the current file. |
|
316 |
|
317 Note: This will give the wrong answer if the file is renamed! |
|
318 |
|
319 @return The FileName (without extension). |
|
320 */ |
|
321 const TDesC& CMMFFile::FileName() const |
|
322 { |
|
323 return *iFileName ; |
|
324 } |
|
325 |
|
326 /** |
|
327 Returns the extension of the current file. |
|
328 |
|
329 Note: This will give the wrong answer if the file is renamed! |
|
330 |
|
331 @return The File Extension. |
|
332 */ |
|
333 const TDesC& CMMFFile::Extension() const |
|
334 { |
|
335 return *iFileExt ; |
|
336 } |
|
337 |
|
338 /** |
|
339 Returns the path of the current file. |
|
340 |
|
341 Note: This will give the wrong answer if the file is renamed! |
|
342 |
|
343 @return The FilePath (without filename and extension) |
|
344 */ |
|
345 const TDesC& CMMFFile::FilePath() const |
|
346 { |
|
347 return *iFilePath ; |
|
348 } |
|
349 |
|
350 /** |
|
351 Returns the drive on which the current file is located. |
|
352 |
|
353 Note: This will give the wrong answer if the file is renamed! |
|
354 |
|
355 @return The FileDrive (drive letter only, without path, filename and extension). |
|
356 */ |
|
357 const TDesC& CMMFFile::FileDrive() const |
|
358 { |
|
359 return *iFileDrive ; |
|
360 } |
|
361 |
|
362 /** |
|
363 Returns the full name of the current file. |
|
364 |
|
365 Note: This will give the wrong answer if the file is renamed! |
|
366 |
|
367 @return The file name (full filename including drive letter, without path, filename and extension). |
|
368 */ |
|
369 const TFileName CMMFFile::FullName() const |
|
370 { |
|
371 return iFullFileName; |
|
372 } |
|
373 |
|
374 /** |
|
375 Returns the uniqueID associated with this content. If no uniqueID has been provided, a null |
|
376 descriptor will be provided |
|
377 |
|
378 @return The UniqueID |
|
379 */ |
|
380 const TDesC& CMMFFile::UniqueId() const |
|
381 { |
|
382 if (iCAFParameters->iUniqueId) |
|
383 return *(iCAFParameters->iUniqueId); |
|
384 else |
|
385 return KNullDesC; |
|
386 } |
|
387 |
|
388 |
|
389 /** |
|
390 Deletes the file. |
|
391 |
|
392 Closes the currently open file, then deletes it. If the file source is accessing a file handle, |
|
393 the file is truncated to 0 bytes instead. |
|
394 |
|
395 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
396 another of the system-wide error codes. |
|
397 */ |
|
398 TInt CMMFFile::Delete() |
|
399 { |
|
400 TInt result = KErrNone; |
|
401 if (!iFileHandle) |
|
402 { |
|
403 delete iFile; |
|
404 iFile = NULL; |
|
405 iFileSize=-1; |
|
406 iPosition=0; |
|
407 |
|
408 result = iFsSession.Delete(iFullFileName); |
|
409 } |
|
410 else |
|
411 { |
|
412 iFileSize=-1; |
|
413 iPosition=0; |
|
414 |
|
415 if (iFile) |
|
416 { |
|
417 result = iFile->SetSize(0); |
|
418 } |
|
419 } |
|
420 |
|
421 return result; |
|
422 } |
|
423 |
|
424 /** |
|
425 Sets the file size. |
|
426 |
|
427 @param aSize |
|
428 The size of the file. |
|
429 |
|
430 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
431 another of the system-wide error codes. |
|
432 */ |
|
433 TInt CMMFFile::SetSize(TInt aSize) |
|
434 { |
|
435 if ( !iFile ) |
|
436 return KErrNotReady; |
|
437 TInt err = iFile->SetSize(aSize); |
|
438 if(err == KErrNone) |
|
439 iFileSize = aSize; |
|
440 else |
|
441 iFileSize = -1; |
|
442 |
|
443 return err; |
|
444 } |
|
445 |
|
446 /** |
|
447 Obtains a CTransferBufferCopy from iTransferBufferCopies that is |
|
448 at least as big as that required. |
|
449 |
|
450 There is no need to put the pointer returned by this method onto the CleanupStack |
|
451 as it will have already been placed into iTransferBufferCopies. |
|
452 |
|
453 @param aMaxLength |
|
454 The size required. |
|
455 |
|
456 @return A pointer to a valid CTransferBufferCopy. |
|
457 */ |
|
458 CTransferBufferCopy* CMMFFile::ObtainCopyOfTransferBufferL(TInt aMaxLength) |
|
459 { |
|
460 //find a free transfer buffer copy of the right size |
|
461 TInt firstFree = -1; |
|
462 CTransferBufferCopy* transBufCopyToUse = NULL; |
|
463 |
|
464 for(TInt cnt=0; cnt < iTransferBufferCopies.Count(); cnt++) |
|
465 { |
|
466 if(!iTransferBufferCopies[cnt]->InUse()) |
|
467 { |
|
468 //record the first free entry, we may remove this |
|
469 //if entries in iTransferBufferCopies > KAcceptableTransferBufferCopiesSize |
|
470 if(firstFree == -1) |
|
471 firstFree = cnt; |
|
472 |
|
473 if(iTransferBufferCopies[cnt]->MaxLength() >= aMaxLength) |
|
474 { |
|
475 transBufCopyToUse = iTransferBufferCopies[cnt]; |
|
476 |
|
477 //Set the MaxLength. This will ensure that the copy acts the same as |
|
478 //the original Transfer buffer, eg. file server will throw KErrOverflow |
|
479 transBufCopyToUse->ReUse(aMaxLength); |
|
480 break; |
|
481 } |
|
482 } |
|
483 } |
|
484 |
|
485 //If we failed to find a suitable entry, we need to create a new one |
|
486 if(!transBufCopyToUse) |
|
487 { |
|
488 //Firstly, should we re-cycle an existing entry? |
|
489 //There must be entries in the array, a free entry must have been found, |
|
490 //the size of the array must be beyond the water mark where we want to start |
|
491 //cycling free entries. |
|
492 if((iTransferBufferCopies.Count() > 0) && |
|
493 (firstFree != -1) && |
|
494 (iTransferBufferCopies.Count() > KAcceptableTransferBufferCopiesSize)) |
|
495 { |
|
496 delete iTransferBufferCopies[firstFree]; |
|
497 iTransferBufferCopies.Remove(firstFree); |
|
498 |
|
499 transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength); |
|
500 CleanupStack::PushL(transBufCopyToUse); |
|
501 User::LeaveIfError(iTransferBufferCopies.Insert(transBufCopyToUse,firstFree)); |
|
502 |
|
503 CleanupStack::Pop(); |
|
504 } |
|
505 else |
|
506 { |
|
507 #ifdef _DEBUG |
|
508 if(iTransferBufferCopies.Count() > KMaximumTransferBufferCopiesSize) |
|
509 { |
|
510 User::Panic(_L("iTransferBufferCopies grew too large in CMMFFile"),KErrTooBig); |
|
511 } |
|
512 #endif |
|
513 |
|
514 transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength); |
|
515 CleanupStack::PushL(transBufCopyToUse); |
|
516 User::LeaveIfError(iTransferBufferCopies.Append(transBufCopyToUse)); |
|
517 |
|
518 CleanupStack::Pop(); |
|
519 } |
|
520 } |
|
521 |
|
522 return transBufCopyToUse; |
|
523 } |
|
524 |
|
525 |
|
526 |
|
527 /** |
|
528 Loads aBuffer from iFile. |
|
529 |
|
530 The file must already be open for reading. File read is asynchronous. CReadRequest is created to |
|
531 respond to completion. |
|
532 |
|
533 @param aBuffer |
|
534 The buffer to be filled from the file. |
|
535 @param aConsumer |
|
536 The data sink consumer of the buffer. |
|
537 */ |
|
538 void CMMFFile::FillBufferL( CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId /*aMediaId*/ ) |
|
539 { |
|
540 // Requires that iFile is open for read. |
|
541 // Reads data from iFile into aBuffer |
|
542 if ((aConsumer == NULL) || (aBuffer == NULL)) |
|
543 User::Leave(KErrArgument); |
|
544 |
|
545 if (!iFile || (iMmfFileEventHandler == NULL)) |
|
546 User::Leave(KErrNotReady); |
|
547 |
|
548 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
549 { |
|
550 CTransferBufferCopy* transBufCopy = NULL; |
|
551 CReadRequest* request = NULL; |
|
552 |
|
553 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
554 |
|
555 TInt requestSize; |
|
556 if(aBuffer->RequestSize()) |
|
557 requestSize = aBuffer->RequestSize(); |
|
558 else |
|
559 requestSize = aBufferDes.MaxLength(); |
|
560 |
|
561 //check whether buffer is safe to send to file server |
|
562 //if not, eg for a transfer buffer, then it needs to be copied |
|
563 if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
564 { |
|
565 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
566 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
567 transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
568 request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, iPosition, Size(), iMmfFileEventHandler); |
|
569 } |
|
570 else |
|
571 { |
|
572 request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, iPosition, Size(), iMmfFileEventHandler); |
|
573 } |
|
574 |
|
575 CleanupStack::PushL( request ); |
|
576 |
|
577 StoreRequestL(request); // transfers ownership |
|
578 CleanupStack::Pop() ; // request |
|
579 |
|
580 iFile->Read(request->BufferDes(), requestSize, request->iStatus); |
|
581 iPosition += requestSize; |
|
582 |
|
583 if (iPosition >= iFileSize) |
|
584 { |
|
585 aBuffer->SetLastBuffer(ETrue); |
|
586 } |
|
587 |
|
588 request->SetActive(); |
|
589 } |
|
590 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
591 User::Leave( KErrNotSupported ) ; |
|
592 } |
|
593 |
|
594 /** |
|
595 Empties aBuffer into iFile. The file must be already open for writing. |
|
596 |
|
597 @param aBuffer |
|
598 The buffer to be written to the file. |
|
599 @param aSupplier |
|
600 The data source supplier of the buffer. |
|
601 */ |
|
602 void CMMFFile::EmptyBufferL( CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/ ) |
|
603 { |
|
604 // Requires that iFile is open for write. |
|
605 // Writes data from iFile into aBuffer |
|
606 if ((aSupplier == NULL) || (aBuffer == NULL)) |
|
607 User::Leave(KErrArgument); |
|
608 |
|
609 if (!iFile || (iMmfFileEventHandler == NULL)) |
|
610 User::Leave(KErrNotReady); |
|
611 |
|
612 CTransferBufferCopy* transBufCopy = NULL; |
|
613 |
|
614 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
615 { |
|
616 CWriteRequest* request = NULL; |
|
617 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
618 |
|
619 //check whether buffer is safe to send to file server |
|
620 //if not, eg for a transfer buffer, then it needs to be copied |
|
621 if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
622 { |
|
623 //Obtain a normal buffer to send to the file server |
|
624 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
625 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
626 transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
627 |
|
628 //Copy the data into the buffer we will send to the file server |
|
629 transBufCopy->Des().Copy(aBufferDes); |
|
630 |
|
631 request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler); |
|
632 } |
|
633 else |
|
634 { |
|
635 request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler); |
|
636 } |
|
637 |
|
638 CleanupStack::PushL( request ); |
|
639 |
|
640 StoreRequestL(request); // transfers ownership |
|
641 CleanupStack::Pop(); // request |
|
642 |
|
643 iFile->Write(request->BufferDes(), request->BufferDes().Length(), request->iStatus); |
|
644 request->SetActive(); |
|
645 } |
|
646 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
647 { |
|
648 User::Leave( KErrNotSupported ) ; |
|
649 } |
|
650 } |
|
651 |
|
652 /** |
|
653 Loads aLength number of bytes into aBuffer from specified point in iFile. |
|
654 |
|
655 @param aLength |
|
656 The number of bytes to be read into buffer. |
|
657 @param aBuffer |
|
658 The buffer to be filled from the file. |
|
659 @param aPosition |
|
660 The offset into the file at which to start reading. |
|
661 @param aConsumer |
|
662 The data sink consumer of the buffer. |
|
663 */ |
|
664 void CMMFFile::ReadBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer) |
|
665 { |
|
666 // Requires that iFile is open for read. |
|
667 // Reads data from iFile into aBuffer |
|
668 if ((aLength < 0) || (aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL)) |
|
669 User::Leave(KErrArgument); |
|
670 |
|
671 if (!iFile || (iMmfFileEventHandler == NULL)) |
|
672 User::Leave(KErrNotReady); |
|
673 |
|
674 CTransferBufferCopy* transBufCopy = NULL; |
|
675 |
|
676 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
677 { |
|
678 CReadRequest* request = NULL; |
|
679 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
680 |
|
681 //check whether buffer is safe to send to file server |
|
682 //if not, eg for a transfer buffer, then it needs to be copied |
|
683 if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
684 { |
|
685 //Obtain a normal buffer to send to the file server |
|
686 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
687 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
688 transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
689 |
|
690 request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, transBufCopy, aPosition, Size(), iMmfFileEventHandler); |
|
691 } |
|
692 else |
|
693 { |
|
694 request = new(ELeave) CReadRequest(STATIC_CAST(TAny*, aConsumer), aBuffer, aPosition, Size(), iMmfFileEventHandler); |
|
695 } |
|
696 |
|
697 CleanupStack::PushL( request ); |
|
698 |
|
699 StoreRequestL(request) ; //transfers ownership |
|
700 CleanupStack::Pop() ; //request |
|
701 |
|
702 TInt err = iFile->Read(aPosition, request->BufferDes(), aLength, request->iStatus); |
|
703 if (err == KErrCANotSupported) |
|
704 { |
|
705 err = KErrNone; |
|
706 if (aPosition != iPosition) |
|
707 { |
|
708 err = iFile->Seek(ESeekStart, aPosition); |
|
709 } |
|
710 if (err==KErrNone) |
|
711 { |
|
712 iFile->Read(request->BufferDes(), aLength, request->iStatus); |
|
713 } |
|
714 } |
|
715 |
|
716 if (err != KErrNone) |
|
717 { |
|
718 TRequestStatus* status = &request->iStatus; |
|
719 User::RequestComplete(status, err); |
|
720 } |
|
721 |
|
722 iPosition = aPosition + aLength; |
|
723 |
|
724 if (iPosition >= iFileSize) |
|
725 { |
|
726 aBuffer->SetLastBuffer(ETrue); |
|
727 } |
|
728 |
|
729 request->SetActive(); |
|
730 } |
|
731 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
732 User::Leave( KErrNotSupported ) ; |
|
733 } |
|
734 |
|
735 |
|
736 /** |
|
737 Loads aBuffer from specified point in iFile. |
|
738 |
|
739 The file must already be open for reading. |
|
740 |
|
741 @param aBuffer |
|
742 The buffer to be filled from the file. |
|
743 @param aPosition |
|
744 The offset into file at which to start reading. |
|
745 @param aConsumer |
|
746 The data sink consumer of the buffer. |
|
747 */ |
|
748 void CMMFFile::ReadBufferL(CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer) |
|
749 { |
|
750 // Requires that iFile is open for read. |
|
751 // Reads data from iFile into aBuffer |
|
752 if ((aPosition<0) || (aConsumer == NULL) || (aBuffer == NULL)) |
|
753 User::Leave(KErrArgument); |
|
754 |
|
755 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
756 { |
|
757 TInt requestSize; |
|
758 if(aBuffer->RequestSize()) |
|
759 requestSize = aBuffer->RequestSize(); |
|
760 else |
|
761 requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().MaxLength(); |
|
762 |
|
763 ReadBufferL(requestSize, aBuffer, aPosition, aConsumer); |
|
764 } |
|
765 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
766 User::Leave(KErrNotSupported); |
|
767 } |
|
768 |
|
769 |
|
770 /** |
|
771 Loads aBuffer from specified point in iFile. Note that this is a synchronous read. |
|
772 |
|
773 @param aBuffer |
|
774 The buffer to be filled from the file. |
|
775 @param aPosition |
|
776 The offset into file at which to start reading. |
|
777 */ |
|
778 void CMMFFile::ReadBufferL( CMMFBuffer* aBuffer, TInt aPosition) |
|
779 { |
|
780 // Requires that iFile is open for read. |
|
781 // Reads data from iFile into aBuffer |
|
782 if ((aPosition<0) || (aBuffer == NULL)) |
|
783 User::Leave(KErrArgument); |
|
784 |
|
785 if (!iFile) |
|
786 User::Leave(KErrNotReady); |
|
787 |
|
788 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
789 { |
|
790 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
791 |
|
792 TInt requestSize; |
|
793 if(aBuffer->RequestSize()) |
|
794 requestSize = aBuffer->RequestSize(); |
|
795 else |
|
796 requestSize = aBufferDes.MaxLength(); |
|
797 |
|
798 //check whether buffer is safe to send to file server |
|
799 //if not, eg for a transfer buffer, then it needs to be copied |
|
800 if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
801 { |
|
802 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
803 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
804 CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
805 |
|
806 User::LeaveIfError(iFile->Seek(ESeekStart, aPosition)); |
|
807 User::LeaveIfError(iFile->Read(transBufCopy->Des(), requestSize)); |
|
808 aBufferDes.Copy(transBufCopy->Des().Left(aBufferDes.MaxLength())); |
|
809 } |
|
810 else |
|
811 { |
|
812 User::LeaveIfError(iFile->Seek(ESeekStart, aPosition)); |
|
813 User::LeaveIfError(iFile->Read(aBufferDes, requestSize)); |
|
814 } |
|
815 |
|
816 iPosition = aPosition + aBufferDes.Length(); |
|
817 |
|
818 //check if the buffer is the last buffer and if so set the last buffer flag on the CMMFDataBuffer |
|
819 //NB: setting last buffer is the done by the formatter, but this is a hang over to account for |
|
820 //existing formatters that may fail if this is removed. |
|
821 if (iPosition >= Size()) |
|
822 { |
|
823 aBuffer->SetLastBuffer(ETrue); |
|
824 } |
|
825 } |
|
826 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
827 User::Leave(KErrNotSupported); |
|
828 } |
|
829 |
|
830 /** |
|
831 Empties aLength bytes from aBuffer into iFile at specified location. |
|
832 |
|
833 @param aLength |
|
834 The number of bytes to be emptied from buffer. |
|
835 @param aBuffer |
|
836 The data buffer containing bytes to be written. |
|
837 @param aPosition |
|
838 The offset into file at which to start writing. |
|
839 @param aSupplier |
|
840 The data source to be notified when the write has been completed. |
|
841 |
|
842 @leave KErrNotReady |
|
843 SinkPrimeL() and SinkThreadLogon() have not been called. |
|
844 @leave KErrArgument |
|
845 aLength<0 or aPosition<0 or aSupplier is NULL. |
|
846 @leave KErrNotSupported |
|
847 aBuffer is not a supported CMMFDataBuffer |
|
848 */ |
|
849 void CMMFFile::WriteBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier) |
|
850 { |
|
851 if ((aLength<0) || (aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL)) |
|
852 User::Leave(KErrArgument); |
|
853 |
|
854 if (!iFile || (iMmfFileEventHandler == NULL)) |
|
855 User::Leave(KErrNotReady); |
|
856 |
|
857 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
858 { |
|
859 CWriteRequest* request = NULL; |
|
860 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
861 |
|
862 //check whether buffer is safe to send to file server |
|
863 //if not, eg for a transfer buffer, then it needs to be copied |
|
864 if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
865 { |
|
866 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
867 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
868 CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
869 |
|
870 transBufCopy->Des().Copy(aBufferDes); |
|
871 |
|
872 request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, transBufCopy, iMmfFileEventHandler); |
|
873 } |
|
874 else |
|
875 { |
|
876 request = new(ELeave) CWriteRequest(STATIC_CAST(TAny*, aSupplier), aBuffer, iMmfFileEventHandler); |
|
877 } |
|
878 |
|
879 CleanupStack::PushL( request ); |
|
880 |
|
881 StoreRequestL(request); // transfers ownership |
|
882 CleanupStack::Pop(); // request |
|
883 |
|
884 User::LeaveIfError(iFile->Seek(ESeekStart, aPosition)); |
|
885 iFile->Write(request->BufferDes(), aLength, request->iStatus); |
|
886 iFileSize = -1; //reset cached size |
|
887 |
|
888 request->SetActive(); |
|
889 } |
|
890 else // if (!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
891 { |
|
892 //write bitmap to file |
|
893 User::Leave(KErrNotSupported); |
|
894 } |
|
895 } |
|
896 |
|
897 /** |
|
898 Empties aBuffer into iFile at the specified location. |
|
899 |
|
900 @param aBuffer |
|
901 The data buffer containing bytes to be written. |
|
902 @param aPosition |
|
903 The offset into file at which to start writing. |
|
904 @param aSupplier |
|
905 The data source to be notified when the write has been completed. |
|
906 |
|
907 @leave KErrNotReady |
|
908 SinkPrimeL() and SinkThreadLogon() have not been called. |
|
909 @leave KErrArgument |
|
910 aSupplier is NULL. |
|
911 @leave KErrNotSupported |
|
912 The aBuffer is not of type KMMFDataBuffer. |
|
913 */ |
|
914 void CMMFFile::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier) |
|
915 { |
|
916 // Requires that iFile is open for write. |
|
917 // Writes data from iFile into aBuffer |
|
918 if ((aPosition<0) || (aSupplier == NULL) || (aBuffer == NULL)) |
|
919 User::Leave(KErrArgument); |
|
920 |
|
921 if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
922 { |
|
923 TUint requestSize = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data().Length(); |
|
924 |
|
925 WriteBufferL(requestSize, aBuffer, aPosition, aSupplier); |
|
926 } |
|
927 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
928 { |
|
929 //write bitmap to file |
|
930 User::Leave( KErrNotSupported ) ; |
|
931 } |
|
932 } |
|
933 |
|
934 /** |
|
935 Empties aBuffer into iFile at specified location. Note that this is a synchronous write. |
|
936 |
|
937 @param aBuffer |
|
938 The data buffer containing bytes to be written. |
|
939 @param aPosition |
|
940 The offset into file at which to start writing. |
|
941 |
|
942 @return The error code from RFile. |
|
943 */ |
|
944 void CMMFFile::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition ) |
|
945 { |
|
946 if ((aPosition<0) || (aBuffer == NULL)) |
|
947 User::Leave(KErrArgument); |
|
948 |
|
949 if (!iFile) |
|
950 User::Leave(KErrNotReady); |
|
951 |
|
952 TInt err(KErrNone) ; |
|
953 |
|
954 //check whether buffer is safe to send to file server |
|
955 //if not, eg for a transfer buffer, then it needs to be copied |
|
956 if ((!CMMFBuffer::IsFileServerSafe(aBuffer->Type())) |
|
957 && (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))) |
|
958 { |
|
959 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
960 |
|
961 //NB: failure in this method will NOT cause transBufCopy to leak as it will be |
|
962 //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. |
|
963 CTransferBufferCopy* transBufCopy = ObtainCopyOfTransferBufferL(aBufferDes.MaxLength()); |
|
964 |
|
965 transBufCopy->Des().Copy(aBufferDes); |
|
966 err = iFile->Seek(ESeekStart, aPosition); |
|
967 if (err==KErrNone) |
|
968 err = iFile->Write(transBufCopy->Des(),transBufCopy->Des().Length()); |
|
969 iFileSize = -1; //reset cached size |
|
970 } |
|
971 else if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
972 { |
|
973 TDes8& aBufferDes = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data(); |
|
974 |
|
975 err = iFile->Seek(ESeekStart, aPosition); |
|
976 if (err==KErrNone) |
|
977 err = iFile->Write(aBufferDes, aBufferDes.Length()); |
|
978 iFileSize = -1; //reset cached size |
|
979 } |
|
980 else // if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())) |
|
981 { |
|
982 User::Leave(KErrNotSupported); |
|
983 } |
|
984 |
|
985 User::LeaveIfError(err); |
|
986 } |
|
987 |
|
988 /** |
|
989 Gets the number of free bytes in the device's file system. |
|
990 |
|
991 @return The number of free bytes. |
|
992 */ |
|
993 TInt64 CMMFFile::BytesFree() |
|
994 { |
|
995 TInt driveNumber = KDefaultDrive; |
|
996 |
|
997 if (FileDrive().Length() > 0) |
|
998 { |
|
999 TChar driveLetter = FileDrive()[0]; |
|
1000 RFs::CharToDrive(driveLetter, driveNumber); |
|
1001 } |
|
1002 |
|
1003 TVolumeInfo volInfo; |
|
1004 if (iFsSession.Volume(volInfo, driveNumber) == KErrNone) |
|
1005 { |
|
1006 return volInfo.iFree; |
|
1007 } |
|
1008 return TInt64(0); |
|
1009 } |
|
1010 |
|
1011 /** |
|
1012 Returns the size of the file in bytes. |
|
1013 |
|
1014 Note: This is not the maximum length. |
|
1015 |
|
1016 @return The size of the file in bytes. |
|
1017 */ |
|
1018 TInt CMMFFile::Size() |
|
1019 { |
|
1020 TInt size = 0; |
|
1021 TInt err = KErrNone; |
|
1022 TBool fileOpened = EFalse; |
|
1023 |
|
1024 if(iFileSize != -1) |
|
1025 return iFileSize; |
|
1026 |
|
1027 if (!iFile) |
|
1028 { |
|
1029 // Open the file. We only need read access, so SourcePrimeL will open the file with read flag |
|
1030 TRAP(err, SourcePrimeL()); |
|
1031 if (iFile) |
|
1032 fileOpened = ETrue; |
|
1033 } |
|
1034 if (err == KErrNone) |
|
1035 err = iFile->Size(size); |
|
1036 if (err) |
|
1037 { |
|
1038 size = 0; |
|
1039 iFileSize = -1; //reset cached size |
|
1040 } |
|
1041 else |
|
1042 iFileSize = size; //cache the filesize |
|
1043 |
|
1044 if (fileOpened) |
|
1045 { |
|
1046 delete iFile; |
|
1047 iFile = NULL; |
|
1048 iFileSize = -1; |
|
1049 } |
|
1050 |
|
1051 return size; |
|
1052 } |
|
1053 |
|
1054 /** |
|
1055 Source thread logon. |
|
1056 |
|
1057 Shares fsSession between threads |
|
1058 |
|
1059 @param aEventHandler |
|
1060 This is an MAsyncEventHandler to handle asynchronous events that occur during the |
|
1061 transfer of multimedia data. |
|
1062 |
|
1063 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
1064 another of the system-wide error codes. |
|
1065 */ |
|
1066 TInt CMMFFile::SourceThreadLogon(MAsyncEventHandler& aEventHandler) |
|
1067 { |
|
1068 iEventHandler = &aEventHandler; |
|
1069 if(!iMmfFileEventHandler) |
|
1070 { |
|
1071 iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this); |
|
1072 if(!iMmfFileEventHandler) |
|
1073 return KErrNoMemory; |
|
1074 } |
|
1075 #ifdef __IPC_V2_PRESENT__ |
|
1076 return KErrNone; // nothing to do |
|
1077 #else |
|
1078 return iFsSession.Attach(); |
|
1079 #endif // __HIDE_IPC_V1__ |
|
1080 } |
|
1081 |
|
1082 /** |
|
1083 Logs off source thread. |
|
1084 */ |
|
1085 void CMMFFile::SourceThreadLogoff() |
|
1086 { |
|
1087 delete iMmfFileEventHandler; |
|
1088 iMmfFileEventHandler = NULL; |
|
1089 iEventHandler = NULL; |
|
1090 } |
|
1091 |
|
1092 |
|
1093 /** |
|
1094 Sink thread logon. |
|
1095 |
|
1096 Shares fsSession between threads. |
|
1097 |
|
1098 @param aEventHandler |
|
1099 This is an MAsyncEventHandler to handle asynchronous events that occur during the |
|
1100 transfer of multimedia data. |
|
1101 |
|
1102 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
1103 another of the system-wide error codes. |
|
1104 */ |
|
1105 TInt CMMFFile::SinkThreadLogon(MAsyncEventHandler& aEventHandler) |
|
1106 { |
|
1107 iEventHandler = &aEventHandler; |
|
1108 if(!iMmfFileEventHandler) |
|
1109 { |
|
1110 iMmfFileEventHandler = new CMMFFileAsyncEventHandler(this); |
|
1111 if(!iMmfFileEventHandler) |
|
1112 return KErrNoMemory; |
|
1113 } |
|
1114 #ifdef __IPC_V2_PRESENT__ |
|
1115 return KErrNone; |
|
1116 #else |
|
1117 return iFsSession.Attach(); |
|
1118 #endif // __HIDE_IPC_V1__ |
|
1119 } |
|
1120 |
|
1121 /** |
|
1122 Sink thread log off. |
|
1123 */ |
|
1124 void CMMFFile::SinkThreadLogoff() |
|
1125 { |
|
1126 delete iMmfFileEventHandler; |
|
1127 iMmfFileEventHandler = NULL; |
|
1128 iEventHandler = NULL; |
|
1129 } |
|
1130 |
|
1131 /** |
|
1132 Stores a request in an array. |
|
1133 |
|
1134 CReadWriteRequests are stored in the array iRequests. |
|
1135 This function takes ownership and places the request in the array. |
|
1136 It also checks the array for completed requests and removes them. |
|
1137 |
|
1138 @param aRequest |
|
1139 The request to store. |
|
1140 */ |
|
1141 void CMMFFile::StoreRequestL( CReadWriteRequest* aRequest ) |
|
1142 { |
|
1143 // add aRequest to iRequests |
|
1144 User::LeaveIfError( iRequests.Append( aRequest ) ) ; |
|
1145 |
|
1146 // Clear out any completed requests |
|
1147 for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ ) |
|
1148 { |
|
1149 if (iRequests[ii]->Completed()) |
|
1150 { |
|
1151 CReadWriteRequest* request = iRequests[ii]; |
|
1152 delete request; |
|
1153 |
|
1154 iRequests.Remove(ii); |
|
1155 ii--; |
|
1156 } |
|
1157 } |
|
1158 } |
|
1159 |
|
1160 |
|
1161 /** |
|
1162 Cancels outstanding requests. |
|
1163 |
|
1164 CReadWriteRequests are stored in the array iRequests. |
|
1165 This function cancels any outstanding requests and removes them |
|
1166 from iRequests. |
|
1167 */ |
|
1168 void CMMFFile::CancelRequests() |
|
1169 { |
|
1170 // Clear out any completed requests |
|
1171 for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ ) |
|
1172 { |
|
1173 CReadWriteRequest* request = iRequests[ii]; |
|
1174 delete request; |
|
1175 iRequests.Remove(ii); |
|
1176 ii--; |
|
1177 } |
|
1178 } |
|
1179 |
|
1180 |
|
1181 |
|
1182 /** |
|
1183 Returns the data type as a fourCC code of CMMFFile as a data source. |
|
1184 |
|
1185 @return The data type fourCC code. |
|
1186 */ |
|
1187 TFourCC CMMFFile::SourceDataTypeCode(TMediaId /*aMediaId*/) |
|
1188 { |
|
1189 return iSourceFourCC ; |
|
1190 } |
|
1191 |
|
1192 /** |
|
1193 Returns the data type as a fourCC code of CMMFFile as a data sink. |
|
1194 |
|
1195 @return The data type fourCC code |
|
1196 */ |
|
1197 TFourCC CMMFFile::SinkDataTypeCode(TMediaId /*aMediaId*/) |
|
1198 { |
|
1199 return iSinkFourCC ; |
|
1200 } |
|
1201 |
|
1202 |
|
1203 /** |
|
1204 CMMFFile as a source is always passive so this function is not supported. |
|
1205 |
|
1206 @param aBuffer |
|
1207 The emptied buffer. |
|
1208 */ |
|
1209 void CMMFFile::BufferEmptiedL(CMMFBuffer* /* aBuffer */) |
|
1210 { |
|
1211 Panic(EMMFFilePanicBufferEmptiedLNotSupported); |
|
1212 } |
|
1213 |
|
1214 /** |
|
1215 Tests whether a source buffer can be created. |
|
1216 |
|
1217 @return A boolean indicating if if CMMFFile can create its own buffer. EFalse if CMMFFile cannot |
|
1218 create it's own buffer. |
|
1219 */ |
|
1220 TBool CMMFFile::CanCreateSourceBuffer() |
|
1221 { |
|
1222 return EFalse ; |
|
1223 } |
|
1224 |
|
1225 /** |
|
1226 Creates a source buffer. |
|
1227 |
|
1228 @param aMediaId |
|
1229 The Media ID. |
|
1230 @param aReference |
|
1231 A boolean indicating if MDataSource owns the buffer. ETrue if it does, EFalse if the caller |
|
1232 owns the buffer. |
|
1233 |
|
1234 @return NULL as a CMMFFile cannot create it's own buffer |
|
1235 */ |
|
1236 CMMFBuffer* CMMFFile::CreateSourceBufferL( TMediaId /*aMediaId*/ , TBool& /*aReference*/) |
|
1237 { |
|
1238 User::Leave(KErrNotSupported); |
|
1239 return NULL ; |
|
1240 } |
|
1241 |
|
1242 /** |
|
1243 CMMFFile as a sink is always passive so this function is not supported. |
|
1244 |
|
1245 @param aBuffer |
|
1246 The buffer. |
|
1247 */ |
|
1248 void CMMFFile::BufferFilledL(CMMFBuffer* /* aBuffer */) |
|
1249 { |
|
1250 Panic(EMMFFilePanicBufferFilledLNotSupported); |
|
1251 } |
|
1252 |
|
1253 /** |
|
1254 Tests whether a sink buffer can be created. |
|
1255 |
|
1256 @return A boolean indicating if the sink buffer can be created. EFalse if CMMFFile cannot create |
|
1257 it's own buffer |
|
1258 */ |
|
1259 TBool CMMFFile::CanCreateSinkBuffer() |
|
1260 { |
|
1261 return EFalse ; |
|
1262 } |
|
1263 |
|
1264 /** |
|
1265 Creates a sink buffer. |
|
1266 |
|
1267 @param aMediaId |
|
1268 The Media ID. |
|
1269 @param aReference |
|
1270 A boolean indicating if MDataSource owns the buffer. ETrue if MDataSource owns the buffer, |
|
1271 EFalse if the caller owns the buffer. |
|
1272 |
|
1273 @return NULL as a CMMFFile cannot create it's own buffer |
|
1274 */ |
|
1275 CMMFBuffer* CMMFFile::CreateSinkBufferL(TMediaId /*aMediaId*/ , TBool& /*aReference*/) |
|
1276 { |
|
1277 User::Leave(KErrNotSupported); |
|
1278 return NULL ; |
|
1279 } |
|
1280 |
|
1281 /** |
|
1282 Primes the source. |
|
1283 |
|
1284 When used as a source, the file prime opens the file as read only. |
|
1285 */ |
|
1286 void CMMFFile::SourcePrimeL() |
|
1287 { |
|
1288 // don't reopen file if already open |
|
1289 if (!iFile) |
|
1290 { |
|
1291 if (iFileHandle) |
|
1292 { |
|
1293 iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI); |
|
1294 } |
|
1295 else |
|
1296 { |
|
1297 // Open for read-only access |
|
1298 iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareReadersOnly, iCAFParameters->iEnableUI); |
|
1299 } |
|
1300 } |
|
1301 } |
|
1302 |
|
1303 /** |
|
1304 Primes the sink. |
|
1305 |
|
1306 When used as a sink, the file prime opens the file for read/write access. |
|
1307 */ |
|
1308 void CMMFFile::SinkPrimeL() |
|
1309 { |
|
1310 // don't reopen file if already open |
|
1311 if (!iFile) |
|
1312 { |
|
1313 if (iFileHandle) |
|
1314 iFile = CF32File::NewL(iHandle); |
|
1315 else |
|
1316 iFile = CF32File::NewL(iFsSession, iFullFileName, EFileRead | EFileWrite); |
|
1317 } |
|
1318 iSinkNotStopped = ETrue; |
|
1319 } |
|
1320 |
|
1321 /** |
|
1322 Stops the file source. When stopping close the file. If the source is a file handle, the position is reset, but the |
|
1323 file handle remains open. |
|
1324 */ |
|
1325 void CMMFFile::SourceStopL() |
|
1326 { |
|
1327 TInt pos = 0; |
|
1328 |
|
1329 CancelRequests(); |
|
1330 |
|
1331 // It is possible the file could have disappeared at this point (MMC/SD Card) |
|
1332 // |
|
1333 if (!iFile) |
|
1334 { |
|
1335 iPosition=pos; |
|
1336 return; |
|
1337 } |
|
1338 |
|
1339 if (!iFileHandle && !iFile->IsProtected()) |
|
1340 { |
|
1341 delete iFile; |
|
1342 iFile = NULL; |
|
1343 iFileSize = -1; |
|
1344 } |
|
1345 else |
|
1346 { |
|
1347 User::LeaveIfError(iFile->Seek(ESeekStart, pos)); |
|
1348 } |
|
1349 iPosition=pos; |
|
1350 } |
|
1351 |
|
1352 /** |
|
1353 Stops the file sink. |
|
1354 |
|
1355 When stopping close the file. When the file sink is a file handle, the position is reset, but the file handle |
|
1356 remains open |
|
1357 */ |
|
1358 void CMMFFile::SinkStopL() |
|
1359 { |
|
1360 iFileSize = -1; |
|
1361 iPosition=0; |
|
1362 |
|
1363 CancelRequests(); |
|
1364 iSinkNotStopped = EFalse; |
|
1365 if (!iFileHandle) |
|
1366 { |
|
1367 delete iFile; |
|
1368 iFile = NULL; |
|
1369 } |
|
1370 else |
|
1371 { |
|
1372 TInt pos = 0; |
|
1373 User::LeaveIfError(iFile->Seek(ESeekStart, pos)); |
|
1374 } |
|
1375 } |
|
1376 |
|
1377 /** |
|
1378 Pauses the file source |
|
1379 */ |
|
1380 void CMMFFile::SourcePauseL() |
|
1381 { |
|
1382 CancelRequests(); |
|
1383 } |
|
1384 |
|
1385 /** |
|
1386 Returns a boolean indicating if the sink has been stopped. |
|
1387 |
|
1388 @return A boolean indicating if the sink has stopped. |
|
1389 */ |
|
1390 TBool CMMFFile::SinkStopped() |
|
1391 { |
|
1392 if(iSinkNotStopped == EFalse) |
|
1393 return ETrue; |
|
1394 else |
|
1395 return EFalse; |
|
1396 } |
|
1397 |
|
1398 /** |
|
1399 Evaluates a given intent against the rights associated with the file. |
|
1400 |
|
1401 The rights are not updated by this function call. |
|
1402 |
|
1403 @param aIntent |
|
1404 The intent to evaluate. |
|
1405 |
|
1406 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
1407 another of the system-wide error codes. |
|
1408 */ |
|
1409 TInt CMMFFile::EvaluateIntent(ContentAccess::TIntent aIntent) const |
|
1410 { |
|
1411 if (iFile==NULL) |
|
1412 { |
|
1413 return KErrNotReady; |
|
1414 } |
|
1415 |
|
1416 return iFile->EvaluateIntent(aIntent); |
|
1417 } |
|
1418 |
|
1419 /** |
|
1420 Evaluates and executes a given intent against the rights associated with the file. |
|
1421 |
|
1422 The rights object is updated after calling this function. |
|
1423 |
|
1424 @param aIntent |
|
1425 The intent to evaluate. |
|
1426 |
|
1427 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
1428 another of the system-wide error codes. |
|
1429 */ |
|
1430 TInt CMMFFile::ExecuteIntent(ContentAccess::TIntent aIntent) |
|
1431 { |
|
1432 if (iFile==NULL) |
|
1433 { |
|
1434 return KErrNotReady; |
|
1435 } |
|
1436 |
|
1437 return iFile->ExecuteIntent(aIntent); |
|
1438 } |
|
1439 |
|
1440 /** |
|
1441 Returns whether the file is protected. |
|
1442 |
|
1443 @return A boolean indicating if the file is protected. ETrue if the file is protected. |
|
1444 */ |
|
1445 TBool CMMFFile::IsProtectedL() const |
|
1446 { |
|
1447 if (iFile==NULL) |
|
1448 { |
|
1449 User::Leave(KErrNotReady); |
|
1450 } |
|
1451 |
|
1452 return iFile->IsProtected(); |
|
1453 } |
|
1454 |
|
1455 TInt CMMFFile::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue) |
|
1456 { |
|
1457 if (iFile==NULL) |
|
1458 { |
|
1459 return KErrNotReady; |
|
1460 } |
|
1461 |
|
1462 return iFile->SetAgentProperty(aProperty, aValue); |
|
1463 } |
|
1464 |
|
1465 /* |
|
1466 * Returns ETrue if the request can safely be deleted. |
|
1467 */ |
|
1468 TBool CReadWriteRequest::Completed() |
|
1469 { |
|
1470 return iCompleted ; |
|
1471 } |
|
1472 |
|
1473 /* |
|
1474 * Returns the data member of CMMFDataBuffer or CMMFTransferBuffer (as TPtr8) |
|
1475 * |
|
1476 */ |
|
1477 TDes8& CReadWriteRequest::BufferDes() |
|
1478 { |
|
1479 if(iTransferBufferCopy) |
|
1480 return iTransferBufferCopy->Des(); |
|
1481 else |
|
1482 { |
|
1483 //reset iBufferDes in case iBuffer has changed... |
|
1484 iBufferDes = &(STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data()); |
|
1485 return *iBufferDes; |
|
1486 } |
|
1487 } |
|
1488 |
|
1489 const TDesC8& CReadWriteRequest::BufferDesC() |
|
1490 { |
|
1491 if(iTransferBufferCopy) |
|
1492 return iTransferBufferCopy->Des(); |
|
1493 else |
|
1494 return BufferDes(); |
|
1495 } |
|
1496 |
|
1497 |
|
1498 /* |
|
1499 * Destructor. |
|
1500 */ |
|
1501 CReadWriteRequest::~CReadWriteRequest() |
|
1502 { |
|
1503 Cancel(); |
|
1504 if(iTransferBufferCopy) |
|
1505 iTransferBufferCopy->SetInUse(EFalse); |
|
1506 } |
|
1507 |
|
1508 /* |
|
1509 * Allows owning class access to SetActive() |
|
1510 */ |
|
1511 void CReadWriteRequest::SetActive() |
|
1512 { |
|
1513 CActive::SetActive() ; |
|
1514 } |
|
1515 |
|
1516 /* |
|
1517 * For the moment at least... Canceled requests may be deleted |
|
1518 */ |
|
1519 void CReadWriteRequest::DoCancel() |
|
1520 { |
|
1521 iCompleted = ETrue ; |
|
1522 } |
|
1523 |
|
1524 /* |
|
1525 * Called when errors in RunL force Leave. For the moment just mark the request deletable |
|
1526 */ |
|
1527 TInt CReadWriteRequest::RunError( TInt aError ) |
|
1528 { |
|
1529 //RunL can leave. |
|
1530 iCompleted = ETrue ; |
|
1531 iError = aError; //keep this error internally for now |
|
1532 return KErrNone ; |
|
1533 } |
|
1534 |
|
1535 /* |
|
1536 * On completion of read request call back to the MDataSink |
|
1537 */ |
|
1538 void CReadRequest::RunL() |
|
1539 { |
|
1540 if (iStatus != KErrNone) |
|
1541 { |
|
1542 TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int()); |
|
1543 iEventHandler->SendEventToClient(event); |
|
1544 } |
|
1545 else |
|
1546 { |
|
1547 //Copy the data from the normal buffer into the Transfer buffer |
|
1548 if(iTransferBufferCopy) |
|
1549 { |
|
1550 //must specify the size here as the dest may be smaller than the source. |
|
1551 TDes8& destDesc = STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data(); |
|
1552 destDesc.Copy(iTransferBufferCopy->Des().Left(destDesc.MaxLength())); |
|
1553 |
|
1554 iTransferBufferCopy->SetInUse(EFalse); |
|
1555 } |
|
1556 |
|
1557 // removed checking EOF from here, it should be checked in CMMFFile |
|
1558 |
|
1559 REINTERPRET_CAST(MDataSink*, iSinkOrSource)->BufferFilledL(iBuffer) ; // callback to MDataSource/Sink |
|
1560 } |
|
1561 |
|
1562 iCompleted = ETrue ; |
|
1563 } |
|
1564 |
|
1565 /* |
|
1566 * On completion of write request call back to the MDataSource |
|
1567 */ |
|
1568 void CWriteRequest::RunL() |
|
1569 { |
|
1570 if(iTransferBufferCopy) |
|
1571 iTransferBufferCopy->SetInUse(EFalse); |
|
1572 |
|
1573 if (iStatus != KErrNone) |
|
1574 { |
|
1575 TMMFEvent event(KMMFErrorCategoryControllerGeneralError, iStatus.Int()); |
|
1576 iEventHandler->SendEventToClient(event); |
|
1577 } |
|
1578 else |
|
1579 REINTERPRET_CAST(MDataSource*, iSinkOrSource)->BufferEmptiedL(iBuffer) ; // callback to MDataSource/Sink |
|
1580 |
|
1581 iCompleted = ETrue ; |
|
1582 } |
|
1583 |
|
1584 CMMFFile::CMMFFileAsyncEventHandler::CMMFFileAsyncEventHandler(CMMFFile* aParent) |
|
1585 { |
|
1586 iParent = aParent; |
|
1587 } |
|
1588 |
|
1589 CMMFFile::CMMFFileAsyncEventHandler::~CMMFFileAsyncEventHandler() |
|
1590 { |
|
1591 } |
|
1592 |
|
1593 TInt CMMFFile::CMMFFileAsyncEventHandler::SendEventToClient(const TMMFEvent& aEvent) |
|
1594 { |
|
1595 if(aEvent.iErrorCode == KErrNotReady)//i.e. MMC removed while recording |
|
1596 { |
|
1597 TRAPD(err, iParent->SinkStopL() ); |
|
1598 if (err != KErrNone) |
|
1599 { |
|
1600 return err; |
|
1601 } |
|
1602 } |
|
1603 return iParent->iEventHandler->SendEventToClient(aEvent); |
|
1604 } |
|
1605 |
|
1606 /** |
|
1607 Returns access to internal CData property |
|
1608 |
|
1609 @param aData |
|
1610 On return, set to the internal CData property used to access file for reading. |
|
1611 |
|
1612 Returns: |
|
1613 * KErrNotReady if the file is not open/data object has not been created. |
|
1614 * KErrNotSupported if not supported (e.g. on data sink) |
|
1615 |
|
1616 @return Standard error code |
|
1617 */ |
|
1618 TInt CMMFFile::Data(ContentAccess::CData*& aData) |
|
1619 { |
|
1620 if (!iFile) |
|
1621 { |
|
1622 return KErrNotReady; |
|
1623 } |
|
1624 else |
|
1625 { |
|
1626 return iFile->Data(aData); |
|
1627 } |
|
1628 } |
|
1629 |