--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/CMsvBodyText.cpp Wed Nov 03 22:41:46 2010 +0530
@@ -0,0 +1,431 @@
+// Copyright (c) 2003-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:
+// CMsvBodyText.cpp
+//
+
+#include "MSVSTORE.H" // CMsvStore
+#include "cmsvbodytext.h"
+#include <charconv.h> // CCnvCharacterSetConverter
+#include <txtrich.h> // CRichText
+#include <s32mem.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "msvconsts.h"
+#endif
+
+/**
+The unique stream identifier of the character set data stored in the message store.
+*/
+const TUid KMsvCharData = {0x101FD0E1};
+
+
+/**
+The version of KMsvEntryCharStream. Used to maintain data compatibility with older versions.
+*/
+const TUint8 KMsvCharDataVersion = 1;
+
+
+/**
+The version of KMsvEntry8BitASCIIStream. Used to maintain data compatibility with older versions.
+*/
+const TUint8 KMsv8BitEncodedBodyDataVersion = 1;
+
+
+
+
+EXPORT_C CMsvBodyText* CMsvBodyText::NewL()
+/**
+Allocates and constructs an empty body text object.
+*/
+ {
+ return new (ELeave) CMsvBodyText();
+ }
+
+
+EXPORT_C CMsvBodyText* CMsvBodyText::NewLC()
+/**
+Allocates and constructs an empty body text object. The object is put on the cleanup stack.
+*/
+ {
+ CMsvBodyText* self = new (ELeave) CMsvBodyText();
+ CleanupStack::PushL(self);
+ return self;
+ }
+
+
+EXPORT_C CMsvBodyText::~CMsvBodyText()
+/**
+Deallocates and destroys the body text object.
+*/
+ {
+ }
+
+
+EXPORT_C void CMsvBodyText::SetCharacterSet(const TUint aCharacterSetIdentifier)
+/**
+Sets the character set unique id to be used when decoding the 8 bit data stream.
+*/
+ {
+ iCharSet = aCharacterSetIdentifier;
+ }
+
+
+EXPORT_C TUint CMsvBodyText::CharacterSet() const
+/**
+Retrieves the character set unique id that will be used when decoding the 8 bit
+data stream.
+*/
+ {
+ return iCharSet;
+ }
+
+
+EXPORT_C void CMsvBodyText::SetDefaultCharacterSet(const TUint aCharacterSetIdentifier)
+/**
+Sets the default character set to use when decoding the 8 bit data if
+the character set unique id has not been specified.
+*/
+ {
+ iDefaultCharSet = aCharacterSetIdentifier;
+ }
+
+
+EXPORT_C TUint CMsvBodyText::DefaultCharacterSet() const
+/**
+Retrieves the default character set unique id that will be used when decoding the 8 bit
+data stream if the character set unique id has not been specified.
+*/
+ {
+ return iDefaultCharSet;
+ }
+
+
+EXPORT_C void CMsvBodyText::RestoreL(CMsvStore& aStore)
+/**
+Retrieves the character set unique ids and 8 bit data stream from the message store.
+
+@param aStore
+A store in read-only or read-write (edit) mode.
+
+@leave KErrNotFound
+The store does not contain 8 bit encoded body text data.
+*/
+ {
+ RMsvReadStream in;
+ in.OpenLC(aStore, KMsvCharData);
+ in.ReadUint8L(); // Ignore the version number. Future versions will have to check this value for data compatibility.
+ iCharSet = in.ReadUint32L();
+ iDefaultCharSet = in.ReadUint32L();
+ CleanupStack::PopAndDestroy(&in);
+ }
+
+
+EXPORT_C void CMsvBodyText::StoreL(CMsvStore& aStore)
+/**
+Just adds the character set identifiers to the store cache.
+
+@pre
+The store must be in read-write (edit) mode.
+
+@param aStore
+The store must be open in read-write (edit) mode.
+
+@leave KErrAccessedDenied
+The message store is not in read-write (edit) mode.
+*/
+ {
+ RMsvWriteStream out;
+ out.AssignLC(aStore, KMsvCharData);
+ out.WriteUint8L(KMsvCharDataVersion);
+ out.WriteUint32L(iCharSet);
+ out.WriteUint32L(iDefaultCharSet);
+ out.CommitL();
+ CleanupStack::PopAndDestroy(&out);
+ }
+
+
+EXPORT_C void CMsvBodyText::StoreL(CMsvStore& aStore, const CBufBase& aData)
+/**
+Adds the character identifiers and 8 bit encoded body text data to the store cache.
+
+@pre
+The store must be in read-write (edit) mode.
+
+@param aStore
+The store must be open in read-write (edit) mode.
+
+@param aData
+8 bit encoded body text data to be added to the store.
+
+@leave KErrAccessedDenied
+The message store is not in read-write (edit) mode.
+*/
+ {
+ // Add the character set information.
+ StoreL(aStore);
+
+ // Add the 8 bit data.
+ RMsvWriteStream out;
+ out.AssignLC(aStore, KMsv8BitEncodedBodyData);
+ out.WriteUint8L(KMsv8BitEncodedBodyDataVersion);
+
+ RBufReadStream reader(aData);
+ out.WriteL(reader,aData.Size());
+
+ out.CommitL();
+ CleanupStack::PopAndDestroy(&out);
+ }
+
+
+EXPORT_C void CMsvBodyText::GetBodyTextL(RFs& aFs, CMsvStore& aStore, CRichText& aBodyText)
+/**
+Decodes the encoded 8 bit body text data into the correct character set and adds the decoded output
+to the richtext object owned by the client. If the character set is not specified, then
+the default character set is used. If the character set is specified but not installed on the
+system then the default character set is used instead.
+
+@pre
+The store must contain encoded 8 bit body text data.
+
+@param aFs
+A connected file system handle. It is used to search for installed character set decoders.
+
+@param aStore
+The store can be opened in read-only or read-write (edit) mode.
+
+@param aBodyText
+The rich text object that will be appended with the decoded text.
+
+@leave KErrNotSupported
+The character set used to decode the 8 bit data cannot be found on the system.
+
+@leave KErrNotFound
+The store does not contain encoded 8 bit body text data.
+*/
+ {
+ // Create and initialise decoder. Leave if the character set cannot be located.
+ CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewL();
+ CleanupStack::PushL(converter);
+ CCnvCharacterSetConverter::TAvailability available = CCnvCharacterSetConverter::ENotAvailable;
+ if (iCharSet != 0)
+ available = converter->PrepareToConvertToOrFromL(iCharSet, aFs);
+
+ if (available == CCnvCharacterSetConverter::ENotAvailable)
+ available = converter->PrepareToConvertToOrFromL(iDefaultCharSet, aFs);
+
+ if (available != CCnvCharacterSetConverter::EAvailable)
+ User::Leave(KErrNotSupported);
+
+ // Open the 8 bit data stream and calculate the number of bytes of data to be read.
+ RMsvReadStream in;
+ in.OpenLC(aStore, KMsv8BitEncodedBodyData);
+ in.ReadUint8L(); // Ignore the version number since this is the 1st version.
+ MStreamBuf* sourceStream = in.Source();
+ TInt bytesRemaining = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.
+
+ // Create temporary buffers to hold the 8 bit data chunk and decoded chunk of unicode characters.
+ // 2 kB unicode output buffer + 1 kB 8 bit input data.
+ HBufC8* inBuf = HBufC8::NewLC(KMsvDecodeChunkLength);
+ HBufC16* outBuf = HBufC16::NewLC(KMsvDecodeChunkLength);
+ TPtr8 inPtr = inBuf->Des();
+ TPtr16 outPtr = outBuf->Des();
+
+ TInt state = CCnvCharacterSetConverter::KStateDefault; // Used to preserve state across multiple calls to ConvertToUnicode.
+ TBool newLine = EFalse;
+ TBool newPara = EFalse;
+
+ // Decode chunk by chunk to limit memory consumption.
+ while(bytesRemaining > 0)
+ {
+ // Set the buffer length to the smaller of the number of bytes remaining,
+ // or the chunk length.
+ inPtr.SetLength(bytesRemaining < KMsvDecodeChunkLength ? bytesRemaining : KMsvDecodeChunkLength);
+
+ // Read data from stream up to and including the 1st LF encountered.
+ TRAPD(err, in.ReadL(inPtr, TChar(0x0A)));
+ if (err != KErrEof)
+ User::LeaveIfError(err);
+ TInt len = inPtr.Length();
+ __ASSERT_DEBUG(len > 0, User::Invariant());
+ bytesRemaining -= len;
+
+ // If the data read is terminated with an LF or CRLF, remove it and mark it for
+ // appending a rich text line end or paragraph delimiter.
+ TInt bytesTruncated = 0;
+ if (inPtr[len - 1] != 0x0A)
+ {
+ // The data read does not contain any new line or paragraph delimters.
+ newLine = EFalse;
+ newPara = EFalse;
+ }
+ else
+ {
+ // Data read is terminated with LF. Truncate length of data to ignore LF or CRLF bytes.
+ if (len > 1 && inPtr[len - 2] == 0x0D)
+ {
+ bytesTruncated = 2;
+ len -= bytesTruncated;
+ inPtr.SetLength(len); // Remove CRLF.
+ }
+ else
+ {
+ bytesTruncated = 1;
+ len -= bytesTruncated;
+ inPtr.SetLength(len); // Remove LF.
+ }
+
+ // Work out if it should be a new line or new paragraph.
+ if (len == 0)
+ {
+ if (newLine)
+ {
+ // There are more than two new line delimiters in a row with no data
+ // between them - new paragraph.
+ newLine = EFalse;
+ newPara = ETrue;
+ }
+ else
+ {
+ newLine = ETrue;
+ newPara = EFalse;
+ }
+ }
+ else
+ {
+ // It's a new line.
+ newLine = ETrue;
+ newPara = EFalse;
+ }
+ }
+
+ // Convert the 8 bit data to unicode.
+ TInt bytesUnconverted = converter->ConvertToUnicode(outPtr, inPtr, state);
+ if (bytesUnconverted > 0)
+ {
+ // Some bytes could not be converted because the output buffer was too small.
+ // Seek back to the position of the 1st unconverted byte and recalculate the bytes remaining.
+ TInt bytesSeekBack = bytesUnconverted + bytesTruncated;
+ sourceStream->SeekL(MStreamBuf::ERead, EStreamMark, -bytesSeekBack);
+ bytesRemaining += bytesSeekBack;
+ newLine = EFalse;
+ newPara = EFalse;
+ }
+
+ // There is no AppendL method for CRichText. Insert decoded text at end of document instead.
+ aBodyText.InsertL(aBodyText.DocumentLength(), outPtr);
+
+ // Insert a new line or paragraph delimiter if necessary.
+ if (newLine)
+ aBodyText.InsertL(aBodyText.DocumentLength(), CEditableText::ELineBreak);
+ if (newPara)
+ aBodyText.InsertL(aBodyText.DocumentLength(), CEditableText::EParagraphDelimiter);
+ }
+
+ CleanupStack::PopAndDestroy(4, converter); // outBuf, inBuf, in, converter
+ }
+
+EXPORT_C void CMsvBodyText::GetBodyTextL(CMsvStore& aStore, TDes8& aBufer)
+ {
+ // Open the 8 bit data stream and calculate the number of bytes of data to be read.
+ if(aStore.IsPresentL(KMsv8BitEncodedBodyData))
+ {
+ RMsvReadStream in;
+ in.OpenLC(aStore, KMsv8BitEncodedBodyData);
+ in.ReadUint8L(); // Ignore the version number since this is the 1st version.
+ MStreamBuf* sourceStream = in.Source();
+ TInt bytesRemaining = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.
+ in.ReadL(aBufer, bytesRemaining);
+ CleanupStack::PopAndDestroy(); // in
+ }
+ else if(aStore.IsPresentL(KMsvPlainBodyText8))
+ {
+ RFileReadStream inputStream;
+ aStore.Restore8BitBodyTextL(inputStream);
+ inputStream.PushL();
+ MStreamBuf* sourceStream = inputStream.Source();
+ inputStream.ReadL(aBufer, sourceStream->SizeL());
+ CleanupStack::PopAndDestroy(); // inputStream
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ }
+ }
+
+EXPORT_C TInt CMsvBodyText::GetBodyLengthL(CMsvStore& aStore)
+ {
+ if(aStore.IsPresentL(KMsv8BitEncodedBodyData))
+ {
+ RMsvReadStream in;
+ in.OpenLC(aStore, KMsv8BitEncodedBodyData);
+ in.ReadUint8L(); // Ignore the version number since this is the 1st version.
+ MStreamBuf* sourceStream = in.Source();
+ TInt length = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.
+ CleanupStack::PopAndDestroy(); // in
+ return length;
+ }
+ else if(aStore.IsPresentL(KMsvPlainBodyText8))
+ {
+ RFileReadStream inputStream;
+ aStore.Restore8BitBodyTextL(inputStream);
+ inputStream.PushL();
+ MStreamBuf* sourceStream = inputStream.Source();
+ TInt bodyLength = sourceStream->SizeL();
+ CleanupStack::PopAndDestroy(); // inputStream
+ return bodyLength;
+ }
+ else
+ {
+ return KErrNotSupported;
+ }
+ }
+
+EXPORT_C void CMsvBodyText::RemoveL(CMsvStore& aStore)
+/**
+Removes the 8 bit data body text data from the store cache.
+
+@pre
+The store must be in read-write (edit) mode.
+
+@leave KErrAccessedDenied
+The message store is not in read-write (edit) mode.
+*/
+ {
+ if (aStore.IsPresentL(KMsvCharData))
+ aStore.RemoveL(KMsvCharData);
+ if (aStore.IsPresentL(KMsv8BitEncodedBodyData))
+ aStore.RemoveL(KMsv8BitEncodedBodyData);
+ }
+
+
+EXPORT_C TBool CMsvBodyText::IsPresentL(const CMsvStore& aStore) const
+/**
+Tests to see if the store contains 8 bit body text data.
+
+@param aStore
+The store can be open in read-only or read-write (edit) mode.
+
+@return
+ETrue if the store contains 8 bit body text data.
+*/
+ {
+ return aStore.IsPresentL(KMsvCharData);
+ }
+
+
+CMsvBodyText::CMsvBodyText()
+/**
+Private constructor.
+*/
+ {
+ }