os/ossrv/genericservices/httputils/EscapeUtils/EscapeUtils.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2001-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 //
    15 
    16 #include <escapeutils.h>
    17 
    18 #include <utf.h>
    19 
    20 #include "EscapeUtilsInternal.h"
    21 
    22 // Constants
    23 //
    24 _LIT(KHexDigit, "0123456789ABCDEF");
    25 _LIT(KExcludedData, "{}|\\^`<>#%\"");
    26 _LIT8(KQueryData8, ";/?:@&=+$,[]");
    27 _LIT8(KPathData8, "/;=?[]");
    28 _LIT8(KAuthData8, ";:@?/[]");
    29 _LIT8(KUrlEncoded8, ";/?:@&=+$[]!\'()~*");
    30 _LIT16(KQueryData16, ";/?:@&=+$,[]");
    31 _LIT16(KPathData16, "/;=?[]");
    32 _LIT16(KAuthData16, ";:@?/[]");
    33 _LIT16(KUrlEncoded16, ";/?:@&=+$[]!\'()~");
    34 const TInt KEscapeUtilsConversionBufferSize	= 50;
    35 const TInt KEscapeIndicator					= '%';
    36 const TInt KEscapeTripleLength				= 3;
    37 const TInt KEscDelimiterPos					= 0;
    38 const TInt KMostSignificantNibblePos		= 1;
    39 const TInt KLeastSignificantNibblePos		= 2;
    40 
    41 // Panic category
    42 //
    43 #ifdef _DEBUG
    44 	_LIT(KEscapeUtilsPanicCategory, "ESC-UTILS"); 
    45 #endif
    46 
    47 //
    48 //
    49 // Implementation of EscapeUtils
    50 //
    51 //
    52 
    53 /**
    54 	Escape encodes excluded and reserved characters in the data as escape triples. 
    55 	The reserved characters are defined by the escape mode. These characters and the 
    56 	set of excluded characters specified by RFC2396 form the entire set of excluded data.
    57 						
    58 	@since			6.0
    59 	@leave		    KUriUtilsErr16BitChar. A 16-Bit character was found in the data to be escape encoded.
    60 	@param			aData	A descriptor with the data to encode.
    61 	@param			aEscapeMode	An enum specifying the escape mode.
    62 	@return			A pointer to a descriptor buffer which contains the escape encoded data.
    63 */
    64 EXPORT_C HBufC8* EscapeUtils::EscapeEncodeL(const TDesC8& aData, TEscapeMode aEscapeMode)
    65 	{
    66 	// Need descriptor pointer to reserved characters...
    67 	TPtrC8 reserved;
    68 
    69 	switch (aEscapeMode)
    70 		{
    71 	case EEscapeNormal:
    72 		{
    73 		// This is normal operation - no reserved chars
    74 		reserved.Set(KNullDesC8);
    75 		} break;
    76 	case EEscapeQuery:
    77 		{
    78 		// Reserved data in a URI query - ; / ? : @ & = + $ ,
    79 		reserved.Set(KQueryData8());
    80 		} break;
    81 	case EEscapePath:
    82 		{
    83 		// Reserved data in a URI path segment - / ; = ?
    84 		reserved.Set(KPathData8());
    85 		} break;
    86 	case EEscapeAuth:
    87 		{
    88 		// Reserved data in a URI authority - ; : @ ? /
    89 		reserved.Set(KAuthData8());
    90 		} break;
    91 	case EEscapeUrlEncoded:
    92 		{
    93 		// Reserved data in  Url Encoded data - ; / ? : @ & = + $ [ ] ! ' ( ) ~ *
    94 		reserved.Set(KUrlEncoded8());
    95 		} break;
    96 	default:
    97 		// Not supported return NULL
    98 		__ASSERT_DEBUG(EFalse, User::Panic(KEscapeUtilsPanicCategory, KUriUtilsErrBadEscapeMode));
    99 		return NULL;
   100 		}
   101 	return EscapeEncodeL(aData, reserved);
   102 	}
   103 
   104 /**
   105 	Escape encodes excluded and reserved characters in the data as escape triples. The 
   106 	reserved characters are defined by the escape mode. These characters and the set of 
   107 	excluded characters specified by RFC2396 form the entire set of excluded data.
   108 						
   109 	@since			6.0
   110 	@leave			KUriUtilsErr16BitChar. A 16-Bit character was found in the data to be escape encoded.
   111 	@param			aData	A descriptor with the data to encode.
   112 	@param			aEscapeMode	An enum specifying the escape mode.
   113 	@return			A pointer to a descriptor buffer which contains the escape encoded data.
   114 */
   115 EXPORT_C HBufC16* EscapeUtils::EscapeEncodeL(const TDesC16& aData, TEscapeMode aEscapeMode)
   116 	{
   117 	// Need to descriptor pointer to reserved chars
   118 	TPtrC16 reserved;
   119 
   120 	switch (aEscapeMode)
   121 		{
   122 	case EEscapeNormal:
   123 		{
   124 		// This is normal operation - no reserved chars
   125 		reserved.Set(KNullDesC16);
   126 		} break;
   127 	case EEscapeQuery:
   128 		{
   129 		// Reserved data in a URI query - ; / ? : @ & = + $ [],
   130 		reserved.Set(KQueryData16());
   131 		} break;
   132 	case EEscapePath:
   133 		{
   134 		// Reserved data in a URI path segment - / ; = ? []
   135 		reserved.Set(KPathData16());
   136 		} break;
   137 	case EEscapeAuth:
   138 		{
   139 		// Reserved data in a URI authority - ; : @ ? / []
   140 		reserved.Set(KAuthData16());
   141 		} break;
   142 	case EEscapeUrlEncoded:
   143 		{
   144 		// Reserved data in  Url Encoded data - ; / ? : @ & = + $ [ ] ! ' ( ) ~
   145 		reserved.Set(KUrlEncoded16());
   146 		} break;
   147 	default:
   148 		// Not supported return NULL
   149 		__ASSERT_DEBUG(EFalse, User::Panic(KEscapeUtilsPanicCategory, KUriUtilsErrBadEscapeMode));
   150 		return NULL;
   151 		}
   152 	return EscapeEncodeL(aData, reserved);
   153 	}
   154 
   155 /**
   156 	Escape encodes excluded and reserved characters in the data as escape triples. These 
   157 	characters and the set of excluded characters specified by RFC2396 form the entire set
   158 	of excluded data.
   159 						
   160 	@since			6.0
   161 	@leave			KUriUtilsErr16BitChar. A 16-Bit character was found in the data to be escape encoded.
   162 	@param			aData			A descriptor with the data to encode.
   163 	@param			aReservedChars	A descriptor with the reserved characters.
   164 	@return			A pointer to a descriptor buffer which contains the escape encoded data.
   165 */
   166 EXPORT_C HBufC8* EscapeUtils::EscapeEncodeL(const TDesC8& aData, const TDesC8& aReservedChars)
   167 	{
   168 	// Allocate space to build escaped url - consider worse case; all characters are excluded => length x 3
   169 	HBufC8* buf = HBufC8::NewLC(aData.Length()*3);
   170 	TPtr8 escaped = buf->Des();
   171 
   172 	User::LeaveIfError(EscapeEncodeData(aData, aReservedChars, escaped));
   173 	HBufC8* encoded = escaped.AllocL();
   174 
   175 	CleanupStack::PopAndDestroy(buf);
   176 	return encoded;
   177 	}
   178 
   179 /**
   180 	Escape encodes excluded and reserved characters in the data as escape triples. These characters 
   181 	and the set of excluded characters specified by RFC2396 form the entire set of excluded data.
   182 						
   183 	@since			6.0
   184 	@leave			KUriUtilsErr16BitChar. A 16-Bit character was found in the data to be escape encoded.
   185 	@param			aData			A descriptor with the data to encode.
   186 	@param			aReservedChars	A descriptor with the reserved characters.
   187 	@return			A pointer to a descriptor buffer which contains the escape encoded data.
   188 */
   189 EXPORT_C HBufC16* EscapeUtils::EscapeEncodeL(const TDesC16& aData, const TDesC16& aReservedChars)
   190 	{
   191 	// Allocate space to build escaped url - consider worse case; all characters are excluded => length x 3
   192 	HBufC16* buf = HBufC16::NewLC(aData.Length()*3);
   193 	TPtr16 escaped = buf->Des();
   194 
   195 	User::LeaveIfError(EscapeEncodeData(aData, aReservedChars, escaped));
   196 	HBufC16* encoded = escaped.AllocL();
   197 
   198 	CleanupStack::PopAndDestroy(buf);
   199 	return encoded;
   200 	}
   201 
   202 /**
   203 	Escape decodes the data.
   204 	
   205 	@since			6.0
   206 	@param			aData	A descriptor with the data to decode.
   207 	@return			A pointer to a descriptor buffer which contains the escape decoded data.
   208 */
   209 EXPORT_C HBufC8* EscapeUtils::EscapeDecodeL(const TDesC8& aData)
   210 	{
   211 	// Allocate space to build unescaped data
   212 	HBufC8* buf = HBufC8::NewLC(aData.Length());
   213 	TPtr8 unescaped = buf->Des();
   214 
   215 	User::LeaveIfError(EscapeDecodeData(aData, unescaped));
   216 	HBufC8* decoded = unescaped.AllocL();
   217 
   218 	CleanupStack::PopAndDestroy(buf);
   219 	return decoded;
   220 	}
   221 
   222 /**
   223 	Escape decodes the data.
   224 	
   225 	@since			6.0
   226 	@param			aData	A descriptor with the data to decode.
   227 	@return			A pointer to a descriptor buffer which contains the escape decoded data.
   228 */
   229 EXPORT_C HBufC16* EscapeUtils::EscapeDecodeL(const TDesC16& aData)
   230 	{
   231 	// Allocate space to build unescaped data
   232 	HBufC16* buf = HBufC16::NewLC(aData.Length());
   233 	TPtr16 unescaped = buf->Des();
   234 
   235 	User::LeaveIfError(EscapeDecodeData(aData, unescaped));
   236 	HBufC16* decoded = unescaped.AllocL();
   237 
   238 	CleanupStack::PopAndDestroy(buf);
   239 	return decoded;
   240 	}
   241 
   242 /**
   243 	@internalComponent
   244 	
   245 	escape encode only those characters that cannot be in a URI. assume all %hh are %encoded already.
   246 	
   247 	@param		aData	The descriptor buffer to be escape encoded.
   248 	@return		A pointer to a descriptor buffer which contains the escape encoded data.
   249 */
   250 HBufC8* EscapeUtils::ReEscapeEncodeL(const TDesC8& aData)
   251 	{
   252 	// Descriptor to hex digits and excluded chars
   253 	const TDesC& KHexChars = KHexDigit;
   254 
   255 	const TInt length = aData.Length();
   256 	
   257 	// find out how many characters need escape encoding
   258 	TInt count = 0;
   259 	for( TInt i=0; i<length; ++i )
   260 		{
   261 		TChar current( aData[i] );
   262 		if( EscapeUtils::IsExcludedChar(current) && current != KFragmentDelimiter && 
   263 			!(current == KEscapeIndicator &&  i+2<length && TChar(aData[i+1]).IsHexDigit() && TChar(aData[i+2]).IsHexDigit() ) )
   264 			{
   265 			count++;
   266 			}
   267 		}
   268 	if( count == 0)	// no encoding needed, just allocate and return the whole string
   269 		{
   270 		return aData.AllocL();
   271 		}
   272 	// pre-allocate space for the descriptor
   273 	HBufC8* buf = HBufC8::NewLC( aData.Length() + count*2 ); // two extra chars for each escaped
   274 	TPtr8 escaped = buf->Des();
   275 
   276 	for( TInt i=0; i<length; ++i )
   277 		{
   278 		// Check if current character must be escaped
   279 		TChar current ( aData[i] );
   280 		// Check if current character is excluded, but not  if it appears to be escape encoded
   281 		TBool excluded = EscapeUtils::IsExcludedChar(current) && current != KFragmentDelimiter &&
   282 			!(current == KEscapeIndicator &&  i+2<length && TChar(aData[i+1]).IsHexDigit() && TChar(aData[i+2]).IsHexDigit() );
   283 
   284 		if( excluded )
   285 			{
   286 			// Excluded char - escape encode
   287 			escaped.Append(KEscapeIndicator);
   288 			const TInt mostSignificantNibble = (current & 0xf0) >> 4;	// Get msNibble by masking against 11110000 and dividing by 16 (>>4)
   289 			escaped.Append(KHexChars[mostSignificantNibble]);
   290 			const TInt leastSignificantNibble = (current & 0x0f);		// Get lsNibble by masking against 00001111
   291 			escaped.Append(KHexChars[leastSignificantNibble]);
   292 			}
   293 		else
   294 			{
   295 			// Not an excluded char - just append			  
   296 			escaped.Append(current);
   297 			}
   298 		}
   299 	CleanupStack::Pop(buf);
   300 	return buf;
   301 	}
   302 
   303 
   304 /**
   305 
   306 	Converts UNICODE data into UTF8 format.
   307 	
   308 	@since			6.0
   309 	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
   310 	@param			aString			A descriptor with the data to convert.
   311 	@return			A pointer to an 8-bit descriptor buffer which contains UTF8 data.
   312 */
   313 EXPORT_C HBufC8* EscapeUtils::ConvertFromUnicodeToUtf8L(const TDesC& aString)
   314 	{
   315 	// Return an empty buffer straight-away
   316 	if( aString.Compare(KNullDesC) == 0 )
   317 		return KNullDesC8().AllocL();
   318 
   319 	// Convert from Unicode to UTF8
   320 	TPtrC unicode = aString;
   321 	TBuf8<KEscapeUtilsConversionBufferSize> buf;
   322 	HBufC8* utf8Buffer = HBufC8::NewLC(unicode.Length());
   323 	TPtr8 utf8 = utf8Buffer->Des();
   324 
   325 	// Loop until all of the filename is converted
   326 	FOREVER
   327 		{
   328 		const TInt returnValue = CnvUtfConverter::ConvertFromUnicodeToUtf8(buf, unicode);
   329 		if( returnValue == CnvUtfConverter::EErrorIllFormedInput || returnValue < 0)
   330 			User::Leave(KUriUtilsCannotConvert);
   331 
   332 		// Is escapedFullPath too small?
   333 		if( utf8.Length() + buf.Length() > utf8.MaxLength() )
   334 			{
   335 			utf8Buffer = utf8Buffer->ReAllocL(utf8.Length() + buf.Length());
   336 			CleanupStack::Pop();	// utf8Buffer (old version)
   337 			CleanupStack::PushL(utf8Buffer);	// new version
   338 			utf8.Set(utf8Buffer->Des());
   339 			}
   340 		// Copy converted characters
   341 		utf8.Append(buf);
   342 
   343 		if( returnValue == KErrNone )
   344 			break; // All of aUnicodeText has been converted and handled
   345 
   346 		// Set input descriptor to remaining characters
   347 		unicode.Set(unicode.Right(returnValue));
   348 		}
   349 	CleanupStack::Pop(utf8Buffer);
   350 	return utf8Buffer;		// Ownership transfered to caller
   351 	}
   352 
   353 /**
   354 	Converts UTF8 format into UNICODE data.
   355 	
   356 	@since			6.0
   357 	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
   358 	@param			aString			A descriptor with the data to convert.
   359 	@return			A pointer to a 16-bit descriptor buffer which contains UNICODE data.
   360 */
   361 EXPORT_C HBufC* EscapeUtils::ConvertToUnicodeFromUtf8L(const TDesC8& aString)
   362 	{
   363 	// Return an empty buffer straight-away
   364 	if( aString.Compare(KNullDesC8) == 0 )
   365 		return KNullDesC().AllocL();
   366 
   367 	// Convert from Unicode to UTF8
   368 	TPtrC8 utf8 = aString;
   369 	TBuf<KEscapeUtilsConversionBufferSize> buf;
   370 	HBufC* unicodeBuffer = HBufC::NewLC(utf8.Length());
   371 	TPtr unicode = unicodeBuffer->Des();
   372 
   373 	// Loop until all of the filename is converted
   374 	FOREVER
   375 		{
   376 		const TInt returnValue = CnvUtfConverter::ConvertToUnicodeFromUtf8(buf, utf8);
   377 		if( returnValue == CnvUtfConverter::EErrorIllFormedInput || returnValue < 0)
   378 			User::Leave(KUriUtilsCannotConvert);
   379 
   380 		// Is escapedFullPath too small?
   381 		if( unicode.Length() + buf.Length() > unicode.MaxLength() )
   382 			{
   383 			unicodeBuffer = unicodeBuffer->ReAllocL(unicode.Length() + buf.Length());
   384 			CleanupStack::Pop();	// unicodeBuffer (old version)
   385 			CleanupStack::PushL(unicodeBuffer);	// new version
   386 			unicode.Set(unicodeBuffer->Des());
   387 			}
   388 		// Copy converted characters
   389 		unicode.Append(buf);
   390 
   391 		if( returnValue==0 )
   392 			break; // All of utf8 has been converted and handled
   393 
   394 		// Set input descriptor to remaining characters
   395 		utf8.Set(utf8.Right(returnValue));
   396 		}
   397 	CleanupStack::Pop(unicodeBuffer);
   398 	return unicodeBuffer;	// Ownership transfered to caller
   399 	}
   400 
   401 /**
   402 	Checks to see if the input argument is excluded.
   403 	
   404 	@since			6.0
   405 	@param			aChar	The character to be checked.
   406 	@return			A boolean value of ETrue if the character is an excluded one, or
   407 					EFalse if it is not.
   408  */
   409 EXPORT_C TBool EscapeUtils::IsExcludedChar(TChar aChar)
   410 	{
   411 	const TDesC& KExcludedChars = KExcludedData;
   412 	TBool excluded = KExcludedChars.Locate(aChar) != KErrNotFound || aChar <= 0x1F || aChar == ' ' || aChar > 0x7E;
   413 	return excluded;
   414 	}
   415 
   416 /**
   417 	Checks for an escape triple at the start of the input descriptor. If there is a triple 
   418 	its value is calculated and returned through the output argument aHexValue. If there is 
   419 	no escape triple then this argument is left unchanged.
   420 						
   421 	@since			6.0
   422 	@param			aData		The descriptor to be checked for an escape triple.
   423 	@param			aHexValue	The output argument with the value of the escape triple 
   424 	if it exists.
   425 	@return			A boolean value of ETrue if there is an escape triple at the start of 
   426 	the input descriptor, EFalse otherwise.
   427 */
   428 EXPORT_C TBool EscapeUtils::IsEscapeTriple(const TDesC8& aData, TInt& aHexValue)
   429 	{
   430 	return CheckAndConvertEscapeTriple(aData, aHexValue);
   431 	}
   432 
   433 /**
   434 	Checks for an escape triple at the start of the input descriptor. If there is a triple 
   435 	its value is calculated and returned through the output argument aHexValue. If there is 
   436 	no escape triple then this argument is left unchanged.
   437 						
   438 	@since			6.0
   439 	@param			aData		The descriptor to be checked for an escape triple.
   440 	@param			aHexValue	The output argument with the value of the escape triple 
   441 	if it exists.
   442 	@return			A boolean value of ETrue if there is an escape triple at the start of 
   443 	the input descriptor, EFalse otherwise.
   444 */
   445 EXPORT_C TBool EscapeUtils::IsEscapeTriple(const TDesC16& aData, TInt& aHexValue)
   446 	{
   447 	return CheckAndConvertEscapeTriple(aData, aHexValue);
   448 	}
   449 
   450 /**
   451 	returns the escape encoded descriptor output. This checks the every character of aData 
   452 	against aCharsToEscape and if it exist then it escape encodes that character.
   453 
   454 	@param			aData	The descriptor to be checked against escaping set of characters.
   455 	@param			aCharsToEscape	The set of escape characters.
   456 	@return			A pointer to the escape encoded descriptor.
   457 */
   458 EXPORT_C HBufC8* EscapeUtils::SpecificEscapeEncodeL ( const TDesC8& aData, const TDesC8& aCharsToEscape )
   459 	{
   460 	// Descriptor to hex digits and excluded chars
   461 	const TDesC& KHexChars = KHexDigit;
   462 
   463 	const TInt length = aData.Length();
   464 	
   465 	// find out how many characters need escape encoding
   466 	TInt count = 0;
   467 	for( TInt i=0; i<length; ++i )
   468 		{
   469 		TChar current( aData[i] );
   470 		if ( current <= 0x1F || aCharsToEscape.Locate ( current ) != KErrNotFound || current > 0x7E )
   471 			{
   472 			count++;
   473 			}
   474 		}
   475 	if( count == 0)	// no encoding needed, just allocate and return the whole string
   476 		{
   477 		return aData.AllocL();
   478 		}
   479 
   480 	// pre-allocate space for the descriptor
   481 	HBufC8* buf = HBufC8::NewLC( length + count*2 ); // two extra chars for each escaped
   482 	TPtr8 escaped = buf->Des();
   483 
   484 	for( TInt i=0; i<length; ++i )
   485 		{
   486 		// Check if current character must be escaped
   487 		TChar current ( aData[i] );
   488 		// Check if current character is excluded ( control characters and the character specified for escaping )
   489 		TBool excluded = current <= 0x1F || ( aCharsToEscape.Locate ( current ) != KErrNotFound ) || current > 0x7E;
   490 
   491 		if( excluded )
   492 			{
   493 			// Excluded char - escape encode
   494 			escaped.Append(KEscapeIndicator);
   495 			const TInt mostSignificantNibble = (current & 0xf0) >> 4;	// Get msNibble by masking against 11110000 and dividing by 16 (>>4)
   496 			escaped.Append(KHexChars[mostSignificantNibble]);
   497 			const TInt leastSignificantNibble = (current & 0x0f);		// Get lsNibble by masking against 00001111
   498 			escaped.Append(KHexChars[leastSignificantNibble]);
   499 			}
   500 		else
   501 			{
   502 			// Not an excluded char - just append			  
   503 			escaped.Append(current);
   504 			}
   505 		}
   506 	CleanupStack::Pop(buf);
   507 	return buf;		
   508 	}
   509 
   510 /** 
   511     The Dummy API is used to redirect to SpecificEscapeEncodeL() API in order to preserve BC and is made private                                                                                                       
   512 	to ensure no-one else starts using it.
   513 */
   514 EXPORT_C HBufC8* EscapeUtils::DummyForwardingFunctionForCompatibility( const TDesC8& aData, const TDesC8& aCharsToEscape )
   515 	{
   516 	return EscapeUtils::SpecificEscapeEncodeL ( aData, aCharsToEscape );
   517 	}
   518 
   519 
   520 //
   521 //
   522 // Implementation of LOCAL functions
   523 //
   524 //
   525 /**
   526 	Escape encodes the data, converting the reserved characters and excluded characters defined by 
   527 	RFC2396 as escape triples.
   528 						
   529 	@since			6.0
   530 	@warning		This function will panic if the output descriptor aEncodedData is
   531 	not big enough to append all the data.
   532 	@param			aData			A descriptor with the data to encode.
   533 	@param			aReservedChars  Reserved characters set.
   534 	@param			aEncodedData	The output descriptor pointer where the escaped encoded 
   535 	data is placed.
   536 	@return			An error code of KUriUtilsErr16BitChar if the data contains a 16-bit 
   537 	character. KErrNone if the data was successfully encoded.
   538  */				
   539 template<class TDesCType, class TPtrType>
   540 TInt EscapeEncodeData(const TDesCType& aData, const TDesCType& aReservedChars, TPtrType& aEncodedData)
   541 	{
   542 	// Descriptor to hex digits and excluded chars
   543 	const TDesC& KHexChars = KHexDigit;
   544 
   545 	const TInt length = aData.Length();
   546 	for( TInt i=0; i<length; ++i )
   547 		{
   548 		// Check if current character must be escaped, will return error if not 8-bit character
   549 		TChar current = aData[i];
   550 		if( current > 0xff )
   551 			{
   552 			__ASSERT_DEBUG(EFalse, User::Panic(KEscapeUtilsPanicCategory, KUriUtilsErr16BitChar));
   553 			return (KUriUtilsErr16BitChar);
   554 			}
   555 		// Check if current character is excluded, a control character or a space
   556 		TBool excluded = EscapeUtils::IsExcludedChar(current) || aReservedChars.Locate(current) != KErrNotFound;
   557 	  if ( excluded )
   558 		   {
   559        		// Excluded char - escape encode
   560 			aEncodedData.Append(KEscapeIndicator);
   561 			const TInt mostSignificantNibble = (current & 0xf0) >> 4;	// Get msNibble by masking against 11110000 and dividing by 16 (>>4)
   562 			aEncodedData.Append(KHexChars[mostSignificantNibble]);
   563 			const TInt leastSignificantNibble = (current & 0x0f);		// Get lsNibble by masking against 00001111
   564 			aEncodedData.Append(KHexChars[leastSignificantNibble]);
   565 			}
   566 		else
   567 			{
   568 			// Not an excluded char or It's already Escape encode - just append			  
   569 			aEncodedData.Append(current);
   570 		    }
   571 		}
   572 	return KErrNone;
   573 	}
   574 
   575 /**
   576 	Escape decodes the data, converting escape triples back to their single character value.
   577 	
   578 	@since			6.0
   579 	@warning		This function will panic if the output descriptor aDecodedData is not big 
   580 	enough to append all the data.
   581 	@param			aData			A descriptor with the data to decode.
   582 	@param			aDecodedData	The output descriptor pointer where the escaped decoded data 
   583 	is placed.
   584 	@return			An error code of KUriUtilsErr16BitChar if the data contains a 16-bit character. 
   585 	KErrNone if the data was successfully encoded.
   586  */
   587 template<class TDesCType, class TPtrType>
   588 TInt EscapeDecodeData(const TDesCType& aData, TPtrType& aDecodedData)
   589 	{
   590 	// Go through the descriptor
   591 	const TInt length = aData.Length();
   592 	for( TInt i=0; i<length; ++i )
   593 		{
   594 		// See if at start of an escape triple
   595 		TChar current = aData[i];
   596 		if( current == KEscapeIndicator )
   597 			{
   598 			TInt hex;
   599 			if( !CheckAndConvertEscapeTriple(aData.Mid(i), hex) )
   600 				{
   601 				// Either of the nibbles were not a valid hex character
   602 				return KUriUtilsErrBadEscapeTriple;
   603 				}
   604 			// Append hex value
   605 			aDecodedData.Append(hex);
   606 
   607 			// Move index to get next character - add 2 to index
   608 			i += 2;
   609 			}
   610 		else
   611 			{
   612 			// Not an escaped triple - just append
   613 			aDecodedData.Append(current);
   614 			}
   615 		}
   616 	return KErrNone;
   617 	}
   618 
   619 /**
   620 	Checks for an escape triple at the start of the input descriptor. If there is a triple its 
   621 	value is calculated and returned through the output argument aHexValue. If there is no escape 
   622 	then triple this argument is left unchanged.
   623 						
   624 	@since			6.0
   625 	@param			aData		The descriptor to be checked for an escape triple.
   626 	@param			aHexValue	The output argument with the value of the escape triple 
   627 	if it exists.
   628 	@return			A boolean value of ETrue if there is an escape triple at the start 
   629 	of the input descriptor, EFalse otherwise.
   630  */
   631 template<class TDesCType>
   632 TBool CheckAndConvertEscapeTriple(const TDesCType& aData, TInt& aHexValue)
   633 	{
   634 	// See if the descriptor is actually long enough
   635 	if( aData.Length() < KEscapeTripleLength )
   636 		{
   637 		return EFalse;
   638 		}
   639 	// Check that the three characters form an escape triple - first char is '%'
   640 	if( aData[KEscDelimiterPos] != KEscapeIndicator )
   641 		{
   642 		return EFalse;
   643 		}
   644 	// Descriptor to hex digits and excluded chars
   645 	const TDesC& KHexChars = KHexDigit;
   646 
   647 	// Check that next two characters are valid
   648 	TChar mostSignificantNibble = aData[KMostSignificantNibblePos];
   649 	TChar leastSignificantNibble = aData[KLeastSignificantNibblePos];
   650 
   651 	TInt mostSignificantNibbleValue = KHexChars.LocateF(mostSignificantNibble);
   652 	TInt leastSignificantNibbleValue = KHexChars.LocateF(leastSignificantNibble);
   653 
   654 	if( mostSignificantNibbleValue == KErrNotFound || leastSignificantNibbleValue == KErrNotFound )
   655 		{
   656 		// Either of the nibbles were not a valid hex character
   657 		return EFalse;
   658 		}
   659 	// Convert characters into hex value and return
   660 	aHexValue = 0x10*mostSignificantNibbleValue + 0x01*leastSignificantNibbleValue;
   661 	return ETrue;
   662 	}