messagingfw/msgsrvnstore/server/src/CMsvBodyText.cpp
changeset 22 bde600d88860
parent 0 8e480a14352b
child 44 7c176670643f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/CMsvBodyText.cpp	Fri Jun 04 10:32:16 2010 +0100
@@ -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.
+*/
+	{
+	}