obex/obexprotocol/obex/src/obexobjects.cpp
changeset 0 d0791faffa3f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/obex/obexprotocol/obex/src/obexobjects.cpp	Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,1271 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <obex.h>
+#include <obexpanics.h>
+#include "logger.h"
+#include "OBEXUTIL.H"
+#include "obexasyncfilewriter.h"
+#include "obexsyncfilewriter.h"
+#include "obexfaults.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "OBEX");
+#endif
+
+/** Creates a new CObexFileObject object.
+Static file object factory. returns a new CObexFileObject, set up to use a 
+temporary file  to store received data into "on the fly". If used for 
+sourcing an object to send a "NULL" object(body length 0) will be sent.
+@return Instance of CObexFileObject 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexFileObject* CObexFileObject::NewL()
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	CObexFileObject* self = new(ELeave) CObexFileObject;
+	CleanupStack::PushL(self);
+	self->ConstructL(TPtrC(NULL, 0));
+	CleanupStack::Pop();
+	return(self);
+	}
+
+/** Creates a new CObexFileObject object.
+Static file object factory. returns a new CObexFileObject, set up to use
+aDataFile as its data file, or will create a temp file if aDataFile is not
+a valid file name. If used for sourcing an object to send, and no valid data
+file is set, a "NULL" object(body length 0) will be sent.
+@param aDataFile Filename to configure this object to use
+@return Instance of CObexFileObject 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexFileObject* CObexFileObject::NewL(const TDesC &aDataFile)
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	CObexFileObject* self = new(ELeave) CObexFileObject;
+	CleanupStack::PushL(self);
+	self->ConstructL(aDataFile);
+	CleanupStack::Pop();
+	return(self);
+	}
+
+/** Destructor. 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexFileObject::~CObexFileObject()
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	ResetData();
+	iFs.Close();
+	}
+
+/**
+Sets the name of a file which holds the data to be used as the objects body.
+Leaves if the file does not exist, or can not be opened for writing.
+
+@param aDesc Filename to configure this object to use
+*/
+void CObexFileObject::SetDataFileL(const TDesC& aDesc)// does this need to be exported????
+	{
+	ResetData();
+	if(aDesc.Length() == 0)
+		return;
+	TInt err = iDataFile.SetNoWild(aDesc, NULL, NULL);
+	if(err == KErrNone) //try and open for read/write
+ 		err = iFile.Open(iFs, iDataFile.FullName(), EFileWrite  | EFileShareExclusive);
+ 	if(err != KErrNone)
+		{			//can't open it for write so open it for read
+		err = iFile.Open(iFs, iDataFile.FullName(), EFileRead  | EFileShareReadersOnly);
+		if(err != KErrNone)
+			{
+			iDataFile.SetNoWild(KNullDesC, NULL, NULL);
+			iFile.Close();	// Manually close file
+			User::Leave(err);
+			}
+		}
+	}
+
+/** 
+Get the name of the file representing the object body.
+
+@return	the full path and name of the file representing the object body.
+		Null descriptor	if no valid data file has been set, or if Reset()
+		has been called on the object since a file was last set.
+*/
+const TDesC& CObexFileObject::DataFile()
+	{
+	return iDataFile.FullName();
+	}
+
+TInt CObexFileObject::RenameFile(const TDesC& aDesC)
+	{
+	iFile.SetAtt(0,KEntryAttHidden);// - dont check return code - if it fails it fails
+	return(iFile.Rename(aDesC));
+	}
+
+void CObexFileObject::SetTempFilePath(const TDesC& aPath)
+	{
+	iTempFilePath = aPath;
+	}
+
+void CObexFileObject::QueryTempFilePath(TDes& aPath)
+	{
+	aPath = iTempFilePath;
+	}
+
+/**
+Constructs this object.
+
+@param aDataFile The file to use for the object's data part.
+*/
+void CObexFileObject::ConstructL(const TDesC &aDataFile)
+	{
+	CreateHeaderStorageDataL();
+	LEAVEIFERRORL(iFs.Connect());
+	SetDataFileL(aDataFile);
+	iTempFilePath = KNullDesC; 
+	}
+
+/** Initialises this object from the specified file. 
+
+The function attempts to set attribute values for the object as follows:
+
+Length:set to the length of the file
+
+Name:taken from the name portion of the path in aFile
+
+Time:taken from the modification time of the file
+
+Type:set appropriately if the file extension is .vcf (VCard), .vcs (Vcalendar), 
+or .txt.
+
+@param aFile Body data file 	
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexFileObject::InitFromFileL(const TDesC& aFile)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	Reset();
+	SetDataFileL(aFile);
+		
+
+	SetNameL(iDataFile.NameAndExt());
+	GuessTypeFromExtL(iDataFile.Ext());
+	
+	TInt length;
+	if(iFile.Size(length) == KErrNone)
+		{
+		SetLengthL(length);
+		}
+	
+	TTime time;
+	if(iFile.Modified(time) == KErrNone)
+		{
+		SetUtcTimeL(time);
+		}
+	}
+
+
+/**
+Virtual pure function form the base object. Tries to fill aDes with data 
+starting from aPos byte offset. returns null descriptor if no data file is 
+set. 
+@param aPos Position (reliative to start of object) to start extracting data from
+@param aDes Descriptor to fill
+*/
+void CObexFileObject::GetData(TInt aPos, TDes8& aDes)
+	{
+	if(iDataFile.NameOrExtPresent() && iFile.Read(aPos, aDes) == KErrNone)
+		return;
+	aDes.SetLength(0);
+	}
+
+/**
+Virtual pure function overload. inserts aDes into the data file at location 
+aPos 
+@param aPos Position (reliative to start of object) to start inserting data from
+@param aDes Descriptor to insert
+*/
+void CObexFileObject::NewData(TInt aPos, TDes8& aDes)
+	{
+//	iTempFilePath.SetLength(0);
+	if(!iDataFile.NameOrExtPresent())
+		{
+		ResetData();
+		TFileName fname;
+		TInt err = iFile.Temp(iFs, iTempFilePath, fname, EFileWrite | EFileShareExclusive);
+		if(err == KErrNone)
+			err = iFs.Parse(fname, iDataFile.Path(), iDataFile);
+		if(err != KErrNone)
+			{
+			ResetData();
+			iFs.Delete(fname);
+			aDes.SetLength(0);
+			return;
+			}
+		iFile.SetAtt(KEntryAttHidden,0);// dont check return code - if it fails it fails
+		}
+	if(iFile.Write(aPos, aDes) != KErrNone)
+		aDes.SetLength(0);
+	}
+
+/**
+@return number of bytes in the data file (0 if no file is set)
+*/
+TInt CObexFileObject::DataSize()
+	{
+	if(!iDataFile.NameOrExtPresent())
+		return(0);
+	TInt size = 0;
+	iFile.Size(size);
+	return(size);
+	}
+
+/**
+Set object back to a null file.
+*/
+void CObexFileObject::ResetData()
+	{
+	iFile.Close();
+	iDataFile.Set(KNullDesC, NULL, NULL);
+	}
+
+//
+// class CObexBufObject
+//
+
+/**
+Allocates and constructs a new OBEX dynamic buffer object, specifying a buffer.
+
+@param aDataBuf The buffer for the body of the object. This must be set either
+	   by this constructor or by calling SetDataBufL() before using the object.
+@return New OBEX dynamic buffer object 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexBufObject* CObexBufObject::NewL(CBufBase* aDataBuf)
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	CObexBufObject* self = new(ELeave) CObexBufObject;
+	CleanupStack::PushL(self);
+	self->ConstructL(aDataBuf);
+	CleanupStack::Pop();
+	return(self);
+	}
+
+/** Destructor. 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexBufObject::~CObexBufObject()
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	delete iWriter;
+	
+	CloseDataFile();
+	CloseFileServer();
+
+	delete iFilename;
+	
+	delete iDoubleBuf;
+	}
+
+/** Writes contents of object to a file
+@param aFileName Target file
+@return a Symbian OS error code if file write fails. 
+	
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexBufObject::WriteToFile(const TPtrC& aFileName)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	TInt ret = KErrNone;
+	TRAP(ret, CopyFileL(aFileName));
+	return ret;
+	}
+
+
+NONSHARABLE_CLASS(TFileDetails)
+	{
+public:
+	TFileDetails(RFile& aFile, RFs& aFs, const TDesC& aFilename);
+	inline RFile* File();
+	inline RFs* FileServ();
+	inline const TDesC* Filename();
+
+private:
+	RFile* iFile;
+	RFs* iFileServ;
+	const TDesC* iFilename;
+	};
+
+
+TFileDetails::TFileDetails(RFile& aFile, RFs& aFs, const TDesC& aFilename)
+	: iFile(&aFile), iFileServ(&aFs), iFilename(&aFilename)
+	{}
+
+RFile* TFileDetails::File()
+	{ return iFile; }
+
+RFs* TFileDetails::FileServ()
+	{ return iFileServ; }
+
+const TDesC* TFileDetails::Filename()
+	{ return iFilename; }
+
+
+void DoCloseDeleteFile(TAny* aAny)
+// This function does not check for errors. Since we're closing down, not much
+// that we could do!
+	{
+	TFileDetails* fileDetails = reinterpret_cast<TFileDetails*>(aAny);
+	if (fileDetails)
+		{
+		fileDetails->File()->Close();
+		fileDetails->FileServ()->Delete(*(fileDetails->Filename()));
+		}
+	}
+
+
+// Writes object data to specified file.  Called from WriteToFile, exists to simplify
+// error handling as this function can leave.  Leaves are trapped in the caller.
+void CObexBufObject::CopyFileL(const TDesC& aFilename)
+	{
+	// Open persistent connection to fileserver if don't currently
+	// have one
+	LEAVEIFERRORL(OpenFileServer());
+
+	RFile writeFile;
+	LEAVEIFERRORL(writeFile.Create(*iFileServ, aFilename, EFileWrite  | EFileShareExclusive));
+
+	TFileDetails writeFileDetails(writeFile, *iFileServ, aFilename);
+	CleanupStack::PushL(TCleanupItem(DoCloseDeleteFile, &writeFileDetails));
+
+	// Now have three situations to worry about.  May have a file, in which
+	// case we need to copy data to the target file.  If there's a buffer for
+	// writes to this file, need to flush it first.
+	// Then may be using a memory buffer, in which case we just need to save
+	// the data.
+	if (iFile)
+		{
+		if (iBuf)
+			{
+			LEAVEIFERRORL(WriteBufferToFile(ETrue));
+			iBufOffset += iBuffered;
+			}
+
+		TInt dataSize = DataSize();
+		TInt bufSize = Min<TInt>(dataSize, 1024);
+			// Expands to TInt bufSize = (dataSize > 1024) ? 1024 : dataSize;
+		HBufC8* buffer = HBufC8::NewMaxLC(bufSize);
+
+		TInt written = 0;
+		TPtr8 ptr = buffer->Des();
+
+		while (written < dataSize)
+			{
+			LEAVEIFERRORL(iFile->Read(written, ptr));
+			LEAVEIFERRORL(writeFile.Write(written, ptr));
+			written += ptr.Length();
+			}
+
+		CleanupStack::PopAndDestroy(buffer); 
+		}
+	else
+		{
+		TInt segmentSize = iBuf->Ptr(0).Size();
+		TInt written = 0;
+		while (written < BytesReceived())
+			{
+			LEAVEIFERRORL(writeFile.Write(written, iBuf->Ptr(written)));
+		    written += segmentSize;
+			}
+		}
+
+	CleanupStack::Pop(); // file
+	writeFile.Close();
+	}
+
+
+/**
+Build a TObexBufferingDetails object.
+@param aBuffer The CBufBase derived object for Obex to use as a data store.
+	   This object will be resized as appropriate to hold the entire Obex object.
+
+@publishedAll
+@released
+*/
+EXPORT_C TObexBufferingDetails::TObexBufferingDetails(CBufBase& aBuffer)
+	: iVersion(EBasicBuffer), iBuffer(&aBuffer) 
+	{
+	LOG_LINE
+	LOG_FUNC
+	}
+
+
+/**
+Build a TObexBufferingDetails object, setting the version appropriately.
+@param aVersion Version number to insert.
+@param aBuffer The buffer object to use.
+
+@internalComponent
+*/
+TObexBufferingDetails::TObexBufferingDetails(TVersion aVersion, CBufBase* aBuffer)
+	: iVersion(aVersion), iBuffer(aBuffer)
+	{
+	__ASSERT_DEBUG(aVersion < ELastVersion, IrOBEXUtil::Fault(EBadBufferDetailsVersion));
+	}
+
+/**
+Return the version of this object
+@internalComponent
+*/
+TObexBufferingDetails::TVersion TObexBufferingDetails::Version()
+ 	{
+ 	return iVersion;
+ 	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+CBufBase* TObexBufferingDetails::Buffer()
+	{
+	return iBuffer;
+	}
+
+
+/**
+Build a variant of TObexBufferingDetails which instructs the CObexBufObject
+to use a file as the only data store.  This is a special case option provided
+to cater for the MObexServerNotify interface which requires the use of
+CObexBufObject objects.  It is generally better to use a buffered variant.
+If the file cannot be opened for read/write access it will be opened in read
+only mode.  In this situation, attempts to store data in this object will cause
+an Obex error to be signalled in response to the Obex packet which carried the
+body data.
+
+@param aFilename The file to link the object to.
+
+@publishedAll
+@released
+*/
+EXPORT_C TObexPureFileBuffer::TObexPureFileBuffer(const TPtrC& aFilename)
+	: TObexBufferingDetails(EPureFile, NULL), iFilename(aFilename)
+	{
+	LOG_LINE
+	LOG_FUNC
+	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+const TPtrC& TObexPureFileBuffer::Filename()
+	{
+	return iFilename;
+	}
+
+
+/**
+Build a variant of TObexBufferingDetails which instructs the CObexBufObject
+to use a file as the main data store, buffering writes to this in chunks.
+Writes are buffered into the supplied CBufBase derived object, which is not
+resized.  Once it is full, the data contained is written to file.
+Double buffering can be specified by setting aBufferingStrategy appropriately.
+If the file cannot be opened for read/write access it will be opened in read
+only mode.  In this situation, attempts to store data in this object will cause
+an Obex error to be signalled in response to the Obex packet which carried the
+body data.
+
+@param aBuffer The buffer to use as a temporary store.  This is ignored when
+	   reading from the file.
+@param aFilename The filename to use to permanently store the object.
+@param aBufferingStrategy Use double or single buffering.
+@publishedAll
+@released
+*/
+EXPORT_C TObexFilenameBackedBuffer::TObexFilenameBackedBuffer(CBufBase& aBuffer, const TPtrC& aFilename, CObexBufObject::TFileBuffering aBufferingStrategy)
+	: TObexBufferingDetails(EFilenameBackedBuffer, &aBuffer),
+	  iFilename(aFilename),
+	  iBufferingStrategy(aBufferingStrategy)
+	{
+	LOG_LINE
+	LOG_FUNC
+	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+const TPtrC& TObexFilenameBackedBuffer::Filename()
+	{
+	return iFilename;
+	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+CObexBufObject::TFileBuffering TObexFilenameBackedBuffer::Strategy()
+	{
+	return iBufferingStrategy;
+	}
+
+
+/**
+Build a variant of TObexBufferingDetails which instructs the CObexBufObject
+to use a file as the main data store, buffering writes to this in chunks.
+Writes are buffered into the supplied CBufBase derived object, which is not
+resized.  Once it is full, the data contained is written to file.
+Double buffering can be specified by setting aBufferingStrategy appropriately.
+If the file is opened in read only mode, attempts to store data in this object
+will cause an Obex error to be signalled in response to the Obex packet which
+body data.
+
+@param aBuffer The buffer to use as a temporary store.  This is ignored when
+	   reading from the file.
+@param aFile An RFile object pointing to the file, opened in an appropriate
+	   access mode.Note, Obex is responsible for closing the file, and a panic will
+	   result if an attempt is made to close the file from outside of Obex.
+@param aBufferingStrategy Use double or single buffering.
+@publishedAll
+@released
+*/
+EXPORT_C TObexRFileBackedBuffer::TObexRFileBackedBuffer(CBufBase& aBuffer, RFile aFile, CObexBufObject::TFileBuffering aBufferingStrategy)
+	: TObexBufferingDetails(ERFileBackedBuffer, &aBuffer),
+	  iFile(aFile),
+	  iBufferingStrategy(aBufferingStrategy)
+	{
+	LOG_LINE
+	LOG_FUNC
+	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+RFile TObexRFileBackedBuffer::File()
+	{
+	return iFile;
+	}
+
+
+/**
+Basic getter.
+@internalComponent
+*/
+CObexBufObject::TFileBuffering TObexRFileBackedBuffer::Strategy()
+	{
+	return iBufferingStrategy;
+	}
+
+
+/**
+Set the data buffers as specified in the supplied TObexBufferingDetails object.
+@param aDetails The buffering techniques to use.  This only has to persist
+		over the duration of the call to SetDataBufL, once this has returned it can
+		be allowed to go out of scope.
+
+@panic Obex ENullFileHandle TObexPanicCode::ENullFileHandle The RFile object does not point
+to a valid (open) file.
+@panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length.
+@panic Obex EInvalidBufferDetails TObexPanicCode::EInvalidBufferDetails An unknown TObexBufferingDetails
+object was supplied
+@panic Obex EInvalidBufferStrategy TObexPanicCode::EInvalidBufferStrategy An unknown TFileBuffering
+value was supplied.
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexBufObject::SetDataBufL(TObexBufferingDetails& aDetails)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	PrepareToSetBufferL();
+	
+	iBuf = aDetails.Buffer();
+	if (iBuf)
+		{
+		iBufSegSize = iBuf->Ptr(0).Size();
+		}
+	
+	TBool initFile = EFalse;
+	TBool initFileServer = EFalse;
+	TBool initFileWriter = EFalse;
+	TFileBuffering bufferingStrategy = ESingleBuffering;
+	
+	switch (aDetails.Version())
+		{
+		case TObexBufferingDetails::EBasicBuffer:
+			{
+			// All required details already set.
+			break;
+			}
+		
+		case TObexBufferingDetails::EPureFile:
+			{
+			TObexPureFileBuffer& detail = static_cast<TObexPureFileBuffer&>(aDetails);
+			iFilename = detail.Filename().AllocL();
+			
+			initFileServer = ETrue;
+			initFile = ETrue;
+			break;
+			}
+		
+		case TObexBufferingDetails::EFilenameBackedBuffer:
+			{
+			__ASSERT_ALWAYS(iBuf, IrOBEXUtil::Panic(ENullPointer));
+			__ASSERT_ALWAYS(iBuf->Size(), IrOBEXUtil::Panic(EEmptyBuffer));
+			
+			TObexFilenameBackedBuffer& detail = static_cast<TObexFilenameBackedBuffer&>(aDetails);
+			
+			iFilename = detail.Filename().AllocL();
+			bufferingStrategy = detail.Strategy();
+			
+			initFileServer = ETrue;
+			initFile = ETrue;
+			initFileWriter = ETrue;
+			break;
+			}
+			
+		case TObexBufferingDetails::ERFileBackedBuffer:
+			{
+			__ASSERT_ALWAYS(iBuf, IrOBEXUtil::Panic(ENullPointer));
+			__ASSERT_ALWAYS(iBuf->Size(), IrOBEXUtil::Panic(EEmptyBuffer));
+			
+			TObexRFileBackedBuffer& detail = static_cast<TObexRFileBackedBuffer&>(aDetails);
+			__ASSERT_ALWAYS(detail.File().SubSessionHandle(), IrOBEXUtil::Panic(ENullFileHandle));
+			
+			iFile =  new(ELeave) RFile(detail.File());
+			bufferingStrategy = detail.Strategy();
+			
+			initFileServer = ETrue;
+			initFileWriter = ETrue;
+			break;
+			}
+		
+		default:
+			{
+			IrOBEXUtil::Panic(EInvalidBufferDetails);
+			}
+		}
+		
+	if (initFileServer)
+		{
+		LEAVEIFERRORL(OpenFileServer());
+		}
+	
+	if (initFile)
+		{
+		LEAVEIFERRORL(OpenDataFile(*iFilename));
+		}
+	
+	if (initFileWriter)
+		{
+		switch (bufferingStrategy)
+			{
+			case ESingleBuffering:
+				iWriter = CObexSyncFileWriter::NewL(*iFile);
+				break;
+				
+			case EDoubleBuffering:
+				iWriter = CObexAsyncFileWriter::NewL(*iFile);
+				iDoubleBuf = CBufFlat::NewL(iBufSegSize);
+				iDoubleBuf->ResizeL(iBufSegSize);
+				break;
+
+			default:
+				IrOBEXUtil::Panic(EInvalidBufferStrategy);
+				break;
+			}
+		}
+	}
+
+
+/**
+Delete all owned resources in preparation for getting new settings.
+@internalComponent
+*/
+void CObexBufObject::PrepareToSetBufferL()
+	{
+	// Flush file buffer, if any.
+	if (iFile && iBuf)
+		{
+		LEAVEIFERRORL(WriteBufferToFile(ETrue));
+		iBufOffset = 0;
+		}
+
+	// The writer must be deleted at the same time as or before the file
+	// otherwise the writer will have an invalid file handle
+	delete iWriter;
+	iWriter = NULL;
+
+	CloseDataFile();
+	
+	delete iFilename;
+	iFilename = NULL;
+
+	delete iDoubleBuf;
+	iDoubleBuf = NULL;
+	
+	iBuf = NULL;
+	}
+
+
+/**
+Sets a buffer to use the object body data.
+
+Note that the function can leave.
+
+@param aDataBuf The buffer for the body of the object.
+@panic Obex ENullPointer TObexPanicCode::ENullPointer A NULL value was supplied for the
+data buffer.
+ 	
+@publishedAll
+@deprecated
+*/
+EXPORT_C void CObexBufObject::SetDataBufL(CBufBase* aDataBuf)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	__ASSERT_ALWAYS(aDataBuf, IrOBEXUtil::Panic(ENullPointer));
+	TObexBufferingDetails details(*aDataBuf);
+	SetDataBufL(details);
+	}
+
+
+/**
+Set object to use aFilename as its data area.  Leaves if unable to open file. 
+
+@param aFilename The filename to link the object to.
+
+@publishedAll
+@deprecated
+*/
+EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	TObexPureFileBuffer details(aFilename);
+	SetDataBufL(details);
+	}
+
+
+/**
+Set object to use aFilename as its data area.  Leaves if unable to open file.
+Buffers data into aDataBuf before writing to file.  Will not grow the memory buffer,
+so user can tune buffering behaviour when calling function.
+
+@param aFilename The filename to link the object to.
+@param aDataBuf The buffer for the body of the object.
+@panic Obex ENullPointer TObexPanicCode::ENullPointer A NULL value was supplied for the
+data buffer.
+@panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length.
+
+@publishedAll
+@deprecated
+*/
+EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename, CBufBase* aDataBuf)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	__ASSERT_ALWAYS(aDataBuf, IrOBEXUtil::Panic(ENullPointer));
+	TObexFilenameBackedBuffer details(*aDataBuf, aFilename, ESingleBuffering);
+	SetDataBufL(details);
+	}
+
+
+/**
+Set object to write to file, using buffering and the specified
+buffering strategy. Note the size of the buffer passed to this
+function will determine the size of the second buffer if double
+buffering is employed.
+
+@param aFilename The file to link the object to.
+@param aDataBuf A buffer to use.
+@param aBufferingStrategy The buffering strategy to employ.
+@panic Obex EEmptyBuffer TObexPanicCode::EEmptyBuffer The supplied buffer is of zero length.
+@panic Obex EInvalidBufferStrategy TObexPanicCode::EInvalidBufferStrategy An unknown TFileBuffering
+
+@publishedAll
+@deprecated
+*/
+EXPORT_C void CObexBufObject::SetDataBufL(const TPtrC& aFilename, CBufBase& aDataBuf, const TFileBuffering aBufferingStrategy)
+ 	{
+	LOG_LINE
+	LOG_FUNC
+
+ 	TObexFilenameBackedBuffer details(aDataBuf, aFilename, aBufferingStrategy);
+ 	SetDataBufL(details);	
+ 	}
+
+
+/**
+Gets the buffer.
+
+@return The buffer for the body of the object. 
+
+@publishedAll
+@released
+*/
+EXPORT_C CBufBase* CObexBufObject::DataBuf()
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	return(iBuf);
+	}
+
+
+/**
+Returns a pointer to the HBuf holding the filename this object is using.
+May return a null pointer.
+@return iFilename The file name.
+@internalComponent
+*/
+HBufC* CObexBufObject::FileName()
+	{
+	return(iFilename);
+	}
+
+
+CObexBufObject::CObexBufObject()
+	{
+	}
+
+void CObexBufObject::ConstructL(CBufBase* aDataBuf)
+	{
+	CreateHeaderStorageDataL();
+	if (aDataBuf)
+		SetDataBufL(aDataBuf);
+	}
+
+/**
+Reads aDes (up to MaxLength) from aPos offset into the buffer
+
+@param aPos The offset into the buffer to read from
+@param aDes The descriptor to read from
+*/
+void CObexBufObject::GetData(TInt aPos, TDes8& aDes)
+	{
+	__ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer));
+
+	if (iFile)
+		{
+		GetFileData(aPos, aDes);
+		}
+	else
+		{
+		iBuf->Read(aPos, aDes);
+		}
+	}
+
+void CObexBufObject::GetFileData(TInt aPos, TDes8& aDes)
+	{
+	if(iFile->Read(aPos, aDes) == KErrNone)
+		return;
+	aDes.SetLength(0);
+	}
+
+/**
+Writes aDes into the buffer at aPos offset, growing the buffer if necessary
+*/
+void CObexBufObject::NewData(TInt aPos, TDes8& aDes)
+	{
+	// Three possible cases here.  Can either be receiving into a memory
+	// buffer (old behaviour), receiving directly into a file or buffering
+	// file writes into a fixed size buffer.
+
+	// Should always have at least one of iBuf or iFile set.
+	__ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer));
+
+	if (iFile)
+		{
+		TInt err = NewFileData(aPos, aDes);
+		if (err != KErrNone)
+			{
+			LOG1(_L8("Couldn't write data to file (error %d)"), err);
+			aDes.SetLength(0);
+			return;
+			}
+		}
+	else
+		{
+		if(iBuf->Size() < aPos + aDes.Size())
+			{// Buffer needs to grow. Try to guess how big it needs to be.
+			TInt reqsz = aPos + aDes.Size();
+			if((TInt)Length() > reqsz)
+				reqsz = Length();
+			TRAPD(err, iBuf->ResizeL(reqsz));
+			if(err != KErrNone)
+				{// OOM, probably.
+				LOG2(_L8("Couldn't resize buffer object to %d bytes (error %d)"),
+					reqsz, err);
+				iBuf->Compress();
+				aDes.SetLength(0);
+				return;
+				}
+			}
+		iBuf->Write(aPos, aDes);
+		}
+	}
+
+
+/**
+Write new data into a file
+
+We write data out to the file in chunks of iBufSegSize,
+the (segment) size of the buffer.  A packet of data is
+passed to this method in aDes.  aDes may or may not take
+us past the the end of the buffer.  If it does, then we
+write out the buffer then continue filling it up with
+the rest of aDes.  We repeat this until we have used up
+all of aDes.  iBufOffset is the last write position in
+the file. remaining is the amount of data in aDes yet to
+be processed, written is the amount of data in aDes that
+has been processed.  iBuffered is the amount of data in
+iBuf and spare is the amount of free space in the buffer.
+
+@code
+                               aDes.Length()
+                        <---------------------->
+ ------------------------------------------------------------------------
+| ...      |xxxxxxxxxxxx|\\\\\\\\\\|//|*************|  ...      |
+| ...      |xxxxxxxxxxxx|\\\\\\\\\\|//|*************|  ...      |
+ ------------------------------------------------------------------------
+0 ...  iBufOffset     aPos                                      ...  this.Length()
+
+                           written    remaining
+                         <---------><----------->
+
+                    iBuffered                 spare
+            <----------------------><------------------------>
+
+                              iBufSegSize
+            <------------------------------------------------>
+
+ Key:
+      xxx = data already in buffer
+      \\\ = processed data from aDes, copied into iBuf
+      // = unprocessed data from aDes, not yet copied into iBuf
+      *** = free space in iBuf
+@endcode
+
+If there is more data remaining than there is spare space in
+the buffer, then the buffer is filled and written to disk and
+the remainer of the data is then used to continue filling the
+buffer.
+
+@param aPos The position at which aDes is to be written into the file.
+@param aDes The data to write to the file.
+@return Symbian OS error code
+*/
+TInt CObexBufObject::NewFileData(TInt aPos, TDes8& aDes)
+	{
+	// We have a memory buffer to (hopefully) speed file writes.
+	if (iBuf)
+		{
+		TInt err = KErrNone;
+
+		// If moving to earlier position in object, write out buffer
+		if (iBuffered && (aPos <  iBufOffset))
+			{
+			err = WriteBufferToFile(EFalse);
+			if (err) return err;
+			}
+
+		TInt written = 0;
+		TInt remaining;
+		
+		// Calculate the amount of data still to be processed and
+		// continue whilst there is still data to process
+		while ((remaining = (aDes.Length() - written)) > 0)
+			{
+			// Buffer full, write to file
+			if (iBuffered == iBufSegSize)
+				{
+				err = WriteBufferToFile(EFalse);
+				if (err) return err;
+				}
+
+			// Buffer empty, update buffer base
+			if (iBuffered == 0)
+				{
+				iBufOffset = aPos + written;
+				}
+
+			// Calculate the remaining space in the buffer (spare) and
+			// hence the amount of data we can process (length)
+			TInt spare = iBufSegSize - iBuffered;
+			TInt length = (spare > remaining) ? remaining : spare;
+
+			// Copy amount of data to be procesed (length) from the
+			// unprocessed portion of the packet (aDes.Right(remaining))
+			// into the buffer.
+			iBuf->Write(iBuffered, aDes.Right(remaining), length);
+
+			// Update variables to reflect newly processed data
+			written += length;
+			iBuffered += length;
+			}
+
+		// Is this the final packet?
+		const TBool finalPacket = (ValidHeaders() & KObexHdrEndOfBody);
+
+		// Flush buffer to file if we're done and there's data left
+		if (finalPacket && iBuffered)
+			{
+			err = WriteBufferToFile(ETrue);
+			iBufOffset = 0;
+
+			if (err) return err;
+			}
+		}
+	else
+	// Just write directly to the file
+		{
+		return iFile->Write(aPos, aDes);
+		}
+	
+	return KErrNone;
+	}
+
+
+TInt CObexBufObject::DataSize()
+	{
+	__ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer));
+	if (iFile)
+		{
+		// Flush file buffer, if any.
+		if (iBuf)
+			{
+			(void) WriteBufferToFile(ETrue);
+			}
+		// Get file size
+		TInt size;
+		iFile->Size(size);
+		return size;
+		}
+	else
+		{
+		return (iBuf->Size());
+		}
+	}
+
+void CObexBufObject::ResetData()
+	{
+	__ASSERT_ALWAYS((iBuf || iFile), IrOBEXUtil::Panic(ENullPointer));
+	if (iFile)
+		{
+		iFile->SetSize(0);
+		if (iBuf)
+			{
+			iBufOffset = 0;
+			iBuffered  = 0;
+			}
+		}
+	else
+		{
+		iBuf->Reset();
+		}
+	}
+
+
+TInt CObexBufObject::OpenDataFile(const TDesC& aFilename)
+	{
+	TInt err = KErrNotReady;
+
+	if (!iFile)
+		{
+		iFile = new RFile;
+		if (!iFile) return KErrNoMemory;
+		
+		//Try and open the file for read/write
+		err = iFile->Open(*iFileServ, aFilename, EFileWrite | EFileShareExclusive);
+		if (err != KErrNone)
+			{
+			//Try and open file for read only	
+			err = iFile->Open(*iFileServ, aFilename, EFileRead  | EFileShareReadersOnly);
+			if(err == KErrNotFound)
+				{
+				err = iFile->Create(*iFileServ, aFilename, EFileWrite | EFileShareExclusive);
+				}
+			}
+
+		if (err)
+			{
+			delete iFile;
+			iFile = 0;
+			}
+		}
+	
+	return err;
+	}
+
+
+void CObexBufObject::CloseDataFile()
+	{
+	if (iFile)
+		{
+		iFile->Close();
+		delete iFile;
+		iFile = 0;
+		}
+	}
+
+TInt CObexBufObject::OpenFileServer()
+	{
+	TInt err = KErrNone;
+
+	if (!iFileServ)
+		{
+		iFileServ = new RFs;
+		if (!iFileServ) return KErrNoMemory;
+
+		err = iFileServ->Connect();
+		if (err)
+			{
+			delete iFileServ;
+			iFileServ = 0;
+			}
+		}
+	return err;
+	}
+
+void CObexBufObject::CloseFileServer()
+	{
+	if (iFileServ)
+		{
+		iFileServ->Close();
+		delete iFileServ;
+		iFileServ = 0;
+		}
+	}
+
+TInt CObexBufObject::WriteBufferToFile(TBool aFinal)
+	{
+	TInt err = KErrNone;
+	
+	if (aFinal)
+		{
+		err = iWriter->FinalWrite(iBufOffset, iBuf, iBuffered);
+		}
+	else
+		{
+		err = iWriter->Write(iBufOffset, iBuf);
+		}
+	
+	if (!iBuf && iDoubleBuf)
+		{
+		iBuf = iDoubleBuf;
+		}
+
+	iBuffered  = 0;
+
+	return err;
+	}
+
+//
+// class CObexNullObject
+//
+void CObexNullObject::ConstructL()
+	{
+	CreateHeaderStorageDataL();
+	}
+
+/** Allocates and constructs a new null object.
+
+@return New null object 
+
+@publishedAll
+@released
+*/
+EXPORT_C CObexNullObject* CObexNullObject::NewL()
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	CObexNullObject* self = new(ELeave) CObexNullObject;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return(self);
+	}
+
+/**
+To return "NULL" data, we simply set aDes.Size = 0
+*/
+void CObexNullObject::GetData(TInt /*aPos*/, TDes8& aDes)
+	{
+	aDes.SetLength(0);
+	return;
+	}
+
+/**
+In order to appear to consume the data, we don't set aDes.Size = 0
+*/
+void CObexNullObject::NewData(TInt /*aPos*/, TDes8& /*aDes*/)
+	{
+	return;
+	}
+
+TInt CObexNullObject::DataSize()
+	{
+	return(0);
+	}
+
+void CObexNullObject::ResetData()
+	{
+	}