messagingappbase/obexmtms/obexmtm/obexutil/source/obexMtmUtil.cpp
changeset 0 72b543305e3a
child 23 238255e8b033
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/obexmtms/obexmtm/obexutil/source/obexMtmUtil.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,404 @@
+// Copyright (c) 2001-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:
+// $Workfile: obexMtmUtil.cpp $
+// $Author: Stevep $
+// $Revision: 7 $
+// $Date: 8/02/02 10:11 $
+// 
+//
+
+//class include
+#include "obexMtmUtil.h"
+#include "obexheaderlist.h"
+
+#ifdef _DEBUG
+#define DEBPRINT(Z)  User::InfoPrint(Z);
+#else
+#define DEBPRINT(Z)
+#endif
+
+// Uncomment this to test data compatibility with builds older than PHAR-5SDJG9.
+// (if uncommented, messages are externalised the same way it was done before the PHAR-5SDJG9 changes)
+//#define TEST_INC042468 
+
+static const TInt KObexArrayGranularity = 4;
+
+//
+//
+//  Class for externalising a set of filenames to the same message entry store. Rolls back if not explicitely committed.
+//
+
+// Static functions that do the whole process in one go:
+EXPORT_C  void CObexMtmFileNameExternaliser::ExternaliseAndCommit1FileNameL(CMsvEntry* aEntry, const TDesC16* aFileName)
+/**
+* Static function to write one and only one filename to the message store, then finalise and commit it. This function
+* should be called ONCE ONLY. To externalise more than one filename, instantiate this class and use ExternaliseFileNameL()
+* followed by CommitStoreL().
+* @param aEntry the entry whose store is to be written to
+* @param aFileName The filename to write to the store
+* @leave KErrXXX system-wide error codes
+*/	
+	{
+	CMsvStore* messageStore = aEntry->EditStoreL();
+	CleanupStack::PushL(messageStore);
+
+	RMsvWriteStream messageWriteStream;
+	CleanupClosePushL(messageWriteStream);
+
+	messageWriteStream.AssignL(*messageStore, KObexFileNameStreamUid);
+
+	// write the identifier so we know we are internalizing a stream later
+#ifndef TEST_INC042468
+	messageWriteStream.WriteInt32L(KObexFileNameStreamFileNameUid);
+#endif
+	messageWriteStream.WriteInt32L(aFileName->Length());  
+	messageWriteStream.WriteL(*aFileName);
+
+#ifndef TEST_INC042468
+	messageWriteStream.WriteInt32L(KObexFileNameStreamFileNameUid);
+#endif
+	messageWriteStream.WriteInt32L(0);		//Mark the end of the filename list
+
+	messageWriteStream.CommitL();
+
+	CleanupStack::PopAndDestroy(); // trigger a call to Close(); on messageWriteStream as well as removing from the stack
+
+	messageStore->CommitL();
+	CleanupStack::PopAndDestroy(messageStore);
+	}
+
+
+EXPORT_C  void CObexMtmFileNameExternaliser::Internalise1FileNameL(CMsvEntry* aEntry,  TDes16* aFileName)
+/**
+* Static function to read in one filename from the store.
+*
+* @param aEntry entry to read the filename from
+* @param aFileName Descriptor to recieve the new filename. Any existing data will be overwritten. MUST be long enough to contain the name.
+* @leave KErrXXX system wide error codes.
+*/	
+	{
+	CMsvStore* messageStore = aEntry->ReadStoreL();
+	CleanupStack::PushL(messageStore);
+
+	RMsvReadStream messageReadStream;
+	messageReadStream.OpenLC(*messageStore, KObexFileNameStreamUid);  // If data hasn't been stored then this will provide the error.
+
+	// verify that we're reading the right type of data from the stream
+
+
+	// INC042468: "AV21: Data Compatibility break caused by "PHAR-5SDJG9""
+	// To regain compatibility, if the first integer read from the stream
+	// is not the expected "KObexFileNameStreamFileNameUid", it is assumed it 
+	// is the filename length. An extra check is made that it is a valid filename
+	// length (<= KMaxFileName).
+	// "KObexFileNameStreamFileNameUid" has also been modified so that there cannot
+	// be a file with a name length equal to KObexFileNameStreamFileNameUid (in which
+	// case we would have been in trouble ;-) )
+
+	TInt32 firstInt = messageReadStream.ReadInt32L();
+	TInt32 fileNameLength = 0;
+	if (firstInt == KObexFileNameStreamFileNameUid)
+		{
+		// next will be the filename length
+		fileNameLength = messageReadStream.ReadInt32L();
+		}
+	else if (firstInt <= KMaxFileName)
+		{
+		// let's assume the first integer in the stream was the filename length
+		// (this happens if the message was saved by an old build (previous to PHAR-5SDJG9)
+		fileNameLength = firstInt;
+		}
+	else
+		{
+		// neither the expected "KObexFileNameStreamFileNameUid" nor a valid filename length
+		User::Leave(KErrArgument);	
+		}
+
+	messageReadStream.ReadL(*aFileName, fileNameLength);
+
+	CleanupStack::PopAndDestroy(2, messageStore);  // messageStore, messageReadStream (calls Close() first)
+	}
+
+//
+//
+// Class for storing multiple Filenames within a CMsvEntry store.
+//
+EXPORT_C  CObexMtmFileNameExternaliser* CObexMtmFileNameExternaliser::NewL(CMsvSession* aSession, TMsvId aId)
+/**
+* Canonical NewL factory function.
+*
+* @param aSession A messaging server session
+* @param aId TMsvId of the entry to externalise/internalise to/from. This association is fixed for the lifetime of this instance of the class.
+* @return a newly constucted CObexMtmFileNameExternaliser
+* @leave KErrXXX system wide error codes
+*/
+	{
+	CObexMtmFileNameExternaliser* self = new(ELeave) CObexMtmFileNameExternaliser(aSession);
+	CleanupStack::PushL(self);
+	self->InitialiseStoreL(aId);
+	CleanupStack::Pop();  // self
+	return self;
+	}
+CObexMtmFileNameExternaliser::CObexMtmFileNameExternaliser(CMsvSession* aSession)   :   iSession(aSession)
+/**
+* Constructor
+*
+*  @param aSession A messaging server session
+*/
+	{}
+CObexMtmFileNameExternaliser::~CObexMtmFileNameExternaliser()
+/**
+* Destructor. Will revert the stream to its original state if the store hasn't been comitted.
+*/
+	{
+	if(! iHaveCommitted)
+		{
+		iMessageWriteStream.Close();  
+		iMessageStore->Revert();  // Don't commit. Should have been called explicitly using CommitStoreL().
+		}
+	delete iMessageStore;
+	delete iEntry;
+	}
+
+void CObexMtmFileNameExternaliser::InitialiseStoreL(TMsvId aId)
+/**
+ * Initialises the store of the given entry, ready for reading or writing.
+ *
+ * @param aId The TMsvId of the entry whose store should be initialised.
+ * @leave KErrXXX system wide error codes.
+ */
+	{
+	iEntry = iSession->GetEntryL(aId);
+
+	iMessageStore = iEntry->EditStoreL();
+
+	iMessageWriteStream.AssignL(*iMessageStore, KObexFileNameStreamUid);
+	iHaveCommitted = EFalse;
+	}
+
+EXPORT_C  void CObexMtmFileNameExternaliser::ExternaliseFileNameL(const TDesC16* aFileName)
+/**
+ * Externalises a single filename to the associated entry's message store.
+ *
+ * @param aFileName the filename to externalise.
+ * @leave KErrXXX system-wide error codes.
+ */
+	{
+#ifndef TEST_INC042468
+	iMessageWriteStream.WriteInt32L(KObexFileNameStreamFileNameUid);
+#endif
+	iMessageWriteStream.WriteInt32L(aFileName->Length());
+	iMessageWriteStream.WriteL(*aFileName);
+	}
+
+EXPORT_C  void CObexMtmFileNameExternaliser::ExternaliseFileNameAndHeadersL(const TDesC16* aFileName, const CObexHeaderList* aHeaderList)
+/**
+ * Externalises a single filename to the associated entry's message store.
+ *
+ * @param aFileName the filename to externalise.
+ * @leave KErrXXX system-wide error codes.
+ */
+	{
+	ExternaliseFileNameL(aFileName);
+#ifndef TEST_INC042468
+	iMessageWriteStream.WriteInt32L(KObexFileNameStreamHeaderListUid);
+	aHeaderList->ExternalizeL(iMessageWriteStream);
+#endif
+	}
+
+EXPORT_C  void CObexMtmFileNameExternaliser::CommitStoreL()
+/**
+ * Finalises and commits the store. This function MUST be called once all of the filenames have been externalised, and not
+ * before. If it is not called, any changes will be lost and the store will revert to its former state.
+ *
+ * @leave KErrXXX system wide error codes.
+ */
+	{
+#ifndef TEST_INC042468
+	iMessageWriteStream.WriteInt32L(KObexFileNameStreamFileNameUid);
+#endif
+	iMessageWriteStream.WriteInt32L(0);  // length == 0  --> no more names in store.
+	iMessageWriteStream.CommitL();
+	iHaveCommitted = ETrue;
+	iMessageWriteStream.Close();
+
+	iMessageStore->CommitL();
+
+	delete iMessageStore;
+	iMessageStore=NULL;
+	}
+
+EXPORT_C  RObexMtmFileNameWithHeadersArray* CObexMtmFileNameExternaliser::InternaliseFileNamesLC(CMsvStore& aMessageStore)
+/**
+ * Static function to get the filenames stored within the message entry. The returned array is pushed onto the cleanup
+ * stack.
+ *
+ * @param aMessageStore Store from which the names are to be read
+ * @return Array of filenames, pushed onto the cleanup stack.
+ * @leave System wide error codes
+ */
+	{
+	RObexMtmFileNameWithHeadersArray* fileNameArray = new(ELeave) RObexMtmFileNameWithHeadersArray(KObexArrayGranularity);
+	CleanupStack::PushL(fileNameArray);
+
+	RMsvReadStream  newMessageReadStream;
+	newMessageReadStream.OpenL(aMessageStore, KObexFileNameStreamUid);  // If data hasn't been stored then this will provide the error.
+	CleanupClosePushL(newMessageReadStream);
+
+
+
+
+	// INC042468: "AV21: Data Compatibility break caused by "PHAR-5SDJG9""
+	// To regain compatibility, if the first integer read from the stream
+	// is not the expected "KObexFileNameStreamFileNameUid", it is assumed it 
+	// is the filename length. An extra check is made that it is a valid filename
+	// length (<= KMaxFileName).
+	// "KObexFileNameStreamFileNameUid" has also been modified so that there cannot
+	// be a file with a name length equal to KObexFileNameStreamFileNameUid (in which
+	// case we would have been in trouble ;-) )
+
+	TInt32 firstInt = newMessageReadStream.ReadInt32L();
+	
+	TInt32 fileNameLength = 0;
+	if (firstInt == KObexFileNameStreamFileNameUid)
+		{
+		// next will be the filename length
+		fileNameLength = newMessageReadStream.ReadInt32L();
+		}
+	else if (firstInt <= KMaxFileName)
+		{
+		// let's assume the first integer in the stream was the filename length
+		// (this happens if the message was saved by an old build (previous to PHAR-5SDJG9)
+		fileNameLength = firstInt;
+		}
+	else
+		{
+		// neither the expected "KObexFileNameStreamFileNameUid" nor a valid filename length
+		User::Leave(KErrArgument);	
+		}
+
+	TInt32 elementTypeID;
+	TBool lengthAlreadyReadFlag;
+	TFileName thisName;
+	CObexMtmFileNameWithHeaders *thisPackage;
+	while(fileNameLength)
+		{
+
+		thisPackage = CObexMtmFileNameWithHeaders::NewL();
+		CleanupStack::PushL(thisPackage);
+				
+		// read 'bodylength' bytes into a descriptor			
+		newMessageReadStream.ReadL(thisName, fileNameLength);
+		
+		// store this descriptor in the container
+		thisPackage->iFileName = new(ELeave) TFileName(thisName);
+		CleanupStack::PushL(thisPackage->iFileName);
+
+		lengthAlreadyReadFlag = EFalse;	
+		// get the type of the next element
+		elementTypeID = newMessageReadStream.ReadInt32L();
+
+		switch(elementTypeID)
+			{
+		case KObexFileNameStreamHeaderListUid:
+			// this filename has some headers associated with it
+			
+			// read these headers in...
+			thisPackage->iHeaderList = CObexHeaderList::NewLC();
+			thisPackage->iHeaderList->InternalizeL(newMessageReadStream);
+
+			// get the type of the next element
+			elementTypeID = newMessageReadStream.ReadInt32L();
+						
+			// fall through to add this container to the array
+		case KObexFileNameStreamFileNameUid:
+			// this filename has no headers associated with it, this is OK.
+			fileNameArray->Append(thisPackage);
+			break;
+
+		default:
+			// builds previous to PHAR-5SDJG9: 
+			// no stream Uids are externalised and elementTypeID contains already the filename length
+			if (elementTypeID <= KMaxFileName)
+				{
+				fileNameArray->Append(thisPackage);
+				fileNameLength = elementTypeID;
+				lengthAlreadyReadFlag = ETrue;
+				}
+			else
+				{
+				User::Leave(KErrArgument);
+				}
+			// if this value is not one of the two element types, then we can't read the stream
+			
+			break;
+			}
+
+		// this member will be zero if there were no headers on this filename
+		if(thisPackage->iHeaderList)
+			{
+			CleanupStack::Pop(thisPackage->iHeaderList);
+			}
+
+		// safely added filename and headers to list, pop the allocations off the cleanup stack.
+		CleanupStack::Pop(thisPackage->iFileName);
+		
+		CleanupStack::Pop(thisPackage);
+
+		// get the length of the next element
+		if (!lengthAlreadyReadFlag)
+			{
+			TRAPD (err, fileNameLength = newMessageReadStream.ReadInt32L();)  // Length == 0 --> end of array
+			}
+		}
+
+	newMessageReadStream.Close();
+	CleanupStack::PopAndDestroy();  //newMessageReadStream
+
+	return fileNameArray;
+	}
+
+//
+// CObexMtmFileNameWithHeaders
+//
+
+EXPORT_C CObexMtmFileNameWithHeaders* CObexMtmFileNameWithHeaders::NewL()
+	/**
+	 * Canonical NewL factory function.
+	 *
+	 * @return an empty CObexMtmFileNameWithHeaders class
+	 * @leave KErrXXX system wide error codes
+	 */
+	{
+	CObexMtmFileNameWithHeaders *self = new(ELeave)CObexMtmFileNameWithHeaders;
+	return self;
+	}
+
+CObexMtmFileNameWithHeaders::~CObexMtmFileNameWithHeaders()
+/**
+ * Destructor. Will destroy the data pointed to by the 2 member pointers.
+ */
+	{
+	delete iFileName;
+	delete iHeaderList;
+	}
+
+CObexMtmFileNameWithHeaders::CObexMtmFileNameWithHeaders()
+	/**
+	 * Constructor.
+	 */
+	{
+	}
+
+