|
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 /** |
|
17 @file |
|
18 @internalComponent |
|
19 */ |
|
20 |
|
21 #include <obex.h> |
|
22 #include <obexpanics.h> |
|
23 #include "logger.h" |
|
24 #include "OBEXUTIL.H" |
|
25 #include "obexasyncfilewriter.h" |
|
26 #include "obexsyncfilewriter.h" |
|
27 #include "obexfaults.h" |
|
28 |
|
29 #ifdef __FLOG_ACTIVE |
|
30 _LIT8(KLogComponent, "OBEX"); |
|
31 #endif |
|
32 |
|
33 /** Creates a new CObexFileObject object. |
|
34 Static file object factory. returns a new CObexFileObject, set up to use a |
|
35 temporary file to store received data into "on the fly". If used for |
|
36 sourcing an object to send a "NULL" object(body length 0) will be sent. |
|
37 @return Instance of CObexFileObject |
|
38 |
|
39 @publishedAll |
|
40 @released |
|
41 */ |
|
42 EXPORT_C CObexFileObject* CObexFileObject::NewL() |
|
43 { |
|
44 LOG_LINE |
|
45 LOG_STATIC_FUNC_ENTRY |
|
46 |
|
47 CObexFileObject* self = new(ELeave) CObexFileObject; |
|
48 CleanupStack::PushL(self); |
|
49 self->ConstructL(TPtrC(NULL, 0)); |
|
50 CleanupStack::Pop(); |
|
51 return(self); |
|
52 } |
|
53 |
|
54 /** Creates a new CObexFileObject object. |
|
55 Static file object factory. returns a new CObexFileObject, set up to use |
|
56 aDataFile as its data file, or will create a temp file if aDataFile is not |
|
57 a valid file name. If used for sourcing an object to send, and no valid data |
|
58 file is set, a "NULL" object(body length 0) will be sent. |
|
59 @param aDataFile Filename to configure this object to use |
|
60 @return Instance of CObexFileObject |
|
61 |
|
62 @publishedAll |
|
63 @released |
|
64 */ |
|
65 EXPORT_C CObexFileObject* CObexFileObject::NewL(const TDesC &aDataFile) |
|
66 { |
|
67 LOG_LINE |
|
68 LOG_STATIC_FUNC_ENTRY |
|
69 |
|
70 CObexFileObject* self = new(ELeave) CObexFileObject; |
|
71 CleanupStack::PushL(self); |
|
72 self->ConstructL(aDataFile); |
|
73 CleanupStack::Pop(); |
|
74 return(self); |
|
75 } |
|
76 |
|
77 /** Destructor. |
|
78 |
|
79 @publishedAll |
|
80 @released |
|
81 */ |
|
82 EXPORT_C CObexFileObject::~CObexFileObject() |
|
83 { |
|
84 LOG_LINE |
|
85 LOG_FUNC |
|
86 |
|
87 ResetData(); |
|
88 iFs.Close(); |
|
89 } |
|
90 |
|
91 /** |
|
92 Sets the name of a file which holds the data to be used as the objects body. |
|
93 Leaves if the file does not exist, or can not be opened for writing. |
|
94 |
|
95 @param aDesc Filename to configure this object to use |
|
96 */ |
|
97 void CObexFileObject::SetDataFileL(const TDesC& aDesc)// does this need to be exported???? |
|
98 { |
|
99 ResetData(); |
|
100 if(aDesc.Length() == 0) |
|
101 return; |
|
102 TInt err = iDataFile.SetNoWild(aDesc, NULL, NULL); |
|
103 if(err == KErrNone) //try and open for read/write |
|
104 err = iFile.Open(iFs, iDataFile.FullName(), EFileWrite | EFileShareExclusive); |
|
105 if(err != KErrNone) |
|
106 { //can't open it for write so open it for read |
|
107 err = iFile.Open(iFs, iDataFile.FullName(), EFileRead | EFileShareReadersOnly); |
|
108 if(err != KErrNone) |
|
109 { |
|
110 iDataFile.SetNoWild(KNullDesC, NULL, NULL); |
|
111 iFile.Close(); // Manually close file |
|
112 User::Leave(err); |
|
113 } |
|
114 } |
|
115 } |
|
116 |
|
117 /** |
|
118 Get the name of the file representing the object body. |
|
119 |
|
120 @return the full path and name of the file representing the object body. |
|
121 Null descriptor if no valid data file has been set, or if Reset() |
|
122 has been called on the object since a file was last set. |
|
123 */ |
|
124 const TDesC& CObexFileObject::DataFile() |
|
125 { |
|
126 return iDataFile.FullName(); |
|
127 } |
|
128 |
|
129 TInt CObexFileObject::RenameFile(const TDesC& aDesC) |
|
130 { |
|
131 iFile.SetAtt(0,KEntryAttHidden);// - dont check return code - if it fails it fails |
|
132 return(iFile.Rename(aDesC)); |
|
133 } |
|
134 |
|
135 void CObexFileObject::SetTempFilePath(const TDesC& aPath) |
|
136 { |
|
137 iTempFilePath = aPath; |
|
138 } |
|
139 |
|
140 void CObexFileObject::QueryTempFilePath(TDes& aPath) |
|
141 { |
|
142 aPath = iTempFilePath; |
|
143 } |
|
144 |
|
145 /** |
|
146 Constructs this object. |
|
147 |
|
148 @param aDataFile The file to use for the object's data part. |
|
149 */ |
|
150 void CObexFileObject::ConstructL(const TDesC &aDataFile) |
|
151 { |
|
152 CreateHeaderStorageDataL(); |
|
153 LEAVEIFERRORL(iFs.Connect()); |
|
154 SetDataFileL(aDataFile); |
|
155 iTempFilePath = KNullDesC; |
|
156 } |
|
157 |
|
158 /** Initialises this object from the specified file. |
|
159 |
|
160 The function attempts to set attribute values for the object as follows: |
|
161 |
|
162 Length:set to the length of the file |
|
163 |
|
164 Name:taken from the name portion of the path in aFile |
|
165 |
|
166 Time:taken from the modification time of the file |
|
167 |
|
168 Type:set appropriately if the file extension is .vcf (VCard), .vcs (Vcalendar), |
|
169 or .txt. |
|
170 |
|
171 @param aFile Body data file |
|
172 |
|
173 @publishedAll |
|
174 @released |
|
175 */ |
|
176 EXPORT_C void CObexFileObject::InitFromFileL(const TDesC& aFile) |
|
177 { |
|
178 LOG_LINE |
|
179 LOG_FUNC |
|
180 |
|
181 Reset(); |
|
182 SetDataFileL(aFile); |
|
183 |
|
184 |
|
185 SetNameL(iDataFile.NameAndExt()); |
|
186 GuessTypeFromExtL(iDataFile.Ext()); |
|
187 |
|
188 TInt length; |
|
189 if(iFile.Size(length) == KErrNone) |
|
190 { |
|
191 SetLengthL(length); |
|
192 } |
|
193 |
|
194 TTime time; |
|
195 if(iFile.Modified(time) == KErrNone) |
|
196 { |
|
197 SetUtcTimeL(time); |
|
198 } |
|
199 } |
|
200 |
|
201 |
|
202 /** |
|
203 Virtual pure function form the base object. Tries to fill aDes with data |
|
204 starting from aPos byte offset. returns null descriptor if no data file is |
|
205 set. |
|
206 @param aPos Position (reliative to start of object) to start extracting data from |
|
207 @param aDes Descriptor to fill |
|
208 */ |
|
209 void CObexFileObject::GetData(TInt aPos, TDes8& aDes) |
|
210 { |
|
211 if(iDataFile.NameOrExtPresent() && iFile.Read(aPos, aDes) == KErrNone) |
|
212 return; |
|
213 aDes.SetLength(0); |
|
214 } |
|
215 |
|
216 /** |
|
217 Virtual pure function overload. inserts aDes into the data file at location |
|
218 aPos |
|
219 @param aPos Position (reliative to start of object) to start inserting data from |
|
220 @param aDes Descriptor to insert |
|
221 */ |
|
222 void CObexFileObject::NewData(TInt aPos, TDes8& aDes) |
|
223 { |
|
224 // iTempFilePath.SetLength(0); |
|
225 if(!iDataFile.NameOrExtPresent()) |
|
226 { |
|
227 ResetData(); |
|
228 TFileName fname; |
|
229 TInt err = iFile.Temp(iFs, iTempFilePath, fname, EFileWrite | EFileShareExclusive); |
|
230 if(err == KErrNone) |
|
231 err = iFs.Parse(fname, iDataFile.Path(), iDataFile); |
|
232 if(err != KErrNone) |
|
233 { |
|
234 ResetData(); |
|
235 iFs.Delete(fname); |
|
236 aDes.SetLength(0); |
|
237 return; |
|
238 } |
|
239 iFile.SetAtt(KEntryAttHidden,0);// dont check return code - if it fails it fails |
|
240 } |
|
241 if(iFile.Write(aPos, aDes) != KErrNone) |
|
242 aDes.SetLength(0); |
|
243 } |
|
244 |
|
245 /** |
|
246 @return number of bytes in the data file (0 if no file is set) |
|
247 */ |
|
248 TInt CObexFileObject::DataSize() |
|
249 { |
|
250 if(!iDataFile.NameOrExtPresent()) |
|
251 return(0); |
|
252 TInt size = 0; |
|
253 iFile.Size(size); |
|
254 return(size); |
|
255 } |
|
256 |
|
257 /** |
|
258 Set object back to a null file. |
|
259 */ |
|
260 void CObexFileObject::ResetData() |
|
261 { |
|
262 iFile.Close(); |
|
263 iDataFile.Set(KNullDesC, NULL, NULL); |
|
264 } |
|
265 |
|
266 // |
|
267 // class CObexBufObject |
|
268 // |
|
269 |
|
270 /** |
|
271 Allocates and constructs a new OBEX dynamic buffer object, specifying a buffer. |
|
272 |
|
273 @param aDataBuf The buffer for the body of the object. This must be set either |
|
274 by this constructor or by calling SetDataBufL() before using the object. |
|
275 @return New OBEX dynamic buffer object |
|
276 |
|
277 @publishedAll |
|
278 @released |
|
279 */ |
|
280 EXPORT_C CObexBufObject* CObexBufObject::NewL(CBufBase* aDataBuf) |
|
281 { |
|
282 LOG_LINE |
|
283 LOG_STATIC_FUNC_ENTRY |
|
284 |
|
285 CObexBufObject* self = new(ELeave) CObexBufObject; |
|
286 CleanupStack::PushL(self); |
|
287 self->ConstructL(aDataBuf); |
|
288 CleanupStack::Pop(); |
|
289 return(self); |
|
290 } |
|
291 |
|
292 /** Destructor. |
|
293 |
|
294 @publishedAll |
|
295 @released |
|
296 */ |
|
297 EXPORT_C CObexBufObject::~CObexBufObject() |
|
298 { |
|
299 LOG_LINE |
|
300 LOG_FUNC |
|
301 |
|
302 delete iWriter; |
|
303 |
|
304 CloseDataFile(); |
|
305 CloseFileServer(); |
|
306 |
|
307 delete iFilename; |
|
308 |
|
309 delete iDoubleBuf; |
|
310 } |
|
311 |
|
312 /** Writes contents of object to a file |
|
313 @param aFileName Target file |
|
314 @return a Symbian OS error code if file write fails. |
|
315 |
|
316 @publishedAll |
|
317 @released |
|
318 */ |
|
319 EXPORT_C TInt CObexBufObject::WriteToFile(const TPtrC& aFileName) |
|
320 { |
|
321 LOG_LINE |
|
322 LOG_FUNC |
|
323 |
|
324 TInt ret = KErrNone; |
|
325 TRAP(ret, CopyFileL(aFileName)); |
|
326 return ret; |
|
327 } |
|
328 |
|
329 |
|
330 NONSHARABLE_CLASS(TFileDetails) |
|
331 { |
|
332 public: |
|
333 TFileDetails(RFile& aFile, RFs& aFs, const TDesC& aFilename); |
|
334 inline RFile* File(); |
|
335 inline RFs* FileServ(); |
|
336 inline const TDesC* Filename(); |
|
337 |
|
338 private: |
|
339 RFile* iFile; |
|
340 RFs* iFileServ; |
|
341 const TDesC* iFilename; |
|
342 }; |
|
343 |
|
344 |
|
345 TFileDetails::TFileDetails(RFile& aFile, RFs& aFs, const TDesC& aFilename) |
|
346 : iFile(&aFile), iFileServ(&aFs), iFilename(&aFilename) |
|
347 {} |
|
348 |
|
349 RFile* TFileDetails::File() |
|
350 { return iFile; } |
|
351 |
|
352 RFs* TFileDetails::FileServ() |
|
353 { return iFileServ; } |
|
354 |
|
355 const TDesC* TFileDetails::Filename() |
|
356 { return iFilename; } |
|
357 |
|
358 |
|
359 void DoCloseDeleteFile(TAny* aAny) |
|
360 // This function does not check for errors. Since we're closing down, not much |
|
361 // that we could do! |
|
362 { |
|
363 TFileDetails* fileDetails = reinterpret_cast<TFileDetails*>(aAny); |
|
364 if (fileDetails) |
|
365 { |
|
366 fileDetails->File()->Close(); |
|
367 fileDetails->FileServ()->Delete(*(fileDetails->Filename())); |
|
368 } |
|
369 } |
|
370 |
|
371 |
|
372 // Writes object data to specified file. Called from WriteToFile, exists to simplify |
|
373 // error handling as this function can leave. Leaves are trapped in the caller. |
|
374 void CObexBufObject::CopyFileL(const TDesC& aFilename) |
|
375 { |
|
376 // Open persistent connection to fileserver if don't currently |
|
377 // have one |
|
378 LEAVEIFERRORL(OpenFileServer()); |
|
379 |
|
380 RFile writeFile; |
|
381 LEAVEIFERRORL(writeFile.Create(*iFileServ, aFilename, EFileWrite | EFileShareExclusive)); |
|
382 |
|
383 TFileDetails writeFileDetails(writeFile, *iFileServ, aFilename); |
|
384 CleanupStack::PushL(TCleanupItem(DoCloseDeleteFile, &writeFileDetails)); |
|
385 |
|
386 // Now have three situations to worry about. May have a file, in which |
|
387 // case we need to copy data to the target file. If there's a buffer for |
|
388 // writes to this file, need to flush it first. |
|
389 // Then may be using a memory buffer, in which case we just need to save |
|
390 // the data. |
|
391 if (iFile) |
|
392 { |
|
393 if (iBuf) |
|
394 { |
|
395 LEAVEIFERRORL(WriteBufferToFile(ETrue)); |
|
396 iBufOffset += iBuffered; |
|
397 } |
|
398 |
|
399 TInt dataSize = DataSize(); |
|
400 TInt bufSize = Min<TInt>(dataSize, 1024); |
|
401 // Expands to TInt bufSize = (dataSize > 1024) ? 1024 : dataSize; |
|
402 HBufC8* buffer = HBufC8::NewMaxLC(bufSize); |
|
403 |
|
404 TInt written = 0; |
|
405 TPtr8 ptr = buffer->Des(); |
|
406 |
|
407 while (written < dataSize) |
|
408 { |
|
409 LEAVEIFERRORL(iFile->Read(written, ptr)); |
|
410 LEAVEIFERRORL(writeFile.Write(written, ptr)); |
|
411 written += ptr.Length(); |
|
412 } |
|
413 |
|
414 CleanupStack::PopAndDestroy(buffer); |
|
415 } |
|
416 else |
|
417 { |
|
418 TInt segmentSize = iBuf->Ptr(0).Size(); |
|
419 TInt written = 0; |
|
420 while (written < BytesReceived()) |
|
421 { |
|
422 LEAVEIFERRORL(writeFile.Write(written, iBuf->Ptr(written))); |
|
423 written += segmentSize; |
|
424 } |
|
425 } |
|
426 |
|
427 CleanupStack::Pop(); // file |
|
428 writeFile.Close(); |
|
429 } |
|
430 |
|
431 |
|
432 /** |
|
433 Build a TObexBufferingDetails object. |
|
434 @param aBuffer The CBufBase derived object for Obex to use as a data store. |
|
435 This object will be resized as appropriate to hold the entire Obex object. |
|
436 |
|
437 @publishedAll |
|
438 @released |
|
439 */ |
|
440 EXPORT_C TObexBufferingDetails::TObexBufferingDetails(CBufBase& aBuffer) |
|
441 : iVersion(EBasicBuffer), iBuffer(&aBuffer) |
|
442 { |
|
443 LOG_LINE |
|
444 LOG_FUNC |
|
445 } |
|
446 |
|
447 |
|
448 /** |
|
449 Build a TObexBufferingDetails object, setting the version appropriately. |
|
450 @param aVersion Version number to insert. |
|
451 @param aBuffer The buffer object to use. |
|
452 |
|
453 @internalComponent |
|
454 */ |
|
455 TObexBufferingDetails::TObexBufferingDetails(TVersion aVersion, CBufBase* aBuffer) |
|
456 : iVersion(aVersion), iBuffer(aBuffer) |
|
457 { |
|
458 __ASSERT_DEBUG(aVersion < ELastVersion, IrOBEXUtil::Fault(EBadBufferDetailsVersion)); |
|
459 } |
|
460 |
|
461 /** |
|
462 Return the version of this object |
|
463 @internalComponent |
|
464 */ |
|
465 TObexBufferingDetails::TVersion TObexBufferingDetails::Version() |
|
466 { |
|
467 return iVersion; |
|
468 } |
|
469 |
|
470 |
|
471 /** |
|
472 Basic getter. |
|
473 @internalComponent |
|
474 */ |
|
475 CBufBase* TObexBufferingDetails::Buffer() |
|
476 { |
|
477 return iBuffer; |
|
478 } |
|
479 |
|
480 |
|
481 /** |
|
482 Build a variant of TObexBufferingDetails which instructs the CObexBufObject |
|
483 to use a file as the only data store. This is a special case option provided |
|
484 to cater for the MObexServerNotify interface which requires the use of |
|
485 CObexBufObject objects. It is generally better to use a buffered variant. |
|
486 If the file cannot be opened for read/write access it will be opened in read |
|
487 only mode. In this situation, attempts to store data in this object will cause |
|
488 an Obex error to be signalled in response to the Obex packet which carried the |
|
489 body data. |
|
490 |
|
491 @param aFilename The file to link the object to. |
|
492 |
|
493 @publishedAll |
|
494 @released |
|
495 */ |
|
496 EXPORT_C TObexPureFileBuffer::TObexPureFileBuffer(const TPtrC& aFilename) |
|
497 : TObexBufferingDetails(EPureFile, NULL), iFilename(aFilename) |
|
498 { |
|
499 LOG_LINE |
|
500 LOG_FUNC |
|
501 } |
|
502 |
|
503 |
|
504 /** |
|
505 Basic getter. |
|
506 @internalComponent |
|
507 */ |
|
508 const TPtrC& TObexPureFileBuffer::Filename() |
|
509 { |
|
510 return iFilename; |
|
511 } |
|
512 |
|
513 |
|
514 /** |
|
515 Build a variant of TObexBufferingDetails which instructs the CObexBufObject |
|
516 to use a file as the main data store, buffering writes to this in chunks. |
|
517 Writes are buffered into the supplied CBufBase derived object, which is not |
|
518 resized. Once it is full, the data contained is written to file. |
|
519 Double buffering can be specified by setting aBufferingStrategy appropriately. |
|
520 If the file cannot be opened for read/write access it will be opened in read |
|
521 only mode. In this situation, attempts to store data in this object will cause |
|
522 an Obex error to be signalled in response to the Obex packet which carried the |
|
523 body data. |
|
524 |
|
525 @param aBuffer The buffer to use as a temporary store. This is ignored when |
|
526 reading from the file. |
|
527 @param aFilename The filename to use to permanently store the object. |
|
528 @param aBufferingStrategy Use double or single buffering. |
|
529 @publishedAll |
|
530 @released |
|
531 */ |
|
532 EXPORT_C TObexFilenameBackedBuffer::TObexFilenameBackedBuffer(CBufBase& aBuffer, const TPtrC& aFilename, CObexBufObject::TFileBuffering aBufferingStrategy) |
|
533 : TObexBufferingDetails(EFilenameBackedBuffer, &aBuffer), |
|
534 iFilename(aFilename), |
|
535 iBufferingStrategy(aBufferingStrategy) |
|
536 { |
|
537 LOG_LINE |
|
538 LOG_FUNC |
|
539 } |
|
540 |
|
541 |
|
542 /** |
|
543 Basic getter. |
|
544 @internalComponent |
|
545 */ |
|
546 const TPtrC& TObexFilenameBackedBuffer::Filename() |
|
547 { |
|
548 return iFilename; |
|
549 } |
|
550 |
|
551 |
|
552 /** |
|
553 Basic getter. |
|
554 @internalComponent |
|
555 */ |
|
556 CObexBufObject::TFileBuffering TObexFilenameBackedBuffer::Strategy() |
|
557 { |
|
558 return iBufferingStrategy; |
|
559 } |
|
560 |
|
561 |
|
562 /** |
|
563 Build a variant of TObexBufferingDetails which instructs the CObexBufObject |
|
564 to use a file as the main data store, buffering writes to this in chunks. |
|
565 Writes are buffered into the supplied CBufBase derived object, which is not |
|
566 resized. Once it is full, the data contained is written to file. |
|
567 Double buffering can be specified by setting aBufferingStrategy appropriately. |
|
568 If the file is opened in read only mode, attempts to store data in this object |
|
569 will cause an Obex error to be signalled in response to the Obex packet which |
|
570 body data. |
|
571 |
|
572 @param aBuffer The buffer to use as a temporary store. This is ignored when |
|
573 reading from the file. |
|
574 @param aFile An RFile object pointing to the file, opened in an appropriate |
|
575 access mode.Note, Obex is responsible for closing the file, and a panic will |
|
576 result if an attempt is made to close the file from outside of Obex. |
|
577 @param aBufferingStrategy Use double or single buffering. |
|
578 @publishedAll |
|
579 @released |
|
580 */ |
|
581 EXPORT_C TObexRFileBackedBuffer::TObexRFileBackedBuffer(CBufBase& aBuffer, RFile aFile, CObexBufObject::TFileBuffering aBufferingStrategy) |
|
582 : TObexBufferingDetails(ERFileBackedBuffer, &aBuffer), |
|
583 iFile(aFile), |
|
584 iBufferingStrategy(aBufferingStrategy) |
|
585 { |
|
586 LOG_LINE |
|
587 LOG_FUNC |
|
588 } |
|
589 |
|
590 |
|
591 /** |
|
592 Basic getter. |
|
593 @internalComponent |
|
594 */ |
|
595 RFile TObexRFileBackedBuffer::File() |
|
596 { |
|
597 return iFile; |
|
598 } |
|
599 |
|
600 |
|
601 /** |
|
602 Basic getter. |
|
603 @internalComponent |
|
604 */ |
|
605 CObexBufObject::TFileBuffering TObexRFileBackedBuffer::Strategy() |
|
606 { |
|
607 return iBufferingStrategy; |
|
608 } |
|
609 |
|
610 |
|
611 /** |
|
612 Set the data buffers as specified in the supplied TObexBufferingDetails object. |
|
613 @param aDetails The buffering techniques to use. This only has to persist |
|
614 over the duration of the call to SetDataBufL, once this has returned it can |
|
615 be allowed to go out of scope. |
|
616 |
|
617 @panic Obex ENullFileHandle TObexPanicCode::ENullFileHandle The RFile object does not point |
|
618 to a valid (open) file. |
|
619 @panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length. |
|
620 @panic Obex EInvalidBufferDetails TObexPanicCode::EInvalidBufferDetails An unknown TObexBufferingDetails |
|
621 object was supplied |
|
622 @panic Obex EInvalidBufferStrategy TObexPanicCode::EInvalidBufferStrategy An unknown TFileBuffering |
|
623 value was supplied. |
|
624 |
|
625 @publishedAll |
|
626 @released |
|
627 */ |
|
628 EXPORT_C void CObexBufObject::SetDataBufL(TObexBufferingDetails& aDetails) |
|
629 { |
|
630 LOG_LINE |
|
631 LOG_FUNC |
|
632 |
|
633 PrepareToSetBufferL(); |
|
634 |
|
635 iBuf = aDetails.Buffer(); |
|
636 if (iBuf) |
|
637 { |
|
638 iBufSegSize = iBuf->Ptr(0).Size(); |
|
639 } |
|
640 |
|
641 TBool initFile = EFalse; |
|
642 TBool initFileServer = EFalse; |
|
643 TBool initFileWriter = EFalse; |
|
644 TFileBuffering bufferingStrategy = ESingleBuffering; |
|
645 |
|
646 switch (aDetails.Version()) |
|
647 { |
|
648 case TObexBufferingDetails::EBasicBuffer: |
|
649 { |
|
650 // All required details already set. |
|
651 break; |
|
652 } |
|
653 |
|
654 case TObexBufferingDetails::EPureFile: |
|
655 { |
|
656 TObexPureFileBuffer& detail = static_cast<TObexPureFileBuffer&>(aDetails); |
|
657 iFilename = detail.Filename().AllocL(); |
|
658 |
|
659 initFileServer = ETrue; |
|
660 initFile = ETrue; |
|
661 break; |
|
662 } |
|
663 |
|
664 case TObexBufferingDetails::EFilenameBackedBuffer: |
|
665 { |
|
666 __ASSERT_ALWAYS(iBuf, IrOBEXUtil::Panic(ENullPointer)); |
|
667 __ASSERT_ALWAYS(iBuf->Size(), IrOBEXUtil::Panic(EEmptyBuffer)); |
|
668 |
|
669 TObexFilenameBackedBuffer& detail = static_cast<TObexFilenameBackedBuffer&>(aDetails); |
|
670 |
|
671 iFilename = detail.Filename().AllocL(); |
|
672 bufferingStrategy = detail.Strategy(); |
|
673 |
|
674 initFileServer = ETrue; |
|
675 initFile = ETrue; |
|
676 initFileWriter = ETrue; |
|
677 break; |
|
678 } |
|
679 |
|
680 case TObexBufferingDetails::ERFileBackedBuffer: |
|
681 { |
|
682 __ASSERT_ALWAYS(iBuf, IrOBEXUtil::Panic(ENullPointer)); |
|
683 __ASSERT_ALWAYS(iBuf->Size(), IrOBEXUtil::Panic(EEmptyBuffer)); |
|
684 |
|
685 TObexRFileBackedBuffer& detail = static_cast<TObexRFileBackedBuffer&>(aDetails); |
|
686 __ASSERT_ALWAYS(detail.File().SubSessionHandle(), IrOBEXUtil::Panic(ENullFileHandle)); |
|
687 |
|
688 iFile = new(ELeave) RFile(detail.File()); |
|
689 bufferingStrategy = detail.Strategy(); |
|
690 |
|
691 initFileServer = ETrue; |
|
692 initFileWriter = ETrue; |
|
693 break; |
|
694 } |
|
695 |
|
696 default: |
|
697 { |
|
698 IrOBEXUtil::Panic(EInvalidBufferDetails); |
|
699 } |
|
700 } |
|
701 |
|
702 if (initFileServer) |
|
703 { |
|
704 LEAVEIFERRORL(OpenFileServer()); |
|
705 } |
|
706 |
|
707 if (initFile) |
|
708 { |
|
709 LEAVEIFERRORL(OpenDataFile(*iFilename)); |
|
710 } |
|
711 |
|
712 if (initFileWriter) |
|
713 { |
|
714 switch (bufferingStrategy) |
|
715 { |
|
716 case ESingleBuffering: |
|
717 iWriter = CObexSyncFileWriter::NewL(*iFile); |
|
718 break; |
|
719 |
|
720 case EDoubleBuffering: |
|
721 iWriter = CObexAsyncFileWriter::NewL(*iFile); |
|
722 iDoubleBuf = CBufFlat::NewL(iBufSegSize); |
|
723 iDoubleBuf->ResizeL(iBufSegSize); |
|
724 break; |
|
725 |
|
726 default: |
|
727 IrOBEXUtil::Panic(EInvalidBufferStrategy); |
|
728 break; |
|
729 } |
|
730 } |
|
731 } |
|
732 |
|
733 |
|
734 /** |
|
735 Delete all owned resources in preparation for getting new settings. |
|
736 @internalComponent |
|
737 */ |
|
738 void CObexBufObject::PrepareToSetBufferL() |
|
739 { |
|
740 // Flush file buffer, if any. |
|
741 if (iFile && iBuf) |
|
742 { |
|
743 LEAVEIFERRORL(WriteBufferToFile(ETrue)); |
|
744 iBufOffset = 0; |
|
745 } |
|
746 |
|
747 // The writer must be deleted at the same time as or before the file |
|
748 // otherwise the writer will have an invalid file handle |
|
749 delete iWriter; |
|
750 iWriter = NULL; |
|
751 |
|
752 CloseDataFile(); |
|
753 |
|
754 delete iFilename; |
|
755 iFilename = NULL; |
|
756 |
|
757 delete iDoubleBuf; |
|
758 iDoubleBuf = NULL; |
|
759 |
|
760 iBuf = NULL; |
|
761 } |
|
762 |
|
763 |
|
764 /** |
|
765 Sets a buffer to use the object body data. |
|
766 |
|
767 Note that the function can leave. |
|
768 |
|
769 @param aDataBuf The buffer for the body of the object. |
|
770 @panic Obex ENullPointer TObexPanicCode::ENullPointer A NULL value was supplied for the |
|
771 data buffer. |
|
772 |
|
773 @publishedAll |
|
774 @deprecated |
|
775 */ |
|
776 EXPORT_C void CObexBufObject::SetDataBufL(CBufBase* aDataBuf) |
|
777 { |
|
778 LOG_LINE |
|
779 LOG_FUNC |
|
780 |
|
781 __ASSERT_ALWAYS(aDataBuf, IrOBEXUtil::Panic(ENullPointer)); |
|
782 TObexBufferingDetails details(*aDataBuf); |
|
783 SetDataBufL(details); |
|
784 } |
|
785 |
|
786 |
|
787 /** |
|
788 Set object to use aFilename as its data area. Leaves if unable to open file. |
|
789 |
|
790 @param aFilename The filename to link the object to. |
|
791 |
|
792 @publishedAll |
|
793 @deprecated |
|
794 */ |
|
795 EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename) |
|
796 { |
|
797 LOG_LINE |
|
798 LOG_FUNC |
|
799 |
|
800 TObexPureFileBuffer details(aFilename); |
|
801 SetDataBufL(details); |
|
802 } |
|
803 |
|
804 |
|
805 /** |
|
806 Set object to use aFilename as its data area. Leaves if unable to open file. |
|
807 Buffers data into aDataBuf before writing to file. Will not grow the memory buffer, |
|
808 so user can tune buffering behaviour when calling function. |
|
809 |
|
810 @param aFilename The filename to link the object to. |
|
811 @param aDataBuf The buffer for the body of the object. |
|
812 @panic Obex ENullPointer TObexPanicCode::ENullPointer A NULL value was supplied for the |
|
813 data buffer. |
|
814 @panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length. |
|
815 |
|
816 @publishedAll |
|
817 @deprecated |
|
818 */ |
|
819 EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename, CBufBase* aDataBuf) |
|
820 { |
|
821 LOG_LINE |
|
822 LOG_FUNC |
|
823 |
|
824 __ASSERT_ALWAYS(aDataBuf, IrOBEXUtil::Panic(ENullPointer)); |
|
825 TObexFilenameBackedBuffer details(*aDataBuf, aFilename, ESingleBuffering); |
|
826 SetDataBufL(details); |
|
827 } |
|
828 |
|
829 |
|
830 /** |
|
831 Set object to write to file, using buffering and the specified |
|
832 buffering strategy. Note the size of the buffer passed to this |
|
833 function will determine the size of the second buffer if double |
|
834 buffering is employed. |
|
835 |
|
836 @param aFilename The file to link the object to. |
|
837 @param aDataBuf A buffer to use. |
|
838 @param aBufferingStrategy The buffering strategy to employ. |
|
839 @panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length. |
|
840 @panic Obex EInvalidBufferStrategy TObexPanicCode::EInvalidBufferStrategy An unknown TFileBuffering |
|
841 |
|
842 @publishedAll |
|
843 @deprecated |
|
844 */ |
|
845 EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename, CBufBase& aDataBuf, const TFileBuffering aBufferingStrategy) |
|
846 { |
|
847 LOG_LINE |
|
848 LOG_FUNC |
|
849 |
|
850 TObexFilenameBackedBuffer details(aDataBuf, aFilename, aBufferingStrategy); |
|
851 SetDataBufL(details); |
|
852 } |
|
853 |
|
854 |
|
855 /** |
|
856 Gets the buffer. |
|
857 |
|
858 @return The buffer for the body of the object. |
|
859 |
|
860 @publishedAll |
|
861 @released |
|
862 */ |
|
863 EXPORT_C CBufBase* CObexBufObject::DataBuf() |
|
864 { |
|
865 LOG_LINE |
|
866 LOG_FUNC |
|
867 |
|
868 return(iBuf); |
|
869 } |
|
870 |
|
871 |
|
872 /** |
|
873 Returns a pointer to the HBuf holding the filename this object is using. |
|
874 May return a null pointer. |
|
875 @return iFilename The file name. |
|
876 @internalComponent |
|
877 */ |
|
878 HBufC* CObexBufObject::FileName() |
|
879 { |
|
880 return(iFilename); |
|
881 } |
|
882 |
|
883 |
|
884 CObexBufObject::CObexBufObject() |
|
885 { |
|
886 } |
|
887 |
|
888 void CObexBufObject::ConstructL(CBufBase* aDataBuf) |
|
889 { |
|
890 CreateHeaderStorageDataL(); |
|
891 if (aDataBuf) |
|
892 SetDataBufL(aDataBuf); |
|
893 } |
|
894 |
|
895 /** |
|
896 Reads aDes (up to MaxLength) from aPos offset into the buffer |
|
897 |
|
898 @param aPos The offset into the buffer to read from |
|
899 @param aDes The descriptor to read from |
|
900 */ |
|
901 void CObexBufObject::GetData(TInt aPos, TDes8& aDes) |
|
902 { |
|
903 __ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer)); |
|
904 |
|
905 if (iFile) |
|
906 { |
|
907 GetFileData(aPos, aDes); |
|
908 } |
|
909 else |
|
910 { |
|
911 iBuf->Read(aPos, aDes); |
|
912 } |
|
913 } |
|
914 |
|
915 void CObexBufObject::GetFileData(TInt aPos, TDes8& aDes) |
|
916 { |
|
917 if(iFile->Read(aPos, aDes) == KErrNone) |
|
918 return; |
|
919 aDes.SetLength(0); |
|
920 } |
|
921 |
|
922 /** |
|
923 Writes aDes into the buffer at aPos offset, growing the buffer if necessary |
|
924 */ |
|
925 void CObexBufObject::NewData(TInt aPos, TDes8& aDes) |
|
926 { |
|
927 // Three possible cases here. Can either be receiving into a memory |
|
928 // buffer (old behaviour), receiving directly into a file or buffering |
|
929 // file writes into a fixed size buffer. |
|
930 |
|
931 // Should always have at least one of iBuf or iFile set. |
|
932 __ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer)); |
|
933 |
|
934 if (iFile) |
|
935 { |
|
936 TInt err = NewFileData(aPos, aDes); |
|
937 if (err != KErrNone) |
|
938 { |
|
939 LOG1(_L8("Couldn't write data to file (error %d)"), err); |
|
940 aDes.SetLength(0); |
|
941 return; |
|
942 } |
|
943 } |
|
944 else |
|
945 { |
|
946 if(iBuf->Size() < aPos + aDes.Size()) |
|
947 {// Buffer needs to grow. Try to guess how big it needs to be. |
|
948 TInt reqsz = aPos + aDes.Size(); |
|
949 if((TInt)Length() > reqsz) |
|
950 reqsz = Length(); |
|
951 TRAPD(err, iBuf->ResizeL(reqsz)); |
|
952 if(err != KErrNone) |
|
953 {// OOM, probably. |
|
954 LOG2(_L8("Couldn't resize buffer object to %d bytes (error %d)"), |
|
955 reqsz, err); |
|
956 iBuf->Compress(); |
|
957 aDes.SetLength(0); |
|
958 return; |
|
959 } |
|
960 } |
|
961 iBuf->Write(aPos, aDes); |
|
962 } |
|
963 } |
|
964 |
|
965 |
|
966 /** |
|
967 Write new data into a file |
|
968 |
|
969 We write data out to the file in chunks of iBufSegSize, |
|
970 the (segment) size of the buffer. A packet of data is |
|
971 passed to this method in aDes. aDes may or may not take |
|
972 us past the the end of the buffer. If it does, then we |
|
973 write out the buffer then continue filling it up with |
|
974 the rest of aDes. We repeat this until we have used up |
|
975 all of aDes. iBufOffset is the last write position in |
|
976 the file. remaining is the amount of data in aDes yet to |
|
977 be processed, written is the amount of data in aDes that |
|
978 has been processed. iBuffered is the amount of data in |
|
979 iBuf and spare is the amount of free space in the buffer. |
|
980 |
|
981 @code |
|
982 aDes.Length() |
|
983 <----------------------> |
|
984 ------------------------------------------------------------------------ |
|
985 | ... |xxxxxxxxxxxx|\\\\\\\\\\|//|*************| ... | |
|
986 | ... |xxxxxxxxxxxx|\\\\\\\\\\|//|*************| ... | |
|
987 ------------------------------------------------------------------------ |
|
988 0 ... iBufOffset aPos ... this.Length() |
|
989 |
|
990 written remaining |
|
991 <---------><-----------> |
|
992 |
|
993 iBuffered spare |
|
994 <----------------------><------------------------> |
|
995 |
|
996 iBufSegSize |
|
997 <------------------------------------------------> |
|
998 |
|
999 Key: |
|
1000 xxx = data already in buffer |
|
1001 \\\ = processed data from aDes, copied into iBuf |
|
1002 // = unprocessed data from aDes, not yet copied into iBuf |
|
1003 *** = free space in iBuf |
|
1004 @endcode |
|
1005 |
|
1006 If there is more data remaining than there is spare space in |
|
1007 the buffer, then the buffer is filled and written to disk and |
|
1008 the remainer of the data is then used to continue filling the |
|
1009 buffer. |
|
1010 |
|
1011 @param aPos The position at which aDes is to be written into the file. |
|
1012 @param aDes The data to write to the file. |
|
1013 @return Symbian OS error code |
|
1014 */ |
|
1015 TInt CObexBufObject::NewFileData(TInt aPos, TDes8& aDes) |
|
1016 { |
|
1017 // We have a memory buffer to (hopefully) speed file writes. |
|
1018 if (iBuf) |
|
1019 { |
|
1020 TInt err = KErrNone; |
|
1021 |
|
1022 // If moving to earlier position in object, write out buffer |
|
1023 if (iBuffered && (aPos < iBufOffset)) |
|
1024 { |
|
1025 err = WriteBufferToFile(EFalse); |
|
1026 if (err) return err; |
|
1027 } |
|
1028 |
|
1029 TInt written = 0; |
|
1030 TInt remaining; |
|
1031 |
|
1032 // Calculate the amount of data still to be processed and |
|
1033 // continue whilst there is still data to process |
|
1034 while ((remaining = (aDes.Length() - written)) > 0) |
|
1035 { |
|
1036 // Buffer full, write to file |
|
1037 if (iBuffered == iBufSegSize) |
|
1038 { |
|
1039 err = WriteBufferToFile(EFalse); |
|
1040 if (err) return err; |
|
1041 } |
|
1042 |
|
1043 // Buffer empty, update buffer base |
|
1044 if (iBuffered == 0) |
|
1045 { |
|
1046 iBufOffset = aPos + written; |
|
1047 } |
|
1048 |
|
1049 // Calculate the remaining space in the buffer (spare) and |
|
1050 // hence the amount of data we can process (length) |
|
1051 TInt spare = iBufSegSize - iBuffered; |
|
1052 TInt length = (spare > remaining) ? remaining : spare; |
|
1053 |
|
1054 // Copy amount of data to be procesed (length) from the |
|
1055 // unprocessed portion of the packet (aDes.Right(remaining)) |
|
1056 // into the buffer. |
|
1057 iBuf->Write(iBuffered, aDes.Right(remaining), length); |
|
1058 |
|
1059 // Update variables to reflect newly processed data |
|
1060 written += length; |
|
1061 iBuffered += length; |
|
1062 } |
|
1063 |
|
1064 // Is this the final packet? |
|
1065 const TBool finalPacket = (ValidHeaders() & KObexHdrEndOfBody); |
|
1066 |
|
1067 // Flush buffer to file if we're done and there's data left |
|
1068 if (finalPacket && iBuffered) |
|
1069 { |
|
1070 err = WriteBufferToFile(ETrue); |
|
1071 iBufOffset = 0; |
|
1072 |
|
1073 if (err) return err; |
|
1074 } |
|
1075 } |
|
1076 else |
|
1077 // Just write directly to the file |
|
1078 { |
|
1079 return iFile->Write(aPos, aDes); |
|
1080 } |
|
1081 |
|
1082 return KErrNone; |
|
1083 } |
|
1084 |
|
1085 |
|
1086 TInt CObexBufObject::DataSize() |
|
1087 { |
|
1088 __ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer)); |
|
1089 if (iFile) |
|
1090 { |
|
1091 // Flush file buffer, if any. |
|
1092 if (iBuf) |
|
1093 { |
|
1094 (void) WriteBufferToFile(ETrue); |
|
1095 } |
|
1096 // Get file size |
|
1097 TInt size; |
|
1098 iFile->Size(size); |
|
1099 return size; |
|
1100 } |
|
1101 else |
|
1102 { |
|
1103 return (iBuf->Size()); |
|
1104 } |
|
1105 } |
|
1106 |
|
1107 void CObexBufObject::ResetData() |
|
1108 { |
|
1109 __ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer)); |
|
1110 if (iFile) |
|
1111 { |
|
1112 iFile->SetSize(0); |
|
1113 if (iBuf) |
|
1114 { |
|
1115 iBufOffset = 0; |
|
1116 iBuffered = 0; |
|
1117 } |
|
1118 } |
|
1119 else |
|
1120 { |
|
1121 iBuf->Reset(); |
|
1122 } |
|
1123 } |
|
1124 |
|
1125 |
|
1126 TInt CObexBufObject::OpenDataFile(const TDesC& aFilename) |
|
1127 { |
|
1128 TInt err = KErrNotReady; |
|
1129 |
|
1130 if (!iFile) |
|
1131 { |
|
1132 iFile = new RFile; |
|
1133 if (!iFile) return KErrNoMemory; |
|
1134 |
|
1135 //Try and open the file for read/write |
|
1136 err = iFile->Open(*iFileServ, aFilename, EFileWrite | EFileShareExclusive); |
|
1137 if (err != KErrNone) |
|
1138 { |
|
1139 //Try and open file for read only |
|
1140 err = iFile->Open(*iFileServ, aFilename, EFileRead | EFileShareReadersOnly); |
|
1141 if(err == KErrNotFound) |
|
1142 { |
|
1143 err = iFile->Create(*iFileServ, aFilename, EFileWrite | EFileShareExclusive); |
|
1144 } |
|
1145 } |
|
1146 |
|
1147 if (err) |
|
1148 { |
|
1149 delete iFile; |
|
1150 iFile = 0; |
|
1151 } |
|
1152 } |
|
1153 |
|
1154 return err; |
|
1155 } |
|
1156 |
|
1157 |
|
1158 void CObexBufObject::CloseDataFile() |
|
1159 { |
|
1160 if (iFile) |
|
1161 { |
|
1162 iFile->Close(); |
|
1163 delete iFile; |
|
1164 iFile = 0; |
|
1165 } |
|
1166 } |
|
1167 |
|
1168 TInt CObexBufObject::OpenFileServer() |
|
1169 { |
|
1170 TInt err = KErrNone; |
|
1171 |
|
1172 if (!iFileServ) |
|
1173 { |
|
1174 iFileServ = new RFs; |
|
1175 if (!iFileServ) return KErrNoMemory; |
|
1176 |
|
1177 err = iFileServ->Connect(); |
|
1178 if (err) |
|
1179 { |
|
1180 delete iFileServ; |
|
1181 iFileServ = 0; |
|
1182 } |
|
1183 } |
|
1184 return err; |
|
1185 } |
|
1186 |
|
1187 void CObexBufObject::CloseFileServer() |
|
1188 { |
|
1189 if (iFileServ) |
|
1190 { |
|
1191 iFileServ->Close(); |
|
1192 delete iFileServ; |
|
1193 iFileServ = 0; |
|
1194 } |
|
1195 } |
|
1196 |
|
1197 TInt CObexBufObject::WriteBufferToFile(TBool aFinal) |
|
1198 { |
|
1199 TInt err = KErrNone; |
|
1200 |
|
1201 if (aFinal) |
|
1202 { |
|
1203 err = iWriter->FinalWrite(iBufOffset, iBuf, iBuffered); |
|
1204 } |
|
1205 else |
|
1206 { |
|
1207 err = iWriter->Write(iBufOffset, iBuf); |
|
1208 } |
|
1209 |
|
1210 if (!iBuf && iDoubleBuf) |
|
1211 { |
|
1212 iBuf = iDoubleBuf; |
|
1213 } |
|
1214 |
|
1215 iBuffered = 0; |
|
1216 |
|
1217 return err; |
|
1218 } |
|
1219 |
|
1220 // |
|
1221 // class CObexNullObject |
|
1222 // |
|
1223 void CObexNullObject::ConstructL() |
|
1224 { |
|
1225 CreateHeaderStorageDataL(); |
|
1226 } |
|
1227 |
|
1228 /** Allocates and constructs a new null object. |
|
1229 |
|
1230 @return New null object |
|
1231 |
|
1232 @publishedAll |
|
1233 @released |
|
1234 */ |
|
1235 EXPORT_C CObexNullObject* CObexNullObject::NewL() |
|
1236 { |
|
1237 LOG_LINE |
|
1238 LOG_STATIC_FUNC_ENTRY |
|
1239 |
|
1240 CObexNullObject* self = new(ELeave) CObexNullObject; |
|
1241 CleanupStack::PushL(self); |
|
1242 self->ConstructL(); |
|
1243 CleanupStack::Pop(); |
|
1244 return(self); |
|
1245 } |
|
1246 |
|
1247 /** |
|
1248 To return "NULL" data, we simply set aDes.Size = 0 |
|
1249 */ |
|
1250 void CObexNullObject::GetData(TInt /*aPos*/, TDes8& aDes) |
|
1251 { |
|
1252 aDes.SetLength(0); |
|
1253 return; |
|
1254 } |
|
1255 |
|
1256 /** |
|
1257 In order to appear to consume the data, we don't set aDes.Size = 0 |
|
1258 */ |
|
1259 void CObexNullObject::NewData(TInt /*aPos*/, TDes8& /*aDes*/) |
|
1260 { |
|
1261 return; |
|
1262 } |
|
1263 |
|
1264 TInt CObexNullObject::DataSize() |
|
1265 { |
|
1266 return(0); |
|
1267 } |
|
1268 |
|
1269 void CObexNullObject::ResetData() |
|
1270 { |
|
1271 } |