diff -r 9f5ae1728557 -r db3f5fa34ec7 messagingfw/msgsrvnstore/server/src/CMsvBodyText.cpp --- /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 // CCnvCharacterSetConverter +#include // CRichText +#include +#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. +*/ + { + }