--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/CMsvPlainBodyText.cpp Fri Jun 04 10:32:16 2010 +0100
@@ -0,0 +1,1143 @@
+// Copyright (c) 2007-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:
+// CMsvPlainBodyText.cpp
+//
+
+#include <cmsvplainbodytext.h>
+#include "cmsvbodytext.h"
+#include <mmsvstoremanager.h>
+#include "MSVPANIC.H"
+#include <txtrich.h>
+#include <utf.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "msvconsts.h"
+#endif
+
+/**
+The number of characters that will be converted to Unicode at any one time.
+*/
+const TInt KMaxDecodeUnicodeLength = 20;
+
+/**
+The NewL factory function for Write operation.
+@param aMsvStoreManager The MMsvStoreManager reference to call Store related RFile APIs
+@param aStore The CMsvStore object.
+@param aIs8Bit TBool indicating whether to store bdy text as 8/16 bit.
+@param aCharsetId The charset of the body part.
+@param aDefaultCharsetId The default charset of the system.
+@param aMessageId The Id of the message that is to be stored.
+@param aFs The RFs for handling RFile related operations.
+@return CMsvPlainBodyText.
+*/
+CMsvPlainBodyText* CMsvPlainBodyText::NewL(MMsvStoreManager& aMsvStoreManager, CMsvStore& aStore, TBool aIs8Bit, TUint aCharsetId, TUint aDefaultCharsetId, TMsvId aMessageId, RFs& aFs)
+ {
+ CMsvPlainBodyText* self = new(ELeave)CMsvPlainBodyText(aMsvStoreManager, aStore, aIs8Bit, aCharsetId, aDefaultCharsetId, aMessageId, aFs);
+ CleanupStack::PushL(self);
+ self->ConstructWriteL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Overloaded NewL for Read operation.
+@param aMsvStoreManager The MMsvStoreManager reference to call Store related RFile APIs
+@param aStore The CMsvStore object.
+@param aMessageId The Id of the message that is to be stored.
+@param aFs The RFs for handling RFile related operations.
+@param aChunkLength The length of the chunk that will be stored/restored in single operaion
+@return CMsvPlainBodyText.
+*/
+CMsvPlainBodyText* CMsvPlainBodyText::NewL(MMsvStoreManager& aMsvStoreManager, CMsvStore& aStore, TMsvId aMessageId, RFs& aFs, TInt aChunkLength)
+ {
+ CMsvPlainBodyText* self = new(ELeave)CMsvPlainBodyText(aMsvStoreManager, aStore, aMessageId, aFs, aChunkLength);
+ CleanupStack::PushL(self);
+ self->ConstructReadL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Default Constructor for write operation.
+*/
+CMsvPlainBodyText::CMsvPlainBodyText(MMsvStoreManager& aMsvStoreManager, CMsvStore& aStore, TBool aIs8Bit, TUint aCharsetId, TUint aDefaultCharsetId, TMsvId aMessageId,RFs& aFs)
+: CMsgActive(EPriorityNormal), iMsvStoreManager(aMsvStoreManager), iStore(aStore), iIs8Bit(aIs8Bit), iCharsetId(aCharsetId), iDefaultCharsetId(aDefaultCharsetId),
+ iMessageId(aMessageId), iFSession(aFs), iMsvFileStatus(EMsvFileWriting)
+ {
+ iAvailable = CCnvCharacterSetConverter::ENotAvailable;
+ CActiveScheduler::Add(this);
+ }
+
+/**
+Default Constructor called for Read operation..
+*/
+CMsvPlainBodyText::CMsvPlainBodyText(MMsvStoreManager& aMsvStoreManager, CMsvStore& aStore, TMsvId aMessageId, RFs& aFs, TInt aChunkLength)
+: CMsgActive(EPriorityNormal), iMsvStoreManager(aMsvStoreManager), iStore(aStore), iMessageId(aMessageId), iFSession(aFs), iPos(0), iChunkMaxLength(aChunkLength),
+ iStartPosOfNextChunk(0), iMsvFileStatus(EMsvFileReading)
+ {
+ iAvailable = CCnvCharacterSetConverter::ENotAvailable;
+ CActiveScheduler::Add(this);
+ }
+
+/**
+ConstructWriteL for creating and writing to the plain bodytext file.
+*/
+void CMsvPlainBodyText::ConstructWriteL()
+ {
+ RMsvWriteStream out;
+
+ if(iIs8Bit)
+ {
+ out.AssignLC(iStore, KMsvPlainBodyText8);
+ out.WriteUint32L(iCharsetId);
+ out.WriteUint32L(iDefaultCharsetId);
+ }
+ else
+ {
+ out.AssignLC(iStore, KMsvPlainBodyText16);
+ }
+ // iIsCommitted will be EFalse at this point.
+ out.WriteUint32L(iIsCommitted);
+
+ TBuf<KFileNameFixedWidth> fileName;
+ fileName.NumFixedWidth(iMessageId, EHex, KFileNameFixedWidth);
+
+ out << (TDes&)fileName;
+ out.CommitL();
+ out.Close();
+ iStore.CommitL();
+
+ iMsvStoreManager.CreatePlainTextFileL(iFile, iMessageId);
+
+ iRemainingConvertedData.Create(KMaxDecodeUnicodeLength);
+ CleanupStack::PopAndDestroy(&out);
+ }
+
+/**
+ConstructL for Read operation.
+*/
+void CMsvPlainBodyText::ConstructReadL()
+ {
+ // Check whether the data is stored in old-style non-chunk storage mechanism.
+ if(iStore.IsPresentL(KMsvEntryRichTextBody) || iStore.IsPresentL(KMsv8BitEncodedBodyData))
+ {
+ iParaLayer = CParaFormatLayer::NewL();
+ iCharLayer = CCharFormatLayer::NewL();
+ iRichText = CRichText::NewL(iParaLayer, iCharLayer);
+ iStore.RestoreBodyTextL(*iRichText);
+ }
+ else // Data is stored using the new chunk storage mechanism.
+ {
+ RMsvReadStream in;
+ if(iStore.IsPresentL(KMsvPlainBodyText8))
+ {
+ in.OpenLC(iStore, KMsvPlainBodyText8);
+ iCharsetId = in.ReadUint32L();
+ iDefaultCharsetId = in.ReadUint32L();
+ iIs8Bit = ETrue;
+ }
+ else if(iStore.IsPresentL(KMsvPlainBodyText16))
+ {
+ in.OpenLC(iStore, KMsvPlainBodyText16);
+ }
+ else
+ {
+ // The stream is not found.
+ User::Leave(KErrNotFound);
+ }
+ iIsCommitted = in.ReadUint32L();
+ HBufC* filename = HBufC::NewLC(in,KMaxFileName);
+ iFilePath = HBufC::NewL(KMaxFileName);
+
+ TPtr16 fileNamePtr = iFilePath->Des();
+ iMsvStoreManager.BodyTextFilePathL(iMessageId, fileNamePtr);
+ fileNamePtr.Append(*filename);
+ iMsvStoreManager.OpenBodyTextFileForReadL(iFile, iMessageId, *iFilePath);
+
+ iRemainingConvertedData.Create(KMaxDecodeUnicodeLength);
+ CleanupStack::PopAndDestroy(2,&in);// filename, in
+ }
+ }
+
+/**
+Destructor
+*/
+EXPORT_C CMsvPlainBodyText::~CMsvPlainBodyText()
+ {
+ delete iConverter;
+ delete iParaLayer;
+ delete iCharLayer;
+ delete iRichText;
+ delete iFilePath;
+ iTempChunk16.Close();
+ iRemainingConvertedData.Close();
+
+ iStartPosOfEachChunkInFile.Close();
+ iRfileReadBuf8.Close();
+
+ // Cannot leave in destructor, so ignore any error.
+ // iFile will be closed by a call to RevertL method.
+ TRAP_IGNORE(RevertL());
+ }
+
+/**
+Store the plain body text part in chunks.
+@param aChunk. The 8 bit chunk that is to be stored.
+@param aStatus. The TRequestStatus parameter for this request.
+@leave KErrAccessDenied. If CMsvStore was opened in Read mode or
+ If CommitL is already called.
+@leave Other Standard system-wide error codes.
+@return void.
+*/
+EXPORT_C void CMsvPlainBodyText::StoreChunkL(const TDesC8& aChunk, TRequestStatus& aStatus)
+ {
+ iTempChunk16.Close();
+ if(iIsCommitted || iMsvFileStatus == EMsvFileReading)
+ {
+ // Leave if CommitL is already called or CMsvStore is opened in Read mode.
+ User::Leave(KErrAccessDenied);
+ }
+
+ if(iIs8Bit)
+ {
+ iFile.Write(aChunk, aStatus);
+ }
+ // convert to 16..........
+ else
+ {
+ ConvertChunkToUnicodeForStoreL(aChunk);
+ iFile.Write(iRfileWritePtr8, aStatus);
+ }
+ }
+
+/**
+Store the plain body text part in chunks,synchronous version.
+@param aChunk. The 8 bit chunk that is to be stored.
+@leave KErrAccessDenied. If CMsvStore was opened in Read mode or
+ If CommitL is already called.
+@leave Other Standard system-wide error codes.
+@return void.
+*/
+EXPORT_C void CMsvPlainBodyText::StoreChunkL(const TDesC8& aChunk)
+ {
+ iTempChunk16.Close();
+ if(iIsCommitted || iMsvFileStatus == EMsvFileReading)
+ {
+ // Leave if CommitL is already called or CMsvStore is opened in Read mode.
+ User::Leave(KErrAccessDenied);
+ }
+ if(iIs8Bit)
+ {
+ User::LeaveIfError(iFile.Write(aChunk));
+ }
+ else
+ {
+ ConvertChunkToUnicodeForStoreL(aChunk);
+ User::LeaveIfError(iFile.Write(iRfileWritePtr8));
+ }
+ }
+
+/**
+Converts the 8 bit chunk to Unicode.
+@param aChunk The 8bit chunk to be converted.
+@return void.
+*/
+void CMsvPlainBodyText::ConvertChunkToUnicodeForStoreL(const TDesC8& aChunk)
+ {
+ TInt chunkLength = aChunk.Length();
+ TPtrC8 chunkPtr8(aChunk);
+
+ iTempChunk16.Create(chunkLength);
+
+ PrepareToConvertL();
+ TInt charsetState = CCnvCharacterSetConverter::KStateDefault;
+
+ if (iAvailable == CCnvCharacterSetConverter::ENotAvailable)
+ {
+ // Copy data if character convertor not available
+ iTempChunk16.Copy(chunkPtr8);
+ }
+ else
+ {
+ TInt rem = iConverter->ConvertToUnicode(iTempChunk16, chunkPtr8, charsetState);
+ if (rem < 0)
+ {
+ // Copy the data without conversion,if there was error while converting.
+ iTempChunk16.Copy(aChunk);
+ }
+ else if(rem > 0)
+ {
+ // Some of the characters were not converted because the output buffer
+ // was not long enough, so reallocate the output buffer.
+ do
+ {
+ TBuf<KMaxDecodeUnicodeLength> buf;
+ chunkPtr8.Set(chunkPtr8.Right(rem));
+ rem = iConverter->ConvertToUnicode(buf, chunkPtr8, charsetState);
+ if(iTempChunk16.Length() + buf.Length() > iTempChunk16.MaxLength())
+ {
+ iTempChunk16.ReAllocL(iTempChunk16.Length() + buf.Length());
+ }
+ iTempChunk16.Append(buf);
+ }while(rem > 0);
+ }
+ }
+ TPtrC8 convertedChunk8((TUint8*)(iTempChunk16.Ptr()), iTempChunk16.Length()*2);
+ iRfileWritePtr8.Set(convertedChunk8);
+ }
+
+/**
+Store the body part in chunks(16 bit version).
+@param aChunk The 16 bit chunk that is to be stored.
+@param aStatus The TRequestStatus parameter for this request.
+@leave KErrNotSupported If the 8-bit storage was enabled.
+@leave KErrAccessDenied If CMsvStore was opened in Read mode or
+ IfCommitL is already called.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::StoreChunkL(const TDesC16& aChunk, TRequestStatus& aStatus)
+ {
+ if(iIs8Bit)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ if(iIsCommitted || iMsvFileStatus == EMsvFileReading)
+ {
+ // Leave if CommitL is already called or CMsvStore is opened in Read mode.
+ User::Leave(KErrAccessDenied);
+ }
+
+ TPtrC8 inFileBuf8((TUint8*)(aChunk.Ptr()), aChunk.Length()*2);
+ iFile.Write(inFileBuf8, aStatus);
+ }
+
+/**
+Store the body part in chunks(16 bit synchronous version).
+@param aChunk The 16 bit chunk that is to be stored.
+@leave KErrNotSupported If the 8-bit storage was enabled.
+@leave KErrAccessDenied If CMsvStore was opened in Read mode or
+ If CommitL is already called.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::StoreChunkL(const TDesC16& aChunk)
+ {
+ if(iIs8Bit)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ if(iIsCommitted || iMsvFileStatus == EMsvFileReading)
+ {
+ // Leave if CommitL is already called or CMsvStore is opened in Read mode.
+ User::Leave(KErrAccessDenied);
+ }
+
+ TPtrC8 inFileBuf8((TUint8*)(aChunk.Ptr()), aChunk.Length()*2);
+ User::LeaveIfError(iFile.Write(inFileBuf8));
+ }
+
+/**
+Returns the size of body text in bytes.
+@param None.
+@return TInt The size of the plain body text stored in bytes.
+*/
+EXPORT_C TInt CMsvPlainBodyText::Size()
+ {
+ TInt size=0;
+ if(iRichText)
+ {
+ size = iRichText->DocumentLength() * 2;// Since Unicode multiply by 2.
+ }
+ else
+ {
+ iFile.Size(size);
+ }
+ return size;
+ }
+
+/**
+Converts and stores the CRichText contents to a plain text.
+@param aRichText The CRichText object that will be stored as plain body text.
+@leave KErrNotSupported If CMsvStore was opened in Read mode or
+ If CommitL is already called.
+@leave Other Standard system-wide error codes.
+@return void.
+*/
+EXPORT_C void CMsvPlainBodyText::StoreRichTextAsPlainTextL(CRichText& aRichText)
+ {
+ if(iIs8Bit)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ if(iIsCommitted || iMsvFileStatus == EMsvFileReading)
+ {
+ // Leave if CommitL is already called or CMsvStore is opened in Read mode.
+ User::Leave(KErrAccessDenied);
+ }
+ // create a buffer of 512 bytes to extract data from a rich text instead of extracting
+ // the entire richtext so that 2 copies of the mail is not created in RAM.
+ TBuf<KMsvDecodeChunkLength> richBuf;
+ TInt currentPos = 0;
+ TInt richTextLen = aRichText.DocumentLength();
+ TInt lengthToExtract = richTextLen;
+ while(richTextLen > 0)
+ {
+ if(lengthToExtract > KMsvDecodeChunkLength)
+ {
+ lengthToExtract = KMsvDecodeChunkLength;
+ }
+ aRichText.Extract(richBuf,currentPos,lengthToExtract);
+ TPtrC8 richTextPtr1((TUint8*)(richBuf.Ptr()), richBuf.Length() * 2);
+ User::LeaveIfError(iFile.Write(richTextPtr1));
+ currentPos += lengthToExtract;
+ richTextLen -=lengthToExtract;
+ if(richTextLen <= lengthToExtract)
+ {
+ lengthToExtract = richTextLen;
+ }
+ }
+ }
+
+/**
+Retrieve the next chunk of the plain body text.
+@param aChunk The output parameter contains the requested chunk.
+@param aStatus. The TRequestStatus for this request.
+@leave KErrAccessDenied If CMsvStore was opened in Write mode.
+@leave KErrNotSupported If 16-bit storage is enabled.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::NextChunkL(TDes8& aChunk, TRequestStatus& aStatus)
+ {
+ if(!iIs8Bit)
+ {
+ // If 16-bit storage is enabled.
+ User::Leave(KErrNotSupported);
+ }
+ if(iMsvFileStatus == EMsvFileWriting)
+ {
+ // Leave if CMsvStore is opened in Write mode.
+ User::Leave(KErrAccessDenied);
+ }
+ if(aChunk.MaxLength() < iChunkMaxLength)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ iChunk8 = &aChunk;
+ iChunk8->SetLength(0);
+
+ iRetrieving8bit = ETrue;
+
+ //store the current position of the file so that if request cancels and for next
+ // call to NextChunkL() will attempt to read the same chunk that was cancelled
+ iCurrentFilePos = 0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, iCurrentFilePos));
+
+ Queue(aStatus);
+ iFile.Read(aChunk, iChunkMaxLength, iStatus);
+ SetActive();
+ }
+
+/**
+Retrieve the next chunk of the plain body text.
+@param aChunk The output parameter contains the requested chunk.
+@leave KErrNotSupported If CMsvStore was opened in Write mode.
+@leave KErrNotSupported If 16-bit storage is enabled.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::NextChunkL(TDes8& aChunk)
+ {
+ if(!iIs8Bit)
+ {
+ // If 16-bit storage is enabled.
+ User::Leave(KErrNotSupported);
+ }
+ if(iMsvFileStatus == EMsvFileWriting)
+ {
+ // Leave if CMsvStore is opened in Write mode.
+ User::Leave(KErrAccessDenied);
+ }
+ if(aChunk.MaxLength() < iChunkMaxLength)
+ {
+ User::Leave(KErrUnderflow);
+ }
+ aChunk.SetLength(0);
+ User::LeaveIfError(iFile.Read(aChunk, iChunkMaxLength));
+
+ if(aChunk.Length()>0)
+ {
+ iReadChunkLength = aChunk.Length();
+ }
+ }
+
+/**
+Retrieve the next chunk of the plain body text. If body is stored as 8bit, the chunk is
+converted to unicode.Unconverted bytes will be converted while reading the next chunk.
+@param aChunk The output parameter contains the requested chunk.If no more data is in Store this
+ contains NULL descriptor.
+@param aStatus The TRequestStatus for this request.
+@leave KErrAccessDenied If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::NextChunkL(TDes16& aChunk, TRequestStatus& aStatus)
+ {
+ if(iMsvFileStatus == EMsvFileWriting)
+ {
+ // Leave if CMsvStore is opened in Write mode.
+ User::Leave(KErrAccessDenied);
+ }
+
+ if(aChunk.MaxLength() < iChunkMaxLength)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ if(iRichText)
+ {
+ ExtractNextChunkFromRichText(aChunk);
+ TRequestStatus *status=&aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ else
+ {
+ iRfileReadBuf8.Close();
+ iChunk16 = &aChunk;
+ iChunk16->SetLength(0);
+
+ //store the current position of the file so that if request cancels and for next
+ // call to NextChunkL() will attempt to read the same chunk that was cancelled
+ iCurrentFilePos = 0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, iCurrentFilePos));
+
+ Queue(aStatus);
+ if(iIs8Bit)
+ {
+ // if there is any converted data then append to aChunk
+ if(iRemainingConvertedData.Length() != 0)
+ {
+ iChunk16->Append(iRemainingConvertedData);
+ iRemainingConvertedData.SetLength(0);
+ }
+
+ iRfileReadBuf8.Create(iChunkMaxLength);
+ // 8-bit data read will be converted to Unicode in DoRunL.
+ iFile.Read(iRfileReadBuf8, iChunkMaxLength, iStatus);
+ SetActive();
+ }
+ else
+ {
+ iRfileReadBuf8.Create(iChunkMaxLength*2);
+ iFile.Read(iRfileReadBuf8, iChunkMaxLength*2, iStatus);
+ SetActive();
+ }
+ }
+ }
+
+/**
+Retrieve the next chunk of the plain body text. If body is stored as 8bit, convert the chunk to Unicode.
+Unconverted bytes will be converted while reading the next chunk.
+@param aChunk The output parameter contains the requested chunk.If no more data is in Store this
+ contains NULL descriptor.
+@leave KErrAccessDenied If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::NextChunkL(TDes16& aChunk)
+ {
+ if(iMsvFileStatus == EMsvFileWriting)
+ {
+ // Leave if CMsvStore is opened in Write mode.
+ User::Leave(KErrAccessDenied);
+ }
+
+ if(aChunk.MaxLength() < iChunkMaxLength)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ if(iRichText)
+ {
+ ExtractNextChunkFromRichText(aChunk);
+ }
+ else if(iIs8Bit)
+ {
+ iRfileReadBuf8.Close();
+ iChunk16 = &aChunk;
+
+ iChunk16->SetLength(0);
+
+ TInt numOfBytesInCurrentChunk = 0;
+ // if there is any converted data then append to aChunk
+ if(iRemainingConvertedData.Length() != 0)
+ {
+ iChunk16->Append(iRemainingConvertedData);
+ iRemainingConvertedData.SetLength(0);
+ }
+
+ PrepareToConvertL();
+ if(iAvailable != CCnvCharacterSetConverter::EAvailable)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ iIsLastChunk = EFalse;
+ while(iChunk16->Length() < iChunkMaxLength && !iIsLastChunk)
+ {
+ iRfileReadBuf8.Create(iChunkMaxLength);
+ iFile.Read(iRfileReadBuf8, iChunkMaxLength);
+ // iRfileReadBuf8 will be closed when ConvertChunkToUnicodeForRestoreL returns.
+ numOfBytesInCurrentChunk = ConvertChunkToUnicodeForRestoreL();
+ }
+
+ // Push start position of current chunk in to the stack.
+ iStartPosOfEachChunkInFile.Append(iStartPosOfNextChunk);
+ iStartPosOfNextChunk += numOfBytesInCurrentChunk;
+ iReadChunkLength = numOfBytesInCurrentChunk;
+ }
+ else // KMsvPlainBodyText16
+ {
+ HBufC8* inBuffer = HBufC8::NewLC(iChunkMaxLength * 2);
+ TPtr8 inPtr16(inBuffer->Des());
+ iFile.Read(inPtr16, iChunkMaxLength * 2); // Multiply by 2 to get no of bytes.
+ TPtrC16 ptr16((TUint16*)(inBuffer->Ptr()), inBuffer->Length() / 2);
+ aChunk.Copy(ptr16);
+ CleanupStack::PopAndDestroy(inBuffer);
+ if(aChunk.Length())
+ {
+ iReadChunkLength = aChunk.Length();
+ }
+
+ }
+ }
+
+/**
+Extracts a chunk of iChunkMaxLength or less, from the CRichText object.
+*/
+void CMsvPlainBodyText::ExtractNextChunkFromRichText(TDes16& aChunk)
+ {
+ TInt docLength = iRichText->DocumentLength();
+ // If we are at the end of the body text.
+ if(iPos >= docLength)
+ {
+ aChunk.Copy(KNullDesC16);
+ }
+ else
+ {
+ if(iPos+iChunkMaxLength <= docLength)
+ {
+ iRichText->Extract(aChunk, iPos, iChunkMaxLength);
+ iPos += iChunkMaxLength;
+ iReadChunkLength = iChunkMaxLength;
+ }
+ else // If it is the last chunk.
+ {
+ iRichText->Extract(aChunk, iPos, docLength-iPos);
+ iReadChunkLength = docLength-iPos;
+ iPos = docLength;
+ }
+ }
+ }
+
+/**
+Retrieve the previous chunk of the plain body text asynchronously.
+@param aChunk The output parameter containing the requested chunk on completion.
+@param aStatus The TRequestStatus for this request.
+@leave KErrNotSupported If 16-bit storage is enabled.
+@leave KErrAccessDenied If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::PreviousChunkL(TDes8& aChunk, TRequestStatus& aStatus)
+ {
+ TInt currentPos = 0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, currentPos));
+
+ // point to the position from where previous chunk was read.
+ currentPos -= iReadChunkLength;
+ // point to the position from where the new chunk is to be read.
+ currentPos -= iChunkMaxLength;
+
+ if(currentPos >= 0)
+ {
+ iFile.Seek(ESeekStart, currentPos);
+ NextChunkL(aChunk, aStatus);
+ }
+ else
+ {
+ aChunk.Copy(KNullDesC8);
+ TRequestStatus *status = &aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+
+/**
+Retrieve the previous chunk of the plain body text.
+@param aChunk The output parameter containing the requested chunk.
+@leave KErrNotSupported If 16-bit storage is enabled.
+@leave KErrAccessDenied If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::PreviousChunkL(TDes8& aChunk)
+ {
+ TInt currentPos = 0;
+ iFile.Seek(ESeekCurrent, currentPos);
+
+ // point to the position from where previous chunk was read.
+ currentPos -= iReadChunkLength;
+ // point to the position from where the new chunk is to be read.
+ currentPos -= iChunkMaxLength;
+
+ if(currentPos >= 0)
+ {
+ iFile.Seek(ESeekStart, currentPos );
+ NextChunkL(aChunk);
+ }
+ else
+ {
+ aChunk.Copy(KNullDesC8);
+ }
+ }
+
+/**
+Retrieve the previous chunk of the plain body text asynchronously.DoRunl converts the chunk to unicode.
+@param aChunk The output parameter containing the requested chunk on completion.
+@param aStatus The TRequestStatus for this request.
+@leave KErrNotSupported If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::PreviousChunkL(TDes16& aChunk, TRequestStatus& aStatus)
+ {
+ iPrevChunk = ETrue;
+ if(iRichText)
+ {
+ ExtractPreviousChunkFromRichText(aChunk);
+ TRequestStatus *status = &aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ else
+ {
+ if(iIs8Bit && iStartPosOfEachChunkInFile.Count() >= 2)
+ {
+ delete iRemainingUnConvertedData;
+ iRemainingUnConvertedData = NULL;
+ TInt count = iStartPosOfEachChunkInFile.Count() - 1;
+ TInt numOfBytes = iStartPosOfEachChunkInFile[count] - iStartPosOfEachChunkInFile[count - 1];
+ iFile.Seek(ESeekStart, iStartPosOfEachChunkInFile[count - 1] );
+ iReadChunkLength = numOfBytes;
+ NextChunkL(aChunk,aStatus);
+ }
+ else
+ {
+ TInt startPos = 0;
+ TInt currentPos = 0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, currentPos));
+ TInt prevChunkPos = 0;
+ if(currentPos > 0)
+ {
+ startPos = currentPos - iReadChunkLength * 2;
+ if(startPos > 0)
+ {
+ prevChunkPos = startPos - iChunkMaxLength * 2;
+ if(prevChunkPos >= 0)
+ {
+ iFile.Seek(ESeekStart, prevChunkPos);
+ NextChunkL(aChunk,aStatus);
+ }
+ else
+ {
+ iChunk16->Copy(KNullDesC16);
+ TRequestStatus *status = &aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+ else
+ {
+ aChunk.Copy(KNullDesC16);
+ TRequestStatus *status = &aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+ else
+ {
+ aChunk.Copy(KNullDesC16);
+ TRequestStatus *status = &aStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+ }
+ }
+
+/**
+Retrieve the Previouschunk of the plain body text. If body is stored as 8bit, convert the chunk to Unicode.
+@param aChunk The output parameter contains the requested chunk.
+@leave KErrNotSupported If CMsvStore was opened in Write mode.
+@leave KErrUnderflow If aChunk MaxLength is less than iChunkMaxLength.
+@leave Other Standard system-wide error codes.
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::PreviousChunkL(TDes16& aChunk)
+ {
+ if(iRichText)
+ {
+ ExtractPreviousChunkFromRichText(aChunk);
+ }
+ else
+ {
+ if(iIs8Bit && iStartPosOfEachChunkInFile.Count() >= 2)
+ {
+ delete iRemainingUnConvertedData;
+ iRemainingUnConvertedData = NULL;
+
+ TInt count = iStartPosOfEachChunkInFile.Count() - 1;
+
+ iFile.Seek(ESeekStart, iStartPosOfEachChunkInFile[count - 1] );
+ TInt numOfBytes = iStartPosOfEachChunkInFile[count] - iStartPosOfEachChunkInFile[count - 1];
+ iReadChunkLength = numOfBytes;
+ // Pop one position from iStartPosOfEachChunkInFile
+ iStartPosOfNextChunk = iStartPosOfEachChunkInFile[count];
+ iStartPosOfEachChunkInFile.Remove(count);
+ NextChunkL(aChunk);
+ }
+ else
+ {
+ TInt startPos = 0;
+ TInt currentPos = 0;
+ iFile.Seek(ESeekCurrent, currentPos);
+ TInt prevChunkPos = 0;
+
+ if(currentPos > 0)
+ {
+ startPos = currentPos - iReadChunkLength * 2;// Multiply by 2 to get no of bytes.
+ if(startPos > 0)
+ {
+ prevChunkPos = startPos - iChunkMaxLength * 2;// Multiply by 2 to get no of bytes.
+ if(prevChunkPos >= 0)
+ {
+ iFile.Seek(ESeekStart, prevChunkPos );
+ NextChunkL(aChunk);
+ }
+ else
+ {
+ aChunk.Copy(KNullDesC16);
+ }
+ }
+ }
+ }
+ }
+ }
+
+/**
+Extracts a chunk of iChunkMaxLength or less, from the CRichText object.
+*/
+void CMsvPlainBodyText::ExtractPreviousChunkFromRichText(TDes16& aChunk)
+ {
+ iPos -= iReadChunkLength;
+ if(iPos > 0)
+ {
+ iPos -= iChunkMaxLength;
+ if(iPos >= 0)
+ {
+ iRichText->Extract(aChunk, iPos, iChunkMaxLength);
+ iPos += iChunkMaxLength;
+ iReadChunkLength = iChunkMaxLength;
+ }
+ }
+ }
+
+/**
+Asynchronously retrives the body text chunks.If body is stored as 8bit, converts the chunk to Unicode.
+@param None.
+@return
+*/
+void CMsvPlainBodyText::DoRunL()
+ {
+ User::LeaveIfError(iStatus.Int());
+ if(iRetrieving8bit)
+ {
+ if(iChunk8->Length())
+ {
+ iReadChunkLength = iChunk8->Length();
+ }
+ Complete(iStatus.Int());
+ iRetrieving8bit = EFalse;
+ }
+ else
+ {
+ iIsLastChunk = EFalse;
+ if (iIs8Bit)
+ {
+ PrepareToConvertL();
+ if(iAvailable != CCnvCharacterSetConverter::EAvailable)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ TInt numOfBytesInCurrentChunk = ConvertChunkToUnicodeForRestoreL();
+ if(iChunk16->Length() < iChunkMaxLength && !iIsLastChunk)
+ {
+ // iRfileReadBuf8 will be closed when ConvertChunkToUnicodeForRestoreL returns.
+ iRfileReadBuf8.Create(iChunkMaxLength);
+ //store the current position of the file so that if request cancels and for next
+ // call to NextChunkL() will attempt to read the same chunk that was cancelled
+ iCurrentFilePos = 0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, iCurrentFilePos));
+ iFile.Read(iRfileReadBuf8, iChunkMaxLength, iStatus);
+ SetActive();
+ }
+ else
+ {
+ if(iPrevChunk)
+ {
+ //Pop one position from iStartPosOfEachChunkInFile
+ TInt count = iStartPosOfEachChunkInFile.Count() - 1;
+ iStartPosOfNextChunk = iStartPosOfEachChunkInFile[count];
+ iStartPosOfEachChunkInFile.Remove(count);
+ iPrevChunk = EFalse;
+ }
+ else
+ {
+ // Push Start position of current chunk in to the stack.
+ iStartPosOfEachChunkInFile.Append(iStartPosOfNextChunk);
+ iStartPosOfNextChunk += numOfBytesInCurrentChunk;
+ }
+ iReadChunkLength = numOfBytesInCurrentChunk;
+ Complete(iStatus.Int());
+ }
+ }
+ else
+ {
+ TPtrC16 ptr16((TUint16*)(iRfileReadBuf8.Ptr()), iRfileReadBuf8.Length()/2);
+ iChunk16->Copy(ptr16);
+ iRfileReadBuf8.Close();
+ Complete(iStatus.Int());
+ iReadChunkLength = ptr16.Length();
+ }
+ }
+ }
+
+/**
+Converts the 8 bit chunk to unicode.When this is called iRfileReadBuf8 will have the 8-bit
+data that needs to be converted to unicode.8 bit data that is not converted is copied to
+iRemainingUnConvertedData, which is used in conversion when this is called again.
+@param None.
+@return TInt Number of bytes in Current Chunk.
+*/
+TInt CMsvPlainBodyText::ConvertChunkToUnicodeForRestoreL()
+ {
+ TBufC16<KMaxDecodeUnicodeLength> outBuf;
+ TPtr16 outPtr = outBuf.Des();
+ TInt charsetState = CCnvCharacterSetConverter::KStateDefault;
+
+ TInt numOfBytesInCurrentChunk = 0;
+ TInt bytesUnconverted = 0;
+ // Check if we are processing the last chunk.
+ if(iRfileReadBuf8.Length() == 0)
+ {
+ iIsLastChunk = ETrue;
+ }
+ // Check if there are data that are yet to be converted.
+ if(iRemainingUnConvertedData)
+ {
+ if(iIsLastChunk)
+ {
+ TPtrC8 remPtr(*iRemainingUnConvertedData);
+ // If it is the lastchunk then convert the data, need not insert to input buffer.
+ if(iIsLastChunk)
+ {
+ while(remPtr.Length() > 0)
+ {
+ bytesUnconverted = iConverter->ConvertToUnicode(outPtr, remPtr, charsetState);
+ User::LeaveIfError(bytesUnconverted);
+ iChunk16->Append(outPtr);
+ remPtr.Set(remPtr.Right(bytesUnconverted));
+ }
+ }
+ }
+ else // If there are data that are yet to be converted insert it at the front of the input buffer.
+ {
+ iRfileReadBuf8.ReAllocL(iRfileReadBuf8.Length() + iRemainingUnConvertedData->Length());
+ iRfileReadBuf8.Insert(0, *iRemainingUnConvertedData);
+ }
+ delete iRemainingUnConvertedData;
+ iRemainingUnConvertedData = NULL;
+ }
+
+ TPtrC8 remainingUnconvertedData(iRfileReadBuf8);
+ // This loop will convert the data to unicode till iChunk16 is filled with the converted data.
+ while(remainingUnconvertedData.Length() >= KMaxDecodeUnicodeLength || (iIsLastChunk && remainingUnconvertedData.Length() > 0))
+ {
+ bytesUnconverted = iConverter->ConvertToUnicode(outPtr, remainingUnconvertedData, charsetState);
+ User::LeaveIfError(bytesUnconverted);
+ TInt bytesConverted = remainingUnconvertedData.Length()-bytesUnconverted;
+
+ if (iChunk16->Length() + outPtr.Length() <= iChunk16->MaxLength())
+ {
+ iChunk16->Append(outPtr);
+ numOfBytesInCurrentChunk += bytesConverted;
+ }
+ else
+ {
+ // Copy remaining unconverted data to iRemainingConvertedData,
+ // if outBuf.Length() is greater than the space remains in aChunk
+ TInt availableSpaceOnChunk = iChunk16->MaxLength() - iChunk16->Length();
+ iChunk16->Append(outPtr.Left(availableSpaceOnChunk));
+
+ numOfBytesInCurrentChunk += bytesConverted - iRemainingConvertedData.Length();
+ iRemainingConvertedData.Append(outPtr.Mid(availableSpaceOnChunk));
+ remainingUnconvertedData.Set(remainingUnconvertedData.Right(bytesUnconverted));
+ break;
+ }
+ remainingUnconvertedData.Set(remainingUnconvertedData.Right(bytesUnconverted));
+ }
+
+ // Copy remaining unconverted data to iRemainingUnConvertedData
+ if(remainingUnconvertedData.Length())
+ {
+ __ASSERT_DEBUG(iRemainingUnConvertedData == NULL, PanicServer(EMsvBufferNotEmpty));
+ iRemainingUnConvertedData = remainingUnconvertedData.AllocL();
+ }
+ iRfileReadBuf8.Close();
+ return numOfBytesInCurrentChunk;
+ }
+
+/**
+Creates the character converter and specifies the character set to convert to or from.
+Leaves if the specified or default character set is not available.
+@param None.
+@return void.
+*/
+void CMsvPlainBodyText::PrepareToConvertL()
+ {
+ if(!iConverter)
+ {
+ iConverter = CCnvCharacterSetConverter::NewL();
+ if (iCharsetId != 0)
+ {
+ iAvailable = iConverter->PrepareToConvertToOrFromL(iCharsetId, iFSession);
+ }
+ if (iAvailable == CCnvCharacterSetConverter::ENotAvailable)
+ {
+ iAvailable = iConverter->PrepareToConvertToOrFromL(iDefaultCharsetId, iFSession);
+ }
+ }
+ }
+
+/**
+Set iCharsetId to aCharset if body text of the message was downloaded as 8 bit.
+This can be used to override the charset with which a message was downloaded, when
+the body text is opened for reading.
+@param aCharset The new charset with which it needs to be converted.
+@return void.
+*/
+EXPORT_C void CMsvPlainBodyText::SetCharacterSetL(const TUint aCharset)
+ {
+ if(iStore.IsPresentL(KMsvPlainBodyText8))
+ {
+ iCharsetId = aCharset;
+ }
+ }
+
+/**
+Returns the charset for the plain text part
+@param None.
+@return TUint
+*/
+EXPORT_C TUint CMsvPlainBodyText::CharacterSet()
+ {
+ return iCharsetId ;
+ }
+
+/**
+Returns the default charset for the plain text part
+@param None.
+@return TUint
+*/
+EXPORT_C TUint CMsvPlainBodyText::DefaultCharacterSet()
+ {
+ return iDefaultCharsetId;
+ }
+
+/**
+Commit the file and the store after it is written and and also closes the file.
+@param
+@return void
+*/
+EXPORT_C void CMsvPlainBodyText::CommitL()
+ {
+ iFile.Close();
+ RMsvWriteStream out;
+ if(iIs8Bit)
+ {
+ out.AssignLC(iStore, KMsvPlainBodyText8);
+ out.WriteUint32L(iCharsetId);
+ out.WriteUint32L(iDefaultCharsetId);
+ }
+ else
+ {
+ out.AssignLC(iStore, KMsvPlainBodyText16);
+ }
+ iIsCommitted = ETrue;
+ out.WriteUint32L(iIsCommitted);
+
+ TBuf<KFileNameFixedWidth> fileName;
+ fileName.NumFixedWidth(iMessageId, EHex, KFileNameFixedWidth);
+ out << (TDes&)fileName;
+
+ out.CommitL();
+ out.Close();
+ iStore.CommitL();
+ iMsvStoreManager.ReplacePlainTextFileL(iMessageId);
+ CleanupStack::PopAndDestroy(&out);
+ }
+
+/**
+Revert/Delete the file if it is not committed.
+@param None.
+@return void.
+*/
+void CMsvPlainBodyText::RevertL()
+ {
+ iFile.Close();
+ if(!iIsCommitted)
+ {
+ iMsvStoreManager.DeletePlainTextFileL(iMessageId);
+ }
+ }
+
+/**
+Cancel the file read operation and set the filepointer to the current position of the file
+so that next call to NextChunkL() will attempt to read the same chunk that was cancelled
+@param None.
+@return void.
+*/
+void CMsvPlainBodyText::DoCancel()
+ {
+ if(iMsvFileStatus == EMsvFileReading)
+ {
+ iFile.ReadCancel();
+ iFile.Seek(ESeekStart, iCurrentFilePos);
+ }
+ CMsgActive::DoCancel();
+ }