messagingfw/msgsrvnstore/server/src/CMsvBodyText.cpp
changeset 62 db3f5fa34ec7
parent 0 8e480a14352b
child 44 7c176670643f
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // CMsvBodyText.cpp
       
    15 //
       
    16 
       
    17 #include "MSVSTORE.H"     // CMsvStore
       
    18 #include "cmsvbodytext.h"
       
    19 #include <charconv.h>     // CCnvCharacterSetConverter
       
    20 #include <txtrich.h>      // CRichText
       
    21 #include <s32mem.h>
       
    22 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    23 #include "msvconsts.h"
       
    24 #endif
       
    25 
       
    26 /**
       
    27 The unique stream identifier of the character set data stored in the message store.
       
    28 */
       
    29 const TUid KMsvCharData = {0x101FD0E1};
       
    30 
       
    31 
       
    32 /**
       
    33 The version of KMsvEntryCharStream.  Used to maintain data compatibility with older versions.
       
    34 */
       
    35 const TUint8 KMsvCharDataVersion = 1;
       
    36 
       
    37 
       
    38 /**
       
    39 The version of KMsvEntry8BitASCIIStream.  Used to maintain data compatibility with older versions.
       
    40 */
       
    41 const TUint8 KMsv8BitEncodedBodyDataVersion = 1;
       
    42 
       
    43 
       
    44 
       
    45 
       
    46 EXPORT_C CMsvBodyText* CMsvBodyText::NewL()
       
    47 /**
       
    48 Allocates and constructs an empty body text object.
       
    49 */
       
    50 	{
       
    51 	return new (ELeave) CMsvBodyText();
       
    52 	}
       
    53 
       
    54 
       
    55 EXPORT_C CMsvBodyText* CMsvBodyText::NewLC()
       
    56 /**
       
    57 Allocates and constructs an empty body text object.  The object is put on the cleanup stack.
       
    58 */
       
    59 	{
       
    60 	CMsvBodyText* self = new (ELeave) CMsvBodyText();
       
    61 	CleanupStack::PushL(self);
       
    62 	return self;
       
    63 	}
       
    64 
       
    65 
       
    66 EXPORT_C CMsvBodyText::~CMsvBodyText()
       
    67 /**
       
    68 Deallocates and destroys the body text object.
       
    69 */
       
    70 	{
       
    71 	}
       
    72 
       
    73 
       
    74 EXPORT_C void CMsvBodyText::SetCharacterSet(const TUint aCharacterSetIdentifier)
       
    75 /**
       
    76 Sets the character set unique id to be used when decoding the 8 bit data stream.
       
    77 */
       
    78 	{
       
    79 	iCharSet = aCharacterSetIdentifier;
       
    80 	}
       
    81 
       
    82 
       
    83 EXPORT_C TUint CMsvBodyText::CharacterSet() const
       
    84 /**
       
    85 Retrieves the character set unique id that will be used when decoding the 8 bit
       
    86 data stream. 
       
    87 */
       
    88 	{
       
    89 	return iCharSet;
       
    90 	}
       
    91 
       
    92 
       
    93 EXPORT_C void CMsvBodyText::SetDefaultCharacterSet(const TUint aCharacterSetIdentifier)
       
    94 /**
       
    95 Sets the default character set to use when decoding the 8 bit data if
       
    96 the character set unique id has not been specified.
       
    97 */
       
    98 	{
       
    99 	iDefaultCharSet = aCharacterSetIdentifier;
       
   100 	}
       
   101 
       
   102 
       
   103 EXPORT_C TUint CMsvBodyText::DefaultCharacterSet() const
       
   104 /**
       
   105 Retrieves the default character set unique id that will be used when decoding the 8 bit
       
   106 data stream if the character set unique id has not been specified. 
       
   107 */
       
   108 	{
       
   109 	return iDefaultCharSet;
       
   110 	}
       
   111 
       
   112 
       
   113 EXPORT_C void CMsvBodyText::RestoreL(CMsvStore& aStore)
       
   114 /**
       
   115 Retrieves the character set unique ids and 8 bit data stream from the message store.
       
   116 
       
   117 @param aStore
       
   118 A store in read-only or read-write (edit) mode.
       
   119 
       
   120 @leave KErrNotFound
       
   121 The store does not contain 8 bit encoded body text data. 
       
   122 */
       
   123 	{
       
   124 	RMsvReadStream in;
       
   125 	in.OpenLC(aStore, KMsvCharData);
       
   126 	in.ReadUint8L();  // Ignore the version number.  Future versions will have to check this value for data compatibility.
       
   127 	iCharSet = in.ReadUint32L();
       
   128 	iDefaultCharSet = in.ReadUint32L();
       
   129 	CleanupStack::PopAndDestroy(&in);
       
   130 	}
       
   131 
       
   132 
       
   133 EXPORT_C void CMsvBodyText::StoreL(CMsvStore& aStore)
       
   134 /**
       
   135 Just adds the character set identifiers to the store cache.
       
   136 
       
   137 @pre
       
   138 The store must be in read-write (edit) mode.
       
   139 
       
   140 @param aStore
       
   141 The store must be open in read-write (edit) mode.
       
   142 
       
   143 @leave KErrAccessedDenied
       
   144 The message store is not in read-write (edit) mode.  
       
   145 */
       
   146 	{
       
   147 	RMsvWriteStream out;
       
   148 	out.AssignLC(aStore, KMsvCharData);
       
   149 	out.WriteUint8L(KMsvCharDataVersion);
       
   150 	out.WriteUint32L(iCharSet);
       
   151 	out.WriteUint32L(iDefaultCharSet);
       
   152 	out.CommitL();
       
   153 	CleanupStack::PopAndDestroy(&out);
       
   154 	}
       
   155 
       
   156 
       
   157 EXPORT_C void CMsvBodyText::StoreL(CMsvStore& aStore, const CBufBase& aData)
       
   158 /**
       
   159 Adds the character identifiers and 8 bit encoded body text data to the store cache.
       
   160 
       
   161 @pre
       
   162 The store must be in read-write (edit) mode.
       
   163 
       
   164 @param aStore
       
   165 The store must be open in read-write (edit) mode.
       
   166 
       
   167 @param aData
       
   168 8 bit encoded body text data to be added to the store.
       
   169 
       
   170 @leave KErrAccessedDenied
       
   171 The message store is not in read-write (edit) mode.  
       
   172 */
       
   173 	{
       
   174 	// Add the character set information.
       
   175 	StoreL(aStore);
       
   176 	
       
   177 	// Add the 8 bit data.	
       
   178 	RMsvWriteStream out;
       
   179 	out.AssignLC(aStore, KMsv8BitEncodedBodyData);
       
   180 	out.WriteUint8L(KMsv8BitEncodedBodyDataVersion);
       
   181 
       
   182 	RBufReadStream reader(aData);
       
   183 	out.WriteL(reader,aData.Size());
       
   184 
       
   185 	out.CommitL();
       
   186 	CleanupStack::PopAndDestroy(&out);
       
   187 	}
       
   188 
       
   189 
       
   190 EXPORT_C void CMsvBodyText::GetBodyTextL(RFs& aFs, CMsvStore& aStore, CRichText& aBodyText)
       
   191 /**
       
   192 Decodes the encoded 8 bit body text data into the correct character set and adds the decoded output
       
   193 to the richtext object owned by the client. If the character set is not specified, then
       
   194 the default character set is used.  If the character set is specified but not installed on the
       
   195 system then the default character set is used instead.
       
   196 
       
   197 @pre
       
   198 The store must contain encoded 8 bit body text data.
       
   199  
       
   200 @param aFs
       
   201 A connected file system handle.  It is used to search for installed character set decoders.
       
   202 
       
   203 @param aStore
       
   204 The store can be opened in read-only or read-write (edit) mode.
       
   205 
       
   206 @param aBodyText
       
   207 The rich text object that will be appended with the decoded text.
       
   208 
       
   209 @leave KErrNotSupported
       
   210 The character set used to decode the 8 bit data cannot be found on the system.
       
   211 
       
   212 @leave KErrNotFound
       
   213 The store does not contain encoded 8 bit body text data.
       
   214 */
       
   215 	{
       
   216 	// Create and initialise decoder.  Leave if the character set cannot be located.
       
   217 	CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewL();
       
   218 	CleanupStack::PushL(converter);
       
   219 	CCnvCharacterSetConverter::TAvailability available = CCnvCharacterSetConverter::ENotAvailable;
       
   220 	if (iCharSet != 0)
       
   221 		available = converter->PrepareToConvertToOrFromL(iCharSet, aFs);
       
   222 	
       
   223 	if (available == CCnvCharacterSetConverter::ENotAvailable)
       
   224 		available = converter->PrepareToConvertToOrFromL(iDefaultCharSet, aFs);
       
   225 	
       
   226 	if (available != CCnvCharacterSetConverter::EAvailable)
       
   227 		User::Leave(KErrNotSupported);
       
   228 	
       
   229 	// Open the 8 bit data stream and calculate the number of bytes of data to be read.
       
   230 	RMsvReadStream in;
       
   231 	in.OpenLC(aStore, KMsv8BitEncodedBodyData);
       
   232 	in.ReadUint8L();  // Ignore the version number since this is the 1st version.
       
   233 	MStreamBuf* sourceStream = in.Source();
       
   234 	TInt bytesRemaining = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.
       
   235 	
       
   236 	// Create temporary buffers to hold the 8 bit data chunk and decoded chunk of unicode characters.
       
   237 	// 2 kB unicode output buffer + 1 kB 8 bit input data.
       
   238 	HBufC8* inBuf = HBufC8::NewLC(KMsvDecodeChunkLength);
       
   239 	HBufC16* outBuf = HBufC16::NewLC(KMsvDecodeChunkLength);
       
   240 	TPtr8 inPtr = inBuf->Des();
       
   241 	TPtr16 outPtr = outBuf->Des();
       
   242 	
       
   243 	TInt state = CCnvCharacterSetConverter::KStateDefault;  // Used to preserve state across multiple calls to ConvertToUnicode.
       
   244 	TBool newLine = EFalse;
       
   245 	TBool newPara = EFalse;
       
   246 	
       
   247 	// Decode chunk by chunk to limit memory consumption.
       
   248 	while(bytesRemaining > 0)
       
   249 		{
       
   250 		// Set the buffer length to the smaller of the number of bytes remaining,
       
   251 		// or the chunk length.
       
   252 		inPtr.SetLength(bytesRemaining < KMsvDecodeChunkLength ? bytesRemaining : KMsvDecodeChunkLength);
       
   253 		
       
   254 		// Read data from stream up to and including the 1st LF encountered.
       
   255 		TRAPD(err, in.ReadL(inPtr, TChar(0x0A)));
       
   256 		if (err != KErrEof)
       
   257 			User::LeaveIfError(err);
       
   258 		TInt len = inPtr.Length();
       
   259 		__ASSERT_DEBUG(len > 0, User::Invariant());
       
   260 		bytesRemaining -= len;
       
   261 		
       
   262 		// If the data read is terminated with an LF or CRLF, remove it and mark it for
       
   263 		// appending a rich text line end or paragraph delimiter. 
       
   264 		TInt bytesTruncated = 0;
       
   265 		if (inPtr[len - 1] != 0x0A)
       
   266 			{
       
   267 			// The data read does not contain any new line or paragraph delimters.
       
   268 			newLine = EFalse;
       
   269 			newPara = EFalse;
       
   270 			}
       
   271 		else
       
   272 			{
       
   273 			// Data read is terminated with LF.  Truncate length of data to ignore LF or CRLF bytes.
       
   274 			if (len > 1 && inPtr[len - 2] == 0x0D)
       
   275 				{
       
   276 				bytesTruncated = 2;
       
   277 				len -= bytesTruncated;
       
   278 				inPtr.SetLength(len);  // Remove CRLF.
       
   279 				}
       
   280 			else
       
   281 				{
       
   282 				bytesTruncated = 1;
       
   283 				len -= bytesTruncated;
       
   284 				inPtr.SetLength(len);  // Remove LF.
       
   285 				}
       
   286 			
       
   287 			// Work out if it should be a new line or new paragraph.
       
   288 			if (len == 0)
       
   289 				{
       
   290 				if (newLine)
       
   291 					{
       
   292 					// There are more than two new line delimiters in a row with no data
       
   293 					// between them - new paragraph.
       
   294 					newLine = EFalse;
       
   295 					newPara = ETrue;
       
   296 					}
       
   297 				else
       
   298 					{
       
   299 					newLine = ETrue;
       
   300 					newPara = EFalse;
       
   301 					}
       
   302 				}
       
   303 			else
       
   304 				{
       
   305 				// It's a new line.
       
   306 				newLine = ETrue;
       
   307 				newPara = EFalse;
       
   308 				}
       
   309 			}
       
   310 		
       
   311 		// Convert the 8 bit data to unicode.
       
   312 		TInt bytesUnconverted = converter->ConvertToUnicode(outPtr, inPtr, state);
       
   313 		if (bytesUnconverted > 0)
       
   314 			{
       
   315 			// Some bytes could not be converted because the output buffer was too small.
       
   316 			// Seek back to the position of the 1st unconverted byte and recalculate the bytes remaining.  
       
   317 			TInt bytesSeekBack = bytesUnconverted + bytesTruncated;
       
   318 			sourceStream->SeekL(MStreamBuf::ERead, EStreamMark, -bytesSeekBack);
       
   319 			bytesRemaining += bytesSeekBack;
       
   320 			newLine = EFalse;
       
   321 			newPara = EFalse;
       
   322 			}
       
   323 		
       
   324 		// There is no AppendL method for CRichText.  Insert decoded text at end of document instead.
       
   325 		aBodyText.InsertL(aBodyText.DocumentLength(), outPtr);
       
   326 
       
   327 		// Insert a new line or paragraph delimiter if necessary.
       
   328 		if (newLine)
       
   329 			aBodyText.InsertL(aBodyText.DocumentLength(), CEditableText::ELineBreak);
       
   330 		if (newPara)
       
   331 			aBodyText.InsertL(aBodyText.DocumentLength(), CEditableText::EParagraphDelimiter);
       
   332 		}
       
   333 	
       
   334 	CleanupStack::PopAndDestroy(4, converter); // outBuf, inBuf, in, converter
       
   335 	}
       
   336 	
       
   337 EXPORT_C void CMsvBodyText::GetBodyTextL(CMsvStore& aStore, TDes8& aBufer)
       
   338 	{
       
   339 	// Open the 8 bit data stream and calculate the number of bytes of data to be read.	
       
   340 	if(aStore.IsPresentL(KMsv8BitEncodedBodyData))
       
   341 		{
       
   342 		RMsvReadStream in;
       
   343 		in.OpenLC(aStore, KMsv8BitEncodedBodyData);
       
   344 		in.ReadUint8L();  // Ignore the version number since this is the 1st version.
       
   345 		MStreamBuf* sourceStream = in.Source();
       
   346 		TInt bytesRemaining = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.	
       
   347 		in.ReadL(aBufer, bytesRemaining);
       
   348 		CleanupStack::PopAndDestroy(); // in		
       
   349 		}
       
   350 	else if(aStore.IsPresentL(KMsvPlainBodyText8))
       
   351 		{
       
   352 		RFileReadStream inputStream;
       
   353 		aStore.Restore8BitBodyTextL(inputStream);
       
   354 		inputStream.PushL();
       
   355 		MStreamBuf* sourceStream = inputStream.Source();
       
   356 		inputStream.ReadL(aBufer, sourceStream->SizeL());
       
   357 		CleanupStack::PopAndDestroy();	// inputStream
       
   358 		}	
       
   359 	else
       
   360 		{
       
   361 		User::Leave(KErrNotSupported);
       
   362 		}
       
   363 	}	
       
   364 	
       
   365 EXPORT_C TInt CMsvBodyText::GetBodyLengthL(CMsvStore& aStore)
       
   366 	{
       
   367 	if(aStore.IsPresentL(KMsv8BitEncodedBodyData))
       
   368 		{
       
   369 		RMsvReadStream in;
       
   370 		in.OpenLC(aStore, KMsv8BitEncodedBodyData);
       
   371 		in.ReadUint8L();  // Ignore the version number since this is the 1st version.
       
   372 		MStreamBuf* sourceStream = in.Source();
       
   373 		TInt length = sourceStream->SizeL() - 1; // Less one to account for the TUint8 version byte.
       
   374 		CleanupStack::PopAndDestroy(); // in
       
   375 		return length;		
       
   376 		}
       
   377 	else if(aStore.IsPresentL(KMsvPlainBodyText8))
       
   378 		{
       
   379 		RFileReadStream inputStream;
       
   380 		aStore.Restore8BitBodyTextL(inputStream);
       
   381 		inputStream.PushL();
       
   382 		MStreamBuf* sourceStream = inputStream.Source();
       
   383 		TInt bodyLength = sourceStream->SizeL();
       
   384 		CleanupStack::PopAndDestroy();	// inputStream
       
   385 		return bodyLength;
       
   386 		}
       
   387 	else
       
   388 		{
       
   389 		return KErrNotSupported;
       
   390 		}		
       
   391 	}
       
   392 	
       
   393 EXPORT_C void CMsvBodyText::RemoveL(CMsvStore& aStore)
       
   394 /**
       
   395 Removes the 8 bit data body text data from the store cache.
       
   396 
       
   397 @pre
       
   398 The store must be in read-write (edit) mode.
       
   399 
       
   400 @leave KErrAccessedDenied
       
   401 The message store is not in read-write (edit) mode.  
       
   402 */
       
   403 	{
       
   404 	if (aStore.IsPresentL(KMsvCharData))
       
   405 		aStore.RemoveL(KMsvCharData);
       
   406 	if (aStore.IsPresentL(KMsv8BitEncodedBodyData))
       
   407 		aStore.RemoveL(KMsv8BitEncodedBodyData);
       
   408 	}
       
   409 
       
   410 
       
   411 EXPORT_C TBool CMsvBodyText::IsPresentL(const CMsvStore& aStore) const
       
   412 /**
       
   413 Tests to see if the store contains 8 bit body text data.
       
   414 
       
   415 @param aStore
       
   416 The store can be open in read-only or read-write (edit) mode.
       
   417 
       
   418 @return
       
   419 ETrue if the store contains 8 bit body text data.
       
   420 */
       
   421 	{
       
   422 	return aStore.IsPresentL(KMsvCharData);
       
   423 	}
       
   424 
       
   425 
       
   426 CMsvBodyText::CMsvBodyText()
       
   427 /**
       
   428 Private constructor.
       
   429 */
       
   430 	{
       
   431 	}