sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // INCLUDE FILES
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <bafl/qpcodec.h>
sl@0: 
sl@0: /**
sl@0: Decode the string
sl@0: @param aSrcString source string
sl@0: @param rDestString Destination string
sl@0: @return  KErrNone  if decode is complete
sl@0: @return  KErrCorrupt if string is not QuotedPrintable compliant
sl@0: */
sl@0: EXPORT_C TInt QuotedPrintableCodec::Decode( const TDesC8& aSrcString, TDes8& rDestString )
sl@0: 	{
sl@0: 	
sl@0: #ifdef _DEBUG
sl@0: 	TInt KPanicInvalidSMTPLine = 6;
sl@0: 	_LIT(KDllName,"MultipartParser");
sl@0: #endif
sl@0: 	
sl@0: 	const TUint8 KImcvSP			= ' ';
sl@0: 	const TUint8 KImcvCR			= '\r';
sl@0: 	const TUint8 KImcvLF			= '\n';	
sl@0: 	const TUint8 KImcvTab			= '\t';
sl@0: 	const TUint8 KImcvEquals		= '=';
sl@0: 	TUint8 qpCharacter = KImcvEquals;
sl@0: 	
sl@0: 	TInt error = KErrNone;
sl@0: 	
sl@0: 	__ASSERT_DEBUG(aSrcString.Length(), User::Panic( KDllName ,KPanicInvalidSMTPLine));
sl@0: 
sl@0: 	rDestString = KNullDesC8;
sl@0: 
sl@0: 	TPtrC8 source( aSrcString.Ptr(), aSrcString.Length() );
sl@0: 	const TUint8* pSource = source.Ptr();
sl@0: 	const TUint8* pEnd = pSource+aSrcString.Length();
sl@0: 	
sl@0: 	// find out if this is a blank line, if so then we'll add a paragraph delimiter instead
sl@0: 	// assume it's blank and then look for non-blank characters
sl@0: 	// avoid the CRLF at the end of the line (we know it's there thanks to the assertion above)
sl@0: 
sl@0: 	TBool blankLine = ETrue; 
sl@0: 	while (pSource < pEnd-2) 
sl@0: 		{
sl@0: 		if (*pSource!=KImcvSP && *pSource!=KImcvTab)
sl@0: 			{
sl@0: 			blankLine = EFalse;
sl@0: 			break;
sl@0: 			}
sl@0: 		pSource++;
sl@0: 		}
sl@0: 
sl@0: 	if ( blankLine )
sl@0: 		{
sl@0: 		rDestString.Copy( aSrcString );
sl@0: 		return KErrNone;
sl@0: 		}
sl@0: 
sl@0: 	TInt outputLength=0;
sl@0: 	TUint8 loBits;
sl@0: 	TUint8 hiBits;
sl@0: 	TUint8 asciiValue;
sl@0: 	pSource = source.Ptr();	// reset to start of source data
sl@0: 	const TUint8 zero = '0';
sl@0: 	const TUint8 alphaAdjust = 55;  // 'A' is ascii 65 so we need to subtract 55 from 
sl@0: 									// alphabetical hex digits to get their numeric value
sl@0: 	while( pSource < pEnd )
sl@0: 		{
sl@0: 		if (*pSource != qpCharacter )
sl@0: 			{
sl@0: 			//  Quoted character or Attachment bound, just bung it on & move to the next one
sl@0: 			// *ptr++ = *pSource;
sl@0: 			outputLength++;
sl@0: 			rDestString.Append( *pSource );
sl@0: 			}
sl@0: 		else	// check for encoded character
sl@0: 			{
sl@0: 			// start looking at the next two characters, if they are there.
sl@0: 
sl@0: 			if ( pSource+2 < pEnd )
sl@0: 				{
sl@0: 				pSource++;
sl@0: 
sl@0: 				// check for '=' at EOL => this is a soft break, so remove it
sl@0: 				if (*pSource != KImcvCR) 
sl@0: 					{
sl@0: 					if(*pSource != KImcvLF) 
sl@0: 						{
sl@0: 					 	 // now decode hex value into ASCII code : hi-order bits come first
sl@0: 						 hiBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
sl@0: 						 pSource++;
sl@0: 						 loBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
sl@0: 						 asciiValue = (TUint8)( (hiBits<<4) + loBits);
sl@0: 						 // bung the character thus formed onto the decoded string
sl@0: 						 rDestString.Append( asciiValue );
sl@0: 						 // *ptr++ = asciiValue;
sl@0: 						 outputLength++;
sl@0: 						}
sl@0: 					}
sl@0: 				else
sl@0: 					{
sl@0: 					pSource++;
sl@0: 					if(*pSource != KImcvLF)
sl@0: 						{
sl@0: 						error=KErrCorrupt;
sl@0: 						pSource-=2;
sl@0: 						rDestString.Append( *pSource );
sl@0: 						pSource++;
sl@0: 						rDestString.Append( *pSource );
sl@0: 						pSource++;
sl@0: 						outputLength+=2;
sl@0: 						}
sl@0: 					}
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				// copy the rest of the data & use up the input string in the process.
sl@0: 
sl@0: 				while (pSource < pEnd)
sl@0: 					{
sl@0: 					error=KErrCorrupt; // not QP compliant
sl@0: 					//*ptr++ = *pSource++;
sl@0: 					outputLength++;
sl@0: 					rDestString.Append( *pSource );
sl@0: 					pSource++;
sl@0: 					}
sl@0: 				}
sl@0: 			} // check for '=' char
sl@0: 		
sl@0: 		pSource++;  // next source charactery
sl@0: 	} // while
sl@0: 
sl@0: 	rDestString.SetLength(outputLength);
sl@0: 
sl@0: 	return error;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Check for digit
sl@0: @param aChar charcter to be check
sl@0: @return  ETrue if passed charcter is digit
sl@0: @return  EFalse if passed charcter is not digit
sl@0: */	
sl@0: TBool QuotedPrintableCodec::IsDigit( TChar aChar )
sl@0: {
sl@0: 	return ( (aChar >= '0') && (aChar <= '9') );
sl@0: }