// Copyright (c) 1998-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:
//

#include <s32std.h>

#include "MSVIPC.H"
#include "MSVIDS.H"
#include "MSVPANIC.H"

#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include "msvsearchsortconstants.h"
#include "msvconsts.h"
#endif

GLDEF_C void DoUnpackEntry(TUint8*& aPtr, TMsvEntry& aEntry)
//
//
//
	{
	// get the entry from the start of the buffer
	const TMsvEntry* pEntry = (TMsvEntry*) aPtr;
	aEntry = *pEntry;
	aPtr = Align4(aPtr + sizeof(TMsvEntry));

	const TText* textPtr = (TText*)aPtr;
	TInt length=aEntry.iDescription.Length();
	aEntry.iDescription.Set(textPtr, length);
	textPtr = Align4(textPtr + length);

	length=aEntry.iDetails.Length();
	aEntry.iDetails.Set(textPtr, length);
	textPtr = Align4(textPtr + length);

	aPtr = (TUint8*) textPtr;
	}
	

GLDEF_C TInt DoPackEntry(const TUint8*& aPtrStart, const TUint8* aPtrEnd, const TMsvEntry& aEntry)
//
// Packs an entry into the memory area defined by the two pointers.
// Fails with KErrOverflow if the packed entry is too large
// aPtrStart is always returned pointing to the end of the packed entry (even if too large)
//
	{
	// make sure the entry can fit into the memory area defined by the two pointers
	TInt sizeEntry = Align4(sizeof(TMsvEntry));
	TInt sizeString1 = Align4(aEntry.iDescription.Size());
	TInt sizeString2 = Align4(aEntry.iDetails.Size());
	TInt size =  sizeEntry + sizeString1 + sizeString2;
	if ((aPtrStart + size)>aPtrEnd)
		{
		aPtrStart += size;
		return KErrOverflow;
		}
		
	// copy the entry and descriptors into the memory area
	Mem::Copy((void*)aPtrStart, &aEntry, sizeof(TMsvEntry));
	aPtrStart += sizeEntry;

	Mem::Copy((void*)aPtrStart, aEntry.iDescription.Ptr(), aEntry.iDescription.Size());
	aPtrStart += sizeString1;
	
	Mem::Copy((void*)aPtrStart, aEntry.iDetails.Ptr(), aEntry.iDetails.Size());
	aPtrStart += sizeString2;
	
	return KErrNone;
	}
	
	
GLDEF_C void DoUnpackFilter(TUint8*& aPtr, CMsvEntryFilter& aFilter)
//
//
//
	{
	// get the entry from the start of the buffer
	const CMsvEntryFilter* pFilter = (CMsvEntryFilter*) aPtr;
	Mem::Copy(&aFilter, pFilter, sizeof(CMsvEntryFilter));
	aPtr = Align4(aPtr + sizeof(CMsvEntryFilter));
	}


GLDEF_C TInt DoPackFilter(const TUint8*& aPtrStart, const TUint8* aPtrEnd, const CMsvEntryFilter& aFilter)
//
//
//
	{
	// make sure the entry can fit into the memory area defined by the two pointers
	TInt size = Align4(sizeof(CMsvEntryFilter));
	if ((aPtrStart + size)>aPtrEnd)
		{
		aPtrStart += size;
		return KErrOverflow;
		}
		
	// copy the filter into the memory area
	Mem::Copy((void*)aPtrStart, &aFilter, sizeof(CMsvEntryFilter));
	aPtrStart += size;
	
	return KErrNone;
	}

//**********************************
// TMsvPackedEntry
//**********************************


EXPORT_C TMsvPackedEntry::TMsvPackedEntry(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{}

EXPORT_C TInt TMsvPackedEntry::PackEntry(const TMsvEntry& aEntry)
//
//
//
	{
	// find the start and end of the buffer
	const TUint8* pS = iBuffer->Ptr();
	const TUint8* pE = PtrAdd(pS, iBuffer->Des().MaxSize());

	TInt error = DoPackEntry(pS, pE, aEntry);
	if (error==KErrNone)
		{
		// update the length of the buffer
		iBuffer->Des().SetLength(pS-iBuffer->Ptr());
		}

	return error;
	}

EXPORT_C void TMsvPackedEntry::UnpackEntry(TMsvEntry& aEntry)
//
//
//
	{
#if defined(_DEBUG)
	// check that the buffer contain a valid package
	const TMsvEntry* dEntry = (TMsvEntry*) iBuffer->Ptr();
	const TUint8* dPos = PtrAdd(iBuffer->Ptr(), Align4(sizeof(TMsvEntry)) + Align4(dEntry->iDescription.Size()) + Align4(dEntry->iDetails.Size()));
	__ASSERT_DEBUG(dPos <= PtrAdd(iBuffer->Ptr(), iBuffer->Des().MaxLength()), PanicServer(EMsvEntryOverrunBuffer));
#endif
	
	TUint8* pS = CONST_CAST(TUint8*, iBuffer->Ptr());
	DoUnpackEntry(pS, aEntry);
	}

//**********************************
// TMsvPackedEntryArray
//**********************************


EXPORT_C TMsvPackedEntryArray::TMsvPackedEntryArray(HBufC8*& aBuffer, TInt aCount)
: iIndex(0), iCount(aCount), iBuffer(aBuffer) 
	{
	iPos = iBuffer->Ptr();
	}


EXPORT_C void TMsvPackedEntryArray::Reset()
//
//
//
	{
	iBuffer->Des().SetLength(0);
	iPos  = iBuffer->Ptr();
	iIndex=0;
	iCount=0;
	}

EXPORT_C TInt TMsvPackedEntryArray::PackEntry(const TMsvEntry& aEntry)
//
//
//
	{
	const TUint8* pS = iPos;
	const TUint8* pE = PtrAdd(iBuffer->Ptr(), iBuffer->Des().MaxSize());

	TInt error = DoPackEntry(pS, pE, aEntry);
	if (error==KErrNone)
		{
		// update the length of the buffer and the position for the next entry
		iBuffer->Des().SetLength(pS-iBuffer->Ptr());
		iPos = pS;
		iIndex++;
		iCount++;
		}
	
	return error;
	}

EXPORT_C TInt TMsvPackedEntryArray::UnpackEntry(TInt aIndex, TMsvEntry& aEntry)
//
//
//
	{
	TInt error=KErrNone;

	if (iIndex!=aIndex)
		error = FindEntryInArray(aIndex);

	if (error==KErrNone)
		{
		TUint8* pS=CONST_CAST(TUint8*, iPos);
		DoUnpackEntry(pS, aEntry);
		iPos=pS;
		iIndex++;
		}	

	return error;
	}


TInt TMsvPackedEntryArray::FindEntryInArray(TInt aIndex)
//
//
//
	{
	if (aIndex>=iCount)
		return KErrNotFound;

	if (iIndex>aIndex)
		{
		// have to reset to the start of the buffer
		iPos = iBuffer->Ptr();
		iIndex=0;
		}

	while (iIndex!=aIndex)
		{
		const TMsvEntry* pEntry = (TMsvEntry*) iPos;
		iPos += Align4(sizeof(TMsvEntry)) + Align4(pEntry->iDescription.Size()) + Align4(pEntry->iDetails.Size());
		iIndex++;
		}

	__ASSERT_DEBUG(iPos < PtrAdd(iBuffer->Ptr(), iBuffer->Des().MaxLength()), PanicServer(EMsvPointerOverrunBuffer));

	return KErrNone;
	}



//**********************************
// TMsvMoveCopyDetails
//**********************************

EXPORT_C TMsvLocalOperationProgress::TMsvLocalOperationProgress()
: iType(ELocalNone), iTotalNumberOfEntries(0), iNumberCompleted(0), iNumberFailed(0), iNumberRemaining(0), iError(KErrNone), iId(KMsvNullIndexEntryId)
/** Initialises the new object to suitable zero or null values. */
	{
	}

//**********************************
// TMsvServerOperationProgress
//**********************************

EXPORT_C TMsvServerOperationProgress::TMsvServerOperationProgress()
: iOperationType(EMsvNoOperation)
/** Default constructor.

Sets iOperationType to EMsvNoOperation. */
	{
	}

TMsvServerOperationProgress::TMsvServerOperationProgress(TMsvServerOperationType aType)
: iOperationType(aType)
	{
	}

//**********************************
// TMsvIndexProgress
//**********************************

EXPORT_C TMsvIndexProgress::TMsvIndexProgress()
: iTotal(0), iCompleted(0), iRemaining(0), iId(KMsvNullIndexEntryId)
/** Default constructor.

Data members are intialised to 0 or KMsvNullIndexEntryId as appropriate. */
	{
	}

//**********************************
// TMsvIndexLoadProgress
//**********************************

EXPORT_C TMsvIndexLoadProgress::TMsvIndexLoadProgress()
: TMsvServerOperationProgress(EMsvChangeDriveOperation), iError(KErrNone), iState(EIndexNotLoaded)
/** Default constructor.

iOperationType is set to EMsvChangeDriveOperation; iError is set to KErrNone; 
iState is set to EIndexNotLoaded. */
	{
	}
	
	
	
//**********************************
// TMsvCopyProgress
//**********************************

/** Default constructor.
iOperationType is set to EMsvCopyOperation; iError is set to KErrNone; 
iState is set to ENotYetStarted. */  

EXPORT_C TMsvCopyProgress::TMsvCopyProgress()
: TMsvServerOperationProgress(EMsvCopyOperation), iError(KErrNone), iState(ENotYetStarted)
	{
	}


//**********************************
// TMsvDeleteProgress
//**********************************

/** Default constructor.
iOperationType is set to EMsvDeleteOperation; iError is set to KErrNone; 
iState is set to ENotYetStarted. */

EXPORT_C TMsvDeleteProgress::TMsvDeleteProgress()
: TMsvServerOperationProgress(EMsvDeleteOperation), iError(KErrNone), iState(ENotYetStarted)

	{
	}


//**********************************
// TMsvChildrenDetails
//**********************************

EXPORT_C TMsvChildrenDetails::TMsvChildrenDetails()
: iParentId(KMsvNullIndexEntryId), iTotalNumberChildren(0), iNumberChildrenInArray(0), iLastEntryInArray(0)
	{
	}


//**********************************
// TMsvPackedOperation
//**********************************

EXPORT_C TMsvPackedOperation::TMsvPackedOperation(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{
	}


EXPORT_C TInt TMsvPackedOperation::Pack(const CMsvEntrySelection& aSelection, TInt aParameter1, TInt aParameter2)
	{
	// check the buffer is large enough
	TInt requiredSize = (aSelection.Count()+3)*4;
	if (requiredSize>iBuffer->Des().MaxSize())
		return KErrOverflow;
	// set the buffer with correct length
	iBuffer->Des().SetLength(requiredSize);

	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());
	*ptr++ = aSelection.Count();
	for (TInt count=0; count<aSelection.Count(); count++)
		*ptr++ = aSelection.At(count);
	*ptr++ = aParameter1;
	*ptr++ = aParameter2;
	return KErrNone;
	}


EXPORT_C void TMsvPackedOperation::UnpackL(CMsvEntrySelection& aSelection, TInt& aParameter1, TInt& aParameter2)
	{
	__ASSERT_DEBUG(aSelection.Count()==0, PanicServer(EMsvOperationUnpackSelectionNotEmpty));	
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());

	TInt count = *ptr++;
	
	TInt bufSize = iBuffer->Des().Length();
	
	// This length is calculated on the basis of length set in TMsvPackedOperation::Pack above.
	TInt len = (count+3)*4; 
	if(bufSize == len)	
		{
		while (count--)
			{
			aSelection.AppendL(*ptr++);
			}
		aParameter1 = *ptr++;
		aParameter2 = *ptr++;
		}
	else
		{
		User::Leave(KErrArgument);
		}
	}


EXPORT_C TMsvPackedChangeNotification::TMsvPackedChangeNotification(TMsvNotifBuffer& aBuffer)
: iBuffer(aBuffer)
	{
	}


EXPORT_C void TMsvPackedChangeNotification::Pack(TMsvServerChangeNotificationType aChangeType, const CMsvEntrySelection& aSelection, TInt aParameter1, TInt aParameter2, TInt aStartIndex, TInt aFinishIndex)
//
// Packs the aStartIndex->aFinishIndex (inc) into the buffer
//
	{
	__ASSERT_DEBUG(aFinishIndex-aStartIndex+1<=KMsvPackedChangeLimit, PanicServer(EMsvChangeSelectionTooLarge));

	// set the buffer with correct length
	TInt requiredSize = (aFinishIndex-aStartIndex+1+KMsvChangeNotificationNumberOfTInts)*4;
	iBuffer.SetLength(requiredSize);

	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer.Ptr());
	*ptr++ = aChangeType;
	*ptr++ = aParameter1;
	*ptr++ = aParameter2;
	*ptr++ = aFinishIndex - aStartIndex + 1;
	for (TInt count=aStartIndex; count<=aFinishIndex; count++)
		*ptr++ = aSelection.At(count);
	}


EXPORT_C void TMsvPackedChangeNotification::Pack(TMsvServerChangeNotificationType aChangeType, TMsvId aId, TInt aParameter1, TInt aParameter2)
//
// Packs a single id
//
	{
	// set the buffer with correct length
	TInt requiredSize = (1+KMsvChangeNotificationNumberOfTInts)*4;
	iBuffer.SetLength(requiredSize);

	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer.Ptr());
	*ptr++ = aChangeType;
	*ptr++ = aParameter1;
	*ptr++ = aParameter2;
	*ptr++ = 1;
	*ptr++ = aId;
	}


EXPORT_C void TMsvPackedChangeNotification::UnpackL(TMsvServerChangeNotificationType& aChangeType, CMsvEntrySelection& aSelection, TInt& aParameter1, TInt& aParameter2)
//
//
//
	{
	__ASSERT_DEBUG(aSelection.Count()==0, PanicServer(EMsvChangedUnpackSelectionNotEmpty));	
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer.Ptr());
	switch (*ptr++)
		{
		case 1:
			aChangeType = EMsvEntriesCreated;
			break;
		case 2:
			aChangeType = EMsvEntriesChanged;
			break;
		case 3:
			aChangeType = EMsvEntriesDeleted;
			break;
		case 4:
			aChangeType = EMsvEntriesMoved;
			break;
		case 5:
			aChangeType = EMsvMtmGroupInstalled;
			break;
		case 6:
			aChangeType = EMsvMtmGroupDeInstalled;
			break;
		case 8:
			aChangeType = EMsvCloseSession;
			break;
		case 9:
			aChangeType = EMsvIndexLoaded;
			break;
		case 10:
			aChangeType = EMsvIndexFailedToLoad;
			break;
		case 12:
			aChangeType = EMsvMediaChanged;
			break;
		case 13:
			aChangeType = EMsvMediaUnavailable;
			break;
		case 14:
			aChangeType = EMsvMediaAvailable;
			break;
		case 15:
			aChangeType = EMsvMediaIncorrect;
			break;
#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
		case 16:
			aChangeType = EMsvMessageStoreNotSupported;
			break;
		case 17:
			aChangeType = EMsvMessageStoreCorrupt;
			break;
		case 18:
			aChangeType = EMsvRefreshMessageView;
			break;
		case 19:
			aChangeType = EMsvDiskNotAvailable;
			break;
		case 20:
			aChangeType = EMsvUnableToProcessDiskNotification;
			break;
#endif	
		default:
			__ASSERT_DEBUG(EFalse, PanicServer(EMsvUnknownChangeType));
			aChangeType = EMsvEntriesNoChange;
		}
	aParameter1 = *ptr++;
	aParameter2 = *ptr++;
	TInt count = *ptr++;
	while (count--)
		aSelection.AppendL(*ptr++);
	}

TMsvPackedEntryFilter::TMsvPackedEntryFilter(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{}

TInt TMsvPackedEntryFilter::PackFilter(const CMsvEntryFilter& aFilter)
	{
	// find the start and end of the buffer
	const TUint8* pS = iBuffer->Ptr();
	const TUint8* pE = PtrAdd(pS, iBuffer->Des().MaxSize());

	TInt error = DoPackFilter(pS, pE, aFilter);
	if (error==KErrNone)
		{
		// update the length of the buffer
		iBuffer->Des().SetLength(pS-iBuffer->Ptr());
		}

	return error;
	}

void TMsvPackedEntryFilter::UnpackFilter(CMsvEntryFilter& aFilter)
	{
#if defined(_DEBUG)
	// check that the buffer contain a valid package
	const TUint8* dPos = PtrAdd(iBuffer->Ptr(), Align4(sizeof(CMsvEntryFilter)));
	__ASSERT_DEBUG(dPos <= PtrAdd(iBuffer->Ptr(), iBuffer->Des().MaxLength()), PanicServer(EMsvEntryOverrunBuffer));
#endif	
	TUint8* pS = CONST_CAST(TUint8*, iBuffer->Ptr());
	DoUnpackFilter(pS, aFilter);
	}

/**
Constructor for TMsvPackQuery.
@internalComponent
@released
@param aBuffer: buffer for packing
*/

EXPORT_C TMsvPackQuery::TMsvPackQuery(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{}


TInt TMsvPackQuery::DoPackQuery(const TUint8*& aPtrStart, const TUint8* aPtrEnd, const CMsvSearchSortQuery* aQuery)
	{
	//size of class - sizeof(iQueryTable pointer)
	TInt sizeOfClass = Align4(sizeof(CMsvSearchSortQuery) - sizeof(TInt));
	TInt sizeQueryTable = Align4(sizeof(TMsvQueryTable) * KMaxLevelOfSearchAndSort);
	TInt size = sizeOfClass + sizeQueryTable;
	
	if ((aPtrStart + size)>aPtrEnd)
		{
		aPtrStart += size;
		return KErrOverflow;
		}
		
	// copy the entry and descriptors into the memory area
	Mem::Copy((void*)aPtrStart, aQuery, sizeOfClass);
	aPtrStart += sizeOfClass;

	Mem::Copy((void*)aPtrStart, aQuery->iQueryTable, sizeQueryTable);
	aPtrStart += sizeQueryTable;

	return KErrNone;
	}

/**
Packs TMsvSearchSortQuery object into a buffer for sending across IPC. 
@internalComponent
@released
@param aQuery: TMsvSearchSortQuery object needs to pack.
@return: reurn KErrNone if successful else KErrOverflow.
*/
EXPORT_C TInt TMsvPackQuery::PackQuery(const CMsvSearchSortQuery* aQuery)
	{
	// find the start and end of the buffer
	const TUint8* pS = iBuffer->Ptr();
	const TUint8* pE = PtrAdd(pS, iBuffer->Des().MaxSize());

	TInt error = DoPackQuery(pS, pE, aQuery);
	if (error==KErrNone)
		{
		// update the length of the buffer
		iBuffer->Des().SetLength(pS-iBuffer->Ptr());
		}
	return error;
	}
	

void TMsvPackQuery::DoUnpackQuery(TUint8*& aPtr, CMsvSearchSortQuery* aQuery)
	{
	//size of class - sizeof(iQueryTable pointer)
	TInt sizeOfClass = Align4(sizeof(CMsvSearchSortQuery) - sizeof(TInt));
	TInt sizeQueryTable = Align4(sizeof(TMsvQueryTable) * KMaxLevelOfSearchAndSort);
	
	Mem::Copy((void*)aQuery, aPtr, sizeOfClass);
	aPtr += sizeOfClass;
	
	Mem::Copy((void*)aQuery->iQueryTable, aPtr, sizeQueryTable);
	aPtr += sizeQueryTable;
	}	

/**
Unpacks the data to a aQuery.
@internalComponent
@released
@param aQuery: Unpacked TMsvSearchSortQuery object.
*/
EXPORT_C void TMsvPackQuery::UnpackQuery(CMsvSearchSortQuery* aQuery)
	{
#if defined(_DEBUG)
	// check that the buffer contain a valid package
	const TUint8* dPos = PtrAdd(iBuffer->Ptr(), Align4(sizeof(CMsvSearchSortQuery)));
	__ASSERT_DEBUG(dPos <= PtrAdd(iBuffer->Ptr(), iBuffer->Des().MaxLength()), PanicServer(EMsvEntryOverrunBuffer));
#endif
	
	TUint8* pS = CONST_CAST(TUint8*, iBuffer->Ptr());
	DoUnpackQuery(pS, aQuery);
	}

/**
Constructor for TMsvPackedIdOperation.
@internalComponent
@released
@param aBuffer: buffer for packing
*/
EXPORT_C TMsvPackedIdOperation::TMsvPackedIdOperation(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{
	}

/**
Packs RArray of TMsvId and count value into a buffer for sending across IPC. 
@internalComponent
@released
@param aId: RArray of TMsvIds needs to pack.
@return: reurn KErrNone if successful else KErrOverflow.
*/
EXPORT_C TInt TMsvPackedIdOperation::Pack(const RArray<TMsvId>& aId)
	{
	//place for TMsvId's and count
	TInt requiredSize = (aId.Count() + 1) * 4;
	
	// check the buffer is large enough
	if (requiredSize > iBuffer->Des().MaxSize())
		{
		return KErrOverflow;
		}
		
	// set the buffer with correct length
	iBuffer->Des().SetLength(requiredSize);
	
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());
	//number of TMsvId's
	*ptr++ = aId.Count();
	
	//copy TMsvId's to buffer 	
	for (TInt count=0; count<aId.Count(); count++)
		{
		*ptr++ = aId[count];
		}
		
	return KErrNone;
	}

/**
Unpacks the data in buffer to a RArray.
@internalComponent
@released
@param aId: Unpacked RArray of TMsvIds.
*/
EXPORT_C void TMsvPackedIdOperation::UnpackL(RArray<TMsvId>& aId)
	{
	__ASSERT_DEBUG(aId.Count()==0, PanicServer(EMsvOperationUnpackSelectionNotEmpty));	
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());

	//unpack the count
	TInt count = *ptr++;
	//unpack TMsvId's to RArray
	while (count--)
		{
		aId.AppendL(*ptr++);
		}
	}


/**
Constructor for TMsvPackedIdAndMessagePart.
@internalComponent
@released
*/
EXPORT_C TMsvPackedIdAndMessagePart::TMsvPackedIdAndMessagePart()
	{
	}

/**
Size() will returns size of the data occupied by TMsvIdWithSortField.
@internalComponent
@released
@param aData: RArray of TMsvIdWithSortField.
*/	
EXPORT_C TInt TMsvPackedIdAndMessagePart::Size(const RArray<TMsvIdWithSortField>& aData)
	{
	// number of TMsvId's in RArray
	TInt count = aData.Count();
	TInt size = 0;
	
	// to hold counter value
	size += sizeof(TInt);
	
	// calculate length of RArray<TMsvId + SortFiled>
	for(TInt index = 0; index < count; index++)
		{
		size += sizeof(TMsvId);
		size += aData[index].iContentMessagePart.Length();
		}
	return size;
	}

/**
Packs or Externalize the RArray of TMsvIdWithSortField into a aWriteStream for sending across IPC. 
@internalComponent
@released
@param aWriteStream: aData will be written to aWriteStream.
@param aData: RArray of TMsvIdWithSortField
*/	
EXPORT_C void TMsvPackedIdAndMessagePart::ExternalizeL(RWriteStream& aWriteStream, RArray<TMsvIdWithSortField>& aData) const
	{
	TInt count = aData.Count();
	aWriteStream.WriteInt32L(count);
  	
  	for(TInt index=0; index < count; ++index)
 		{
 		aWriteStream.WriteInt32L(aData[index].iMessageId);
 		aWriteStream << aData[index].iContentMessagePart;
 		}
	}

/**
Unpacks or Internalize aReadStream buffer to RArray of TMsvIdWithSortField.
@internalComponent
@released
@param aReadStream: aReadStream data will be unpacked to TMsvIdWithSortField of aData.
@param aData: RArray of TMsvIdWithSortField
*/	
EXPORT_C void TMsvPackedIdAndMessagePart::InternalizeL(RReadStream& aReadStream, RArray<TMsvIdWithSortField>& aData)
	{
	TInt count =  aReadStream.ReadInt32L();
	
	TMsvIdWithSortField tmsvidAndmessagepart;
	
	for(TInt index=0; index < count; ++index)
 		{
 		tmsvidAndmessagepart.iMessageId = aReadStream.ReadInt32L();
 		aReadStream >> tmsvidAndmessagepart.iContentMessagePart;
 		aData.AppendL(tmsvidAndmessagepart);
 		}
	}


#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
EXPORT_C TMsvPackedDriveIdOperation::TMsvPackedDriveIdOperation(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{
	}
	
	
EXPORT_C void TMsvPackedDriveIdOperation::UnpackL(RArray<TDriveNumber>& aDriveNumber)
	{
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());

	// Unpack the count.
	TInt count = *ptr++;
	
	// Append TDriveNumber
	while (count--)
		{
		aDriveNumber.AppendL((TDriveNumber)*ptr++);
		}	
	}
	
	
EXPORT_C TInt TMsvPackedDriveIdOperation::Pack(const RArray<TDriveNumber>& aDriveNumber)
	{
	// place for TMsvId's and count
	TInt requiredSize = (aDriveNumber.Count() + 1) * 4;
	
	// check the buffer is large enough
	if (requiredSize > iBuffer->Des().MaxSize())
		{
		return KErrOverflow;
		}
		
	// set the buffer with correct length
	iBuffer->Des().SetLength(requiredSize);
	
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());
	//number of TMsvId's
	*ptr++ = aDriveNumber.Count();
	
	//copy TMsvId's to buffer 	
	for (TInt count=0; count<aDriveNumber.Count(); count++)
		{
		*ptr++ = aDriveNumber[count];
		}
		
	return KErrNone;
	}

#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)





#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)

/**
 * TMsvPackedHeaderStructure()
 * 
 * TMsvPackedHeaderStructure Constructor.
 *
 * @param HBufC8*&
 * @return None.
 * @leave None.
 */	
EXPORT_C TMsvPackedHeaderStructure::TMsvPackedHeaderStructure(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{
	}
	

/**
 * UnpackL()
 * 
 * Unpacks the buffer to fill header structure.
 *
 * @param RPointerArray<CFieldPair>&: Header Structure.
 * @return None.
 * @leave KErrNoMemory
 */	
EXPORT_C void TMsvPackedHeaderStructure::UnpackL(RPointerArray<CFieldPair>& aFieldDetails)
	{
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());

	// Unpack the count.
	TInt count = *ptr++;

	TInt size = 0;
	TPtrC16 ptrBuf;	

	while (count--)
		{
		CFieldPair* fieldPair = new(ELeave) CFieldPair();
		CleanupStack::PushL(fieldPair);
		size = *ptr++;
		
		const TText* textPtr = (TText*)ptr;
		ptrBuf.Set(textPtr, (size/2));			// ptrBuf is 16 bits.
		ptr += Align4(size)/sizeof(TInt);
		
		fieldPair->iFieldName = ptrBuf.AllocL();
		fieldPair->iFieldType = (EFieldType) *ptr++;
		aFieldDetails.AppendL(fieldPair);
		CleanupStack::Pop();			// fieldPair
		}	
	}
	


/**
 * Pack()
 * 
 * Packs the header structure to a buffer.
 *
 * @param RPointerArray<CFieldPair>&: Header Structure.
 * @return TInt: KErrOverflow, if buffer does not have sufficient memory.
 */		
EXPORT_C TInt TMsvPackedHeaderStructure::Pack(const RPointerArray<CFieldPair>& aFieldDetails)
	{
	TInt count = aFieldDetails.Count();
	TInt requiredSize = 0;
	
	// Calculate the size of the data to be written.
	for(TInt index=0; index<count; index++)
		{
		CFieldPair* fieldPair = aFieldDetails[index]; 	
		requiredSize += Align4(fieldPair->iFieldName->Des().Size());
		requiredSize += 8;		// 4 bytes for EFieldType and 4 bytes for size of iFieldName
		}
	
	// 4 bytes are needed to store the array count.
	requiredSize += 4;
	if(requiredSize > iBuffer->Des().MaxSize())
		{
		return KErrOverflow;
		}

	// Set the buffer with correct length
	iBuffer->Des().SetLength(requiredSize);
		
	// Start writing to the buffer.
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());
	*ptr++ = count;
	
	for(TInt index=0; index<count; index++)
		{
		CFieldPair* fieldPair = aFieldDetails[index];
		TInt size = fieldPair->iFieldName->Des().Size();
		
		*ptr++ = size;
		Mem::Copy((void*)ptr, fieldPair->iFieldName->Des().Ptr(), size);
		ptr += (Align4(size))/sizeof(TInt);
		*ptr++ = (TInt)(fieldPair->iFieldType);
		}

	// place for TMsvId's and count
	return KErrNone;
	}




/**
 * TMsvPackedHeaderData()
 * 
 * TMsvPackedHeaderData Constructor.
 *
 * @param HBufC8*&
 * @return None.
 * @leave None.
 */	
EXPORT_C TMsvPackedHeaderData::TMsvPackedHeaderData(HBufC8*& aBuffer)
: iBuffer(aBuffer)
	{
	}
	

/**
 * UnpackL()
 * 
 * Unpacks the buffer to fill header data structure.
 *
 * @param RPointerArray<CHeaderFields>&: Header Structure.
 * @return None.
 * @leave KErrNoMemory
 */		
EXPORT_C void TMsvPackedHeaderData::UnpackL(RPointerArray<CHeaderFields>& aFieldDetails)
	{
	aFieldDetails.ResetAndDestroy();
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());

	// Unpack the count.
	TInt count = *ptr++;

	TPtrC16 ptrBuf;
	while (count--)
		{
		CHeaderFields* headerRow = new(ELeave) CHeaderFields();
		CleanupStack::PushL(headerRow);
		
		headerRow->iUid = TUid::Uid(*ptr++);
		TInt colCount = *ptr++;
		while(colCount--)
			{
			CFieldPair* fieldObj = new(ELeave) CFieldPair();
			CleanupStack::PushL(fieldObj);
			
			if(EIntegerField == (EFieldType)*ptr++)
				{
				TUint32 rVal = *ptr++;
				fieldObj->iFieldNumValue = rVal;
				TUint64 lVal = (*ptr++);
				lVal = lVal << 32;
				fieldObj->iFieldNumValue |= lVal;
				}
			else
				{
				TInt size = *ptr++;
				const TText* textPtr = (TText*)ptr;
				ptrBuf.Set(textPtr, (size/2));
				ptr += Align4(size)/sizeof(TInt);
				
				fieldObj->iFieldTextValue = ptrBuf.AllocL();
				}

			headerRow->iFieldPairList.AppendL(fieldObj);
			CleanupStack::Pop(fieldObj);
			}
		
		aFieldDetails.AppendL(headerRow);
		CleanupStack::Pop(headerRow);
		}	
	}
	



/**
 * Pack()
 * 
 * Packs the header data to a buffer.
 *
 * @param RPointerArray<CHeaderFields>&: Header Data.
 * @return TInt: KErrOverflow, if buffer does not have sufficient memory.
 */		
EXPORT_C TInt TMsvPackedHeaderData::Pack(const RPointerArray<CHeaderFields>& aFieldDetails)
	{
	TInt count = aFieldDetails.Count();
	TInt requiredSize = 0;
	
	// Calculate the size of the data to be written.
	for(TInt headerRow=0; headerRow<count; headerRow++)
		{
		RPointerArray<CFieldPair>& fieldPairList = aFieldDetails[headerRow]->iFieldPairList;
		for(TInt fieldIndex=0; fieldIndex<fieldPairList.Count(); fieldIndex++)	
			{
			requiredSize += 4;			// Store the data type.
			// If it is a text field
			if(fieldPairList[fieldIndex]->iFieldTextValue)
				{
				requiredSize += 4; 		// 4 bytes to store size of iFieldTextValue
				requiredSize += Align4(fieldPairList[fieldIndex]->iFieldTextValue->Des().Size());				
				}
			else	// For Int or date field.
				{
				requiredSize += sizeof(TInt64);
				}				
			}
		requiredSize += 8;		// 4 bytes for TUid, 4 bytes for size of iFieldPairList
		}
	requiredSize += 4; 			// 4 bytes are needed to store the array count. (count)
	
	if(requiredSize > iBuffer->Des().MaxSize())
		{
		return KErrOverflow;
		}

	// Set the buffer with correct length
	iBuffer->Des().SetLength(requiredSize);
	
	// Start writing to the buffer.
	TInt* ptr = (TInt*) CONST_CAST(TUint8*, iBuffer->Ptr());
	*ptr++ = count;
	
	for(TInt headerRow=0; headerRow<count; headerRow++)
		{
		// For each header row...
		
		// Store UID of the row.
		*ptr++ = aFieldDetails[headerRow]->iUid.iUid;
		
		// Store field list.
		RPointerArray<CFieldPair>& fieldPairList = aFieldDetails[headerRow]->iFieldPairList;
		*ptr++ = fieldPairList.Count();
		
		for(TInt fieldIndex=0; fieldIndex<fieldPairList.Count(); fieldIndex++)
			{
			CFieldPair* fieldPair = fieldPairList[fieldIndex];
			if(fieldPair->iFieldTextValue)
				{
				// Data type
				*ptr++ = ETextField;				
				// Data Size
				TInt textSize = fieldPair->iFieldTextValue->Des().Size();
				*ptr++ = textSize;
				// Data
				Mem::Copy((void*)ptr, fieldPair->iFieldTextValue->Des().Ptr(), textSize);
				ptr += Align4(textSize)/sizeof(TInt);
				}
			else
				{
				// Data type
				*ptr++ = EIntegerField;
				// Data (64 bits)
				TUint64 maskVal = KMaxTUint32;
				*ptr++ = (fieldPair->iFieldNumValue) & maskVal;
				maskVal = ~maskVal;
				*ptr++ = (fieldPair->iFieldNumValue & maskVal) >> 32;
				}
			}
		}
		
	return KErrNone;
	}
	


#endif		// #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)




