obex/obexprotocol/obex/src/obexobjects.cpp
changeset 0 d0791faffa3f
equal deleted inserted replaced
-1:000000000000 0:d0791faffa3f
       
     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 	}