genericservices/httputils/inetprottextutils/inetprottextutils.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 "inetprottextutils.h"
       
    17 
       
    18 #include "inetprottextutilslocal.h"
       
    19 #include <uriutilscommon.h>
       
    20 
       
    21 // Panic category
       
    22 //
       
    23 #ifdef _DEBUG
       
    24 	_LIT(KTextUtilsPanicCategory, "IPTXTUTL"); 
       
    25 #endif
       
    26 
       
    27 const TUint KZeroChar		= '0';
       
    28 const TUint KAChar			= 'A';
       
    29 const TUint	KQuote			= '"';
       
    30 const TUint KMinusSign		= '-';
       
    31 const TInt KMaxTIntDecimalDigits = 11; // KMaxTInt  => "-2147483648" 
       
    32 const TInt KMaxTIntDividedByTen = KMaxTInt/10;
       
    33 
       
    34 #define KHorizTab 0x09
       
    35 #define KSpace 0x20
       
    36 #define KZero 0x30
       
    37 #define KNine 0x39
       
    38 #define KDecimal 0x2E
       
    39 
       
    40 
       
    41 const TInt KMaxNumberSize	= 32;	// includes '-' sign
       
    42 
       
    43 /**
       
    44 	Removes any contiguous whitespace at the extremes of the data, as specified
       
    45 	by aMode. Whitespace is defined by the functions TChar::IsSpace() - white
       
    46 	space includes spaces, tabs, and separators (e.g. new line).
       
    47 	
       
    48 	@param			aData	A descriptor pointer with the data.
       
    49 	@param			aMode	The specified removal mode.
       
    50 	@return			The number of consumed whitespace characters. If the data is
       
    51 	empty or the data is all whitespace the error code KUriUtilsErrEmptyData is
       
    52 	returned.
       
    53 */
       
    54 EXPORT_C TInt InetProtTextUtils::RemoveWhiteSpace(TPtrC8& aData, TRemoveMode aMode)
       
    55 	{
       
    56 	TInt consumed = DoRemoveWhiteSpace(aData, aMode);
       
    57 	if( consumed == KUriUtilsErrEmptyData )
       
    58 		{
       
    59 		// Either empty data or all whitespace
       
    60 		aData.Set(KNullDesC8());
       
    61 		}
       
    62 	return consumed;
       
    63 	}
       
    64 
       
    65 /**
       
    66 	Removes any contiguous whitespace at the extremes of the data, as specified
       
    67 	by aMode. Whitespace is defined by the functions TChar::IsSpace() - white
       
    68 	space includes spaces, tabs, and separators (e.g. new line).
       
    69 	
       
    70 	@param			aData	A descriptor pointer with the data.
       
    71 	@param			aMode	The specified removal mode.
       
    72 	@return			The number of consumed whitespace characters. If the data is
       
    73 	empty or the data is all whitespace the error code KUriUtilsErrEmptyData is
       
    74 	returned.
       
    75 */
       
    76 EXPORT_C TInt InetProtTextUtils::RemoveWhiteSpace(TPtrC16& aData, TRemoveMode aMode)
       
    77 	{
       
    78 	TInt consumed = DoRemoveWhiteSpace(aData, aMode);
       
    79 	if( consumed == KUriUtilsErrEmptyData )
       
    80 		{
       
    81 		// Either empty data or all whitespace
       
    82 		aData.Set(KNullDesC16());
       
    83 		}
       
    84 	return consumed;
       
    85 	}
       
    86 
       
    87 /**
       
    88 	Converts an integer value into its decimal character representation.
       
    89 	
       
    90 	@param			aInt		An integer value.	
       
    91 	@param			aBuffer		An output argument of a pointer to a data buffer
       
    92 	that will contain the character representation of the integer value.
       
    93 */
       
    94 EXPORT_C void InetProtTextUtils::ConvertIntToDescriptorL(TInt aInt, HBufC8*& aBuffer)
       
    95 	{
       
    96 	DoConvertIntToDescriptorL(aInt, aBuffer, EDecimal);
       
    97 	}
       
    98 
       
    99 /**
       
   100 	Converts an integer value into its decimal character representation.
       
   101 	
       
   102 	@param			aInt		An integer value.	
       
   103 	@param			aBuffer		An output argument of a pointer to a data buffer
       
   104 	that will contain the character representation of the integer value.
       
   105 */
       
   106 EXPORT_C void InetProtTextUtils::ConvertIntToDescriptorL(TInt aInt, HBufC16*& aBuffer)
       
   107 	{
       
   108 	DoConvertIntToDescriptorL(aInt, aBuffer, EDecimal);
       
   109 	}
       
   110 
       
   111 /**
       
   112 	Converts the character representation of an integer into its numeric value.
       
   113 	Preceeding whitespace is ignored and the integer is delimited by either the
       
   114 	end of the data, whitespace or any other character other than 0 to 9.
       
   115 	
       
   116 	@param			aData	A descriptor pointer with the data.
       
   117 	@param			aInt	An output argument in which the numeric value of the
       
   118 	data is placed.
       
   119 	@return			The number of consumed characters that contributed to the 
       
   120 					integer value, including any whitespace before the integer. 
       
   121 					If the data is empty the error code KUriUtilsErrEmptyData 
       
   122 					is returned. If there are no digits at the beginning of the
       
   123 					data the error code KUriUtilsErrNoIntergerInData is returned.
       
   124 */
       
   125 EXPORT_C TInt InetProtTextUtils::ConvertDescriptorToInt(const TDesC8& aData, TInt& aInt)
       
   126 	{
       
   127 	// Do conversion and return number of consumed characters
       
   128 	return DoConvertDescriptorToInt(TPtrC8(aData), aInt, EDecimal);
       
   129 	}
       
   130 
       
   131 /**
       
   132 	Converts the character representation of an integer into its numeric value.
       
   133 	Preceeding whitespace is ignored and the integer is delimited by either the
       
   134 	end of the data, whitespace or any other character other than 0 to 9.
       
   135 	
       
   136 	@param			aData	A descriptor pointer with the data.
       
   137 	@param			aInt	An output argument in which the numeric value of the
       
   138 	data is placed.
       
   139 	@return			The number of consumed characters that contributed to the 
       
   140 					integer value, including any whitespace before the integer.
       
   141 					If the data is empty the error code KUriUtilsErrEmptyData is
       
   142 					returned. If there are no digits at the beginning of the data
       
   143 					the error code KUriUtilsErrNoIntergerInData is returned.
       
   144 */
       
   145 EXPORT_C TInt InetProtTextUtils::ConvertDescriptorToInt(const TDesC16& aData, TInt& aInt)
       
   146 	{
       
   147 	// Do conversion and return number of consumed characters
       
   148 	return DoConvertDescriptorToInt(TPtrC16(aData), aInt, EDecimal);
       
   149 	}
       
   150 
       
   151 /**
       
   152 	@internalComponent
       
   153 	
       
   154 	Converts an integer to its hex representation.
       
   155 	
       
   156 	@param		aHex	The integer value to convert.
       
   157 	@param		aBuffer	An output argument that is set to the buffer containing 
       
   158 						the hex representation of aValue.
       
   159 	@panic		EInvariantFalse	The integer value was too big.
       
   160 */
       
   161 EXPORT_C void InetProtTextUtils::ConvertHexToDescriptorL(TInt aHex, HBufC8*& aBuffer)
       
   162 	{
       
   163 	DoConvertIntToDescriptorL(aHex, aBuffer, EHex);
       
   164 	}
       
   165 
       
   166 /**
       
   167 	@internalComponent
       
   168 	
       
   169 	Converts an integer to its hex representation.
       
   170 	
       
   171 	@param		aHex	The integer value to convert.
       
   172 	@param		aBuffer	An output argument that is set to the buffer containing 
       
   173 						the hex representation of aValue.
       
   174 	@panic		EInvariantFalse	The integer value was too big.
       
   175 */
       
   176 EXPORT_C void InetProtTextUtils::ConvertHexToDescriptorL(TInt aHex, HBufC16*& aBuffer)
       
   177 	{
       
   178 	DoConvertIntToDescriptorL(aHex, aBuffer, EHex);
       
   179 	}
       
   180 
       
   181 /**
       
   182 	@internalComponent
       
   183 	
       
   184 	Descriptor to hex convertor. Searches the descriptor buffer for a hex number
       
   185 	representation at the start of the buffer. The hex number is deemed to have 
       
   186 	ended when the first non-hex character is found. The numeric value of the 
       
   187 	hex number is returned along with the number characters consumed in obtaining
       
   188 	the number. The amount of leading whitespace is included in the number of 
       
   189 	characters consumed.
       
   190 	
       
   191 	@param		aData	The descriptor buffer to be parsed.
       
   192 	@param		aHex	An output argument set to the numeric value of the 
       
   193 						parsed hex number.
       
   194 	@return		The number of characters consumed in parsing the hex number. If 
       
   195 				the descriptor was empty then KUriUtilsErrEmptyData is returned.
       
   196 				If no hex number was parsed then KUriUtilsErrNoIntergerInData is
       
   197 				returned.
       
   198 */
       
   199 EXPORT_C TInt InetProtTextUtils::ConvertDescriptorToHex(const TDesC8& aData, TInt& aHex)
       
   200 	{
       
   201 	// Do conversion, returning the number of consumed characters
       
   202 	return DoConvertDescriptorToInt(TPtrC8(aData), aHex, EHex);
       
   203 	}
       
   204 
       
   205 /**
       
   206 	@internalComponent
       
   207 	
       
   208 	Descriptor to hex convertor. Searches the descriptor buffer for a hex number
       
   209 	representation at the start of the buffer. The hex number is deemed to have 
       
   210 	ended when the first non-hex character is found. The numeric value of the 
       
   211 	hex number is returned along with the number characters consumed in obtaining
       
   212 	the number. The amount of leading whitespace is included in the number of 
       
   213 	characters consumed.
       
   214 	
       
   215 	@param		aData	The descriptor buffer to be parsed.
       
   216 	@param		aHex	An output argument set to the numeric value of the 
       
   217 						parsed hex number.
       
   218 	@return		The number of characters consumed in parsing the hex number. If 
       
   219 				the descriptor was empty then KUriUtilsErrEmptyData is returned.
       
   220 				If no hex number was parsed then KUriUtilsErrNoIntergerInData is
       
   221 				returned.
       
   222 */
       
   223 EXPORT_C TInt InetProtTextUtils::ConvertDescriptorToHex(const TDesC16& aData, TInt& aHex)
       
   224 	{
       
   225 	// Do conversion, returning the number of consumed characters
       
   226 	return DoConvertDescriptorToInt(TPtrC16(aData), aHex, EHex);
       
   227 	}
       
   228 
       
   229 /** 
       
   230 	Extract a token from the head of the supplied buffer, which is assumed to be
       
   231 	a token-list. The tokens are separated by the specified character. Any white
       
   232 	space surrounding the token is stripped out.  The number of characters 
       
   233 	consumed from the buffer are returned. The buffer is updated to not include
       
   234 	the extracted token including the separator.
       
   235 	
       
   236 	@param			aBuffer		The buffer containing the token-list.
       
   237 	@param			aToken		An output argument containing the extracted token.
       
   238 	@param			aSeparator	The separator character.
       
   239 	@return			The number of characters consumed from the buffer.
       
   240 */
       
   241 EXPORT_C TInt InetProtTextUtils::ExtractNextTokenFromList(TPtrC8& aBuffer, TPtrC8& aToken, TChar aSeparator)
       
   242 	{
       
   243 	return DoExtractNextTokenFromList(aBuffer, aToken, aSeparator);
       
   244 	}
       
   245 
       
   246 /** 
       
   247 	Extract a token from the head of the supplied buffer, which is assumed to be
       
   248 	a token-list. The tokens are separated by the specified character. Any white
       
   249 	space surrounding the token is stripped out.  The number of characters 
       
   250 	consumed from the buffer are returned. The buffer is updated to not include
       
   251 	the extracted token including the separator.
       
   252 	
       
   253 	@param			aBuffer		The buffer containing the token-list.
       
   254 	@param			aToken		An output argument containing the extracted token.
       
   255 	@param			aSeparator	The separator character.
       
   256 	@return			The number of characters consumed from the buffer.
       
   257 */
       
   258 EXPORT_C TInt InetProtTextUtils::ExtractNextTokenFromList(TPtrC16& aBuffer, TPtrC16& aToken, TChar aSeparator)
       
   259 	{
       
   260 	return DoExtractNextTokenFromList(aBuffer, aToken, aSeparator);
       
   261 	}
       
   262 
       
   263 /** 
       
   264 	Extract a token from the head of the supplied buffer, which is assumed to be
       
   265 	a token-list. The tokens are separated by one of the specified characters. 
       
   266 	Any white space surrounding the token is stripped out.  The number of 
       
   267 	characters consumed from the buffer are returned. The buffer is updated to 
       
   268 	not include the extracted token including the separator.
       
   269 	
       
   270 	@param			aBuffer		The buffer containing the token-list.
       
   271 	@param			aToken		An output argument containing the extracted token.
       
   272 	@param			aSeparators	The list of separator characters.
       
   273 	@return			The number of characters consumed from the buffer.
       
   274 */
       
   275 EXPORT_C TInt InetProtTextUtils::ExtractNextTokenFromList(TPtrC8& aBuffer, TPtrC8& aToken, const TDesC8& aSeparators)
       
   276 	{
       
   277 	TPtrC8 separators = aSeparators;
       
   278 	return DoExtractNextTokenFromList(aBuffer, aToken, separators);
       
   279 	}
       
   280 
       
   281 /** 
       
   282 	Extract a token from the head of the supplied buffer, which is assumed to be
       
   283 	a token-list. The tokens are separated by one of the specified characters. 
       
   284 	Any white space surrounding the token is stripped out.  The number of 
       
   285 	characters consumed from the buffer are returned. The buffer is updated to 
       
   286 	not include the extracted token including the separator.
       
   287 	
       
   288 	@param			aBuffer		The buffer containing the token-list.
       
   289 	@param			aToken		An output argument containing the extracted token.
       
   290 	@param			aSeparators	The list of separator characters.
       
   291 	@return			The number of characters consumed from the buffer.
       
   292 */
       
   293 EXPORT_C TInt InetProtTextUtils::ExtractNextTokenFromList(TPtrC16& aBuffer, TPtrC16& aToken, const TDesC16& aSeparators)
       
   294 	{
       
   295 	TPtrC16 separators = aSeparators;
       
   296 	return DoExtractNextTokenFromList(aBuffer, aToken, separators);
       
   297 	}
       
   298 
       
   299 /**	
       
   300 	Extract a quoted string value from the head of the supplied buffer. Anything
       
   301 	outside the quotes is discarded and the quotes themselves are not included 
       
   302 	in the returned string.
       
   303 	
       
   304 	@param			aBuffer			The buffer containing the quoted.
       
   305 	@param			aQuotedString	An output argument containing the extracted
       
   306 									string.
       
   307 	@return			The number of characters consumed from the buffer.
       
   308 */
       
   309 EXPORT_C TInt InetProtTextUtils::ExtractQuotedStringL(TPtrC8& aBuffer, TPtrC8& aQuotedString)
       
   310 	{
       
   311 	return DoExtractQuotedStringL(aBuffer, aQuotedString);
       
   312 	}
       
   313 
       
   314 /**	
       
   315 	Extract a quoted string value from the head of the supplied buffer. Anything
       
   316 	outside the quotes is discarded and the quotes themselves are not included 
       
   317 	in the returned string.
       
   318 	
       
   319 	@param			aBuffer			The buffer containing the quoted.
       
   320 	@param			aQuotedString	An output argument containing the extracted
       
   321 									string.
       
   322 	@return			The number of characters consumed from the buffer.
       
   323 */
       
   324 EXPORT_C TInt InetProtTextUtils::ExtractQuotedStringL(TPtrC16& aBuffer, TPtrC16& aQuotedString)
       
   325 
       
   326 	{
       
   327 	return DoExtractQuotedStringL(aBuffer, aQuotedString);
       
   328 	}
       
   329 
       
   330 /**	
       
   331 	@internalTechnology
       
   332 	
       
   333 	Extract an integer value from the head of the supplied buffer.
       
   334 	
       
   335 	@param			aBuffer	The buffer containing the integer value.
       
   336 	@param			aIntVal	An output argument in which extracted integer value
       
   337 							is placed.
       
   338 	@param			aAllowNonWsTerminator	If set to true whitespace is considered as the 
       
   339 									terminator, if set to false a non-decimal charecter
       
   340 									is considered as terminator.
       
   341 	@return			The number of characters in aBuffer after the integer.
       
   342 	@leave			KUriUtilsErrMalformedInteger if the value in aBuffer is not an integer 
       
   343 					(ie, contains non-decimal characters, or is too big to fit in a TInt)
       
   344 */
       
   345 EXPORT_C TInt InetProtTextUtils::ExtractIntegerValueL(TPtrC8& aBuffer, TInt& aIntVal, TBool aAllowNonWsTerminator)
       
   346 	{
       
   347 	// Anticipate an empty token by default
       
   348 	TPtrC8 data(aBuffer);
       
   349 
       
   350 	// Trim out any whitespace to the left the integer and check there's something left!
       
   351 	InetProtTextUtils::RemoveWhiteSpace(data, InetProtTextUtils::ERemoveLeft);
       
   352 	const TInt len = data.Length();
       
   353 	TInt retVal = aBuffer.Length() -  len; // the amount of WS consumed
       
   354 	if (len == 0)
       
   355 		{
       
   356 		// No integer was found - the supplied buffer was all WS!
       
   357 		aIntVal = 0;
       
   358 		retVal = aBuffer.Length();
       
   359 		aBuffer.Set(data);
       
   360 		}
       
   361 	else
       
   362 		{
       
   363 		// Got some data to work with... find out how many digits are present. Assume that the integer
       
   364 		// required is a contiguous set of decimal digits followed by WS or the end of the buffer
       
   365 		TInt numDigits = 0;
       
   366 		TChar ch = KZero; // default most significant digit to zero without affecting the result
       
   367 		TBool done = EFalse;
       
   368 		while (!done)
       
   369 			{
       
   370 			// check for the end of the integer. This depends on what is allowed to terminate it.
       
   371 			if (aAllowNonWsTerminator)
       
   372 				{
       
   373 				done = (numDigits == data.Length());
       
   374 				if (!done)
       
   375 					{
       
   376 					ch = data[numDigits];
       
   377 					done = ((ch < KZero) || (ch > KNine));
       
   378 					}
       
   379 				}
       
   380 			else
       
   381 				{
       
   382 				done = (numDigits == data.Length());
       
   383 				if (!done)
       
   384 					{
       
   385 					ch = data[numDigits];
       
   386 					done = ((ch == KSpace) || (ch == KHorizTab) || (ch == KDecimal));
       
   387 					}
       
   388 				}
       
   389 
       
   390 			// Check that we're getting digits
       
   391 			if (!done)
       
   392 				{
       
   393 				if ((ch < KZero) || (ch > KNine)) // digits 0-9
       
   394 					User::Leave(KUriUtilsErrMalformedInteger);
       
   395 				++numDigits;
       
   396 				}
       
   397 			}
       
   398 		// Make sure there's no overflow (trivial check)
       
   399 		if(numDigits>KMaxTIntDecimalDigits)
       
   400 			User::Leave(KUriUtilsErrMalformedInteger);
       
   401 		
       
   402 		// Now work back, building up the integer
       
   403 		aIntVal = 0;
       
   404 		for (TInt pos = 0; pos < numDigits; pos++)
       
   405 			{
       
   406 			// double check no overflow (
       
   407 			if(aIntVal>KMaxTIntDividedByTen   ||  //works except for 2147483648 and ...49)
       
   408 				( (aIntVal == KMaxTIntDividedByTen)  && (data[pos] >= (KNine-1)) ) // covers those two cases
       
   409 				)  
       
   410 				User::Leave(KUriUtilsErrMalformedInteger);
       
   411 			aIntVal = (data[pos] - KZero) + (aIntVal * 10); // decimal, innit?
       
   412 			}
       
   413 
       
   414 		// work out how much this has consumed
       
   415 		retVal += numDigits;
       
   416 
       
   417 		// Finally ensure the buffer has had the correct amount of data consumed
       
   418 		if (len == aBuffer.Length())
       
   419 			aBuffer.Set(KNullDesC8()); // there was nothing to the right of the integer
       
   420 		else
       
   421 			aBuffer.Set(aBuffer.Mid(retVal));
       
   422 		}
       
   423 	return retVal;
       
   424 	}
       
   425 
       
   426 /*
       
   427  *	Local methods
       
   428  */
       
   429 
       
   430 /**
       
   431 	@internalComponent
       
   432 	
       
   433 	Does the whitespace removal. Checks the mode and then calls the appropriate
       
   434 	functions.
       
   435 
       
   436 	@warning		Will panic will KUriUtilsErrBadTExtRemoveMode if aMode not valid.
       
   437 	@param			aData	A descriptor pointer with the data.
       
   438 	@param			aMode	The specified removal mode.
       
   439 	@return			The number of consumed whitespace characters. If the data is
       
   440 					empty or the data is all whitespace the error code 
       
   441 					KUriUtilsErrEmptyData is returned.
       
   442 */
       
   443 template<class TPtrCType>
       
   444 TInt DoRemoveWhiteSpace(TPtrCType& aData, InetProtTextUtils::TRemoveMode aMode)
       
   445 	{
       
   446 	TInt consumed = 0;
       
   447 	switch( aMode )
       
   448 		{
       
   449 	case InetProtTextUtils::ERemoveLeft:
       
   450 		{
       
   451 		consumed = FindWhiteSpaceLeft(aData);
       
   452 		if( consumed > 0 )
       
   453 			{
       
   454 			// Found some whitespace
       
   455 			aData.Set(aData.Mid(consumed));
       
   456 			}
       
   457 		} break;
       
   458 	case InetProtTextUtils::ERemoveRight:
       
   459 		{
       
   460 		consumed = FindWhiteSpaceRight(aData);
       
   461 		if( consumed > 0 )
       
   462 			{
       
   463 			// Found some whitespace
       
   464 			aData.Set(aData.Left(aData.Length() - consumed));
       
   465 			}
       
   466 		} break;
       
   467 	case InetProtTextUtils::ERemoveBoth:
       
   468 		{
       
   469 		// Remove from left first...
       
   470 		consumed = FindWhiteSpaceLeft(aData);
       
   471  		if( consumed != KUriUtilsErrEmptyData )
       
   472 			{
       
   473 			// Found some whitespace - set the pointer then remove from right
       
   474 			aData.Set(aData.Mid(consumed));
       
   475 			TInt consumedRight = FindWhiteSpaceRight(aData);
       
   476 
       
   477 			// To get this far descriptor is non-empty and not all whitespace - no check
       
   478 			aData.Set(aData.Left(aData.Length() - consumedRight));
       
   479 			consumed += consumedRight;
       
   480 			}
       
   481 		} break;
       
   482 	default:
       
   483 		__ASSERT_DEBUG(EFalse, User::Panic(KTextUtilsPanicCategory, KUriUtilsErrBadTextRemoveMode));
       
   484 		}
       
   485 	return consumed;
       
   486 	}
       
   487 
       
   488 /**
       
   489 	@internalComponent
       
   490 	
       
   491 	Finds the number of contiguous whitespace characters at the 
       
   492 	beginning of the data.
       
   493 
       
   494 	@param			aData	A descriptor pointer with the data.
       
   495 	@return			The number of consumed whitespace characters. If the data is
       
   496 					empty or the data is all whitespace the error code 
       
   497 					KTextUtilsErrEmptyData is returned.
       
   498  */
       
   499 template<class TPtrCType>
       
   500 TInt FindWhiteSpaceLeft(const TPtrCType& aData)
       
   501 	{
       
   502 	const TInt length = aData.Length();
       
   503 	if( length == 0 )
       
   504 		return KUriUtilsErrEmptyData;
       
   505 	TInt i = 0;
       
   506 	TBool done = EFalse;
       
   507 	while( !done && i < length )
       
   508 		{
       
   509 		TChar current = aData[i];
       
   510 		done  = !current.IsSpace();
       
   511 		if( !done )
       
   512 			++i;
       
   513 		}
       
   514 	if( i == length )
       
   515 		return KUriUtilsErrEmptyData;
       
   516 	return i;
       
   517 	}
       
   518 
       
   519 /**
       
   520 	@internalComponent
       
   521 	
       
   522 	Finds the number of contiguous whitespace characters at the end of the data.
       
   523 
       
   524 	@param			aData	A descriptor pointer with the data.
       
   525 	@return			The number of consumed whitespace characters. If the data is
       
   526 					empty or the data is all whitespace the error code 
       
   527 					KTextUtilsErrEmptyData is returned.
       
   528 */
       
   529 template<class TPtrCType>
       
   530 TInt FindWhiteSpaceRight(const TPtrCType& aData)
       
   531 	{
       
   532 	const TInt length = aData.Length();
       
   533 	if( length == 0 )
       
   534 		return KUriUtilsErrEmptyData;
       
   535 	TInt i = 0;
       
   536 	TBool done = EFalse;
       
   537 	while( !done && i < length )
       
   538 		{
       
   539 		TChar current = aData[(length-1) - i];
       
   540 		done  = !current.IsSpace();
       
   541 		if( !done )
       
   542 			++i;
       
   543 		}
       
   544 	if( i == length )
       
   545 		return KUriUtilsErrEmptyData;
       
   546 	return i;
       
   547 	}
       
   548 
       
   549 /** 
       
   550 	Extracts next token from the buffer.
       
   551 	
       
   552 	@param			aBuffer		The buffer containing the token-list.
       
   553 	@param			aToken		An output argument containing the extracted token.
       
   554 	@param			aSeparator	The separator character.
       
   555 	@return			The number of characters consumed from the buffer.
       
   556 */
       
   557 template<class TPtrCType>
       
   558 TInt DoExtractNextTokenFromList(TPtrCType& aBuffer, TPtrCType& aToken, TChar aSeparator)
       
   559 	{
       
   560 	// Anticipate an empty token by default.
       
   561 	TInt consumed = 0;
       
   562 
       
   563 	// Search for the separator
       
   564 	const TInt pos = aBuffer.Locate(aSeparator);
       
   565 
       
   566 	// If the separator was found, take chars upto it. Otherwise use the whole
       
   567 	// remaining buffer - implies the last token in the list.
       
   568 	if( pos == KErrNotFound )
       
   569 		{
       
   570 		// Last token - take the whole lot
       
   571 		aToken.Set(aBuffer);
       
   572 		consumed = aBuffer.Length();
       
   573 		}
       
   574 	else
       
   575 		{
       
   576 		// Take upto the separator position for the token, and move the buffer 
       
   577 		// past the token.
       
   578 		aToken.Set(aBuffer.Left(pos));
       
   579 		consumed = pos + 1;	// include the separator
       
   580 		}
       
   581 	// Set the buffer to move past the extracted token.
       
   582 	aBuffer.Set(aBuffer.Mid(consumed));
       
   583 
       
   584 	// Trim out any whitespace surrounding the token, and return how many charas
       
   585 	// were consumed.
       
   586 	InetProtTextUtils::RemoveWhiteSpace(aToken, InetProtTextUtils::ERemoveBoth);
       
   587 	return consumed;
       
   588 	}
       
   589 
       
   590 /** 
       
   591 	Extracts next token from the buffer.
       
   592 	
       
   593 	@param			aBuffer		The buffer containing the token-list.
       
   594 	@param			aToken		An output argument containing the extracted token.
       
   595 	@param			aSeparator	The separator.
       
   596 	@return			The number of characters consumed from the buffer.
       
   597 */
       
   598 template<class TPtrCType>
       
   599 TInt DoExtractNextTokenFromList(TPtrCType& aBuffer, TPtrCType& aToken, const TPtrCType& aSeparator)
       
   600 	{
       
   601 	// Finds the next token in the list, where all the characters in
       
   602 	// the separator array are considered to be separators.
       
   603 
       
   604 	// Anticipate an empty token by default.
       
   605 	TInt consumed = 0;
       
   606 
       
   607 	// Search for separator...
       
   608 	const TInt length = aBuffer.Length();
       
   609 	TInt pos = 0;
       
   610 	TBool found = EFalse;
       
   611 	while( !found && pos < length )
       
   612 		{
       
   613 		// If we find a quoted string, skip over it (and any token
       
   614 		// separators within it)
       
   615 		if( aBuffer[pos] == KQuote )
       
   616 			{
       
   617 			for( ++pos; pos < length && aBuffer[pos] != KQuote; ++pos )
       
   618 				{}
       
   619 			if (pos == length)
       
   620 				break; // end of string reached
       
   621 			}
       
   622 		if( aSeparator.Locate(aBuffer[pos]) != KErrNotFound )
       
   623 			found = ETrue;
       
   624 		else
       
   625 			++pos;
       
   626 		}
       
   627 
       
   628 	// If the separator was found, take chars upto it. Otherwise use the whole
       
   629 	// remaining buffer - implies the last token in the list.
       
   630 	if( found )
       
   631 		{
       
   632 		// Take upto the separator position for the token, and move the buffer 
       
   633 		// past the token.
       
   634 		aToken.Set(aBuffer.Left(pos));
       
   635 		consumed = pos + 1;
       
   636 		}
       
   637 	else
       
   638 		{
       
   639 		// Last token - take the whole lot
       
   640 		aToken.Set(aBuffer);
       
   641 		consumed = aBuffer.Length();
       
   642 		}
       
   643 	// Set the buffer to move past the extracted token.
       
   644 	aBuffer.Set(aBuffer.Mid(consumed));
       
   645 
       
   646 	// Trim out any whitespace surrounding the token, and return how
       
   647 	// many characters were extracted.
       
   648 	InetProtTextUtils::RemoveWhiteSpace(aToken, InetProtTextUtils::ERemoveBoth);
       
   649 	return consumed;
       
   650 	}
       
   651 
       
   652 /**	
       
   653 	Extract a quoted string value from the buffer. 
       
   654 	
       
   655 	@param			aBuffer			The buffer containing the quoted.
       
   656 	@param			aQuotedString	An output argument containing the extracted
       
   657 									string.
       
   658 	@return			The number of characters consumed from the buffer.
       
   659 */
       
   660 template<class TPtrCType>
       
   661 TInt DoExtractQuotedStringL(TPtrCType& aBuffer, TPtrCType& aQuotedString)
       
   662 	{
       
   663 	// Find the opening "
       
   664 	TInt quotePos1 = aBuffer.Locate(KQuote);
       
   665 	if( quotePos1 == KErrNotFound )
       
   666 		User::Leave(KUriUtilsErrDecodeMalformedQuotedString);
       
   667 
       
   668 	// Find the closing "
       
   669 	TPtrCType temp = aBuffer.Mid(quotePos1 + 1);	// ignore the "
       
   670 	TInt quotePos2 = temp.LocateReverse(KQuote);
       
   671 	if( quotePos2 == KErrNotFound )
       
   672 		User::Leave(KUriUtilsErrDecodeMalformedQuotedString);
       
   673 	
       
   674 	// return what's between them and consume the right number of characters from the buffer
       
   675 	aQuotedString.Set(temp.Left(quotePos2));
       
   676 	TInt consumed = quotePos1 + quotePos2 + 2; // +2 is to consume the quotes themselves
       
   677 	aBuffer.Set(aBuffer.Mid(consumed));
       
   678 	return consumed;
       
   679 	}
       
   680 
       
   681 /**
       
   682 	Converts an integer value into its decimal character representation.
       
   683 	
       
   684 	@param			aInt		An integer value.	
       
   685 	@param			aBuffer		An output argument of a pointer to a data buffer
       
   686 	that will contain the character representation of the integer value.
       
   687 	@param			aRadix		enum value.	
       
   688 */
       
   689 template<class HBufCType>
       
   690 void DoConvertIntToDescriptorL(TInt aInt, HBufCType*& aBuffer, TRadix aRadix)
       
   691 	{
       
   692 	// Create the buffer - max possible size for binary number is 32
       
   693 	TBuf8<KMaxNumberSize> buf;
       
   694 	buf.SetMax();
       
   695 
       
   696 	// Is the number -ve?
       
   697 	TUint value = aInt;
       
   698 	TBool negative = EFalse;
       
   699 	if( aInt < 0 )
       
   700 		{
       
   701 		negative = ETrue;
       
   702 		value = -aInt;
       
   703 		}
       
   704 
       
   705 	// Now form the number...
       
   706 	TInt index = KMaxNumberSize;
       
   707 	do	
       
   708 		{
       
   709 		// Update the index
       
   710 		--index;
       
   711 		__ASSERT_DEBUG( index > 0, User::Invariant() );
       
   712 
       
   713 		// Find the value of the least significant digit
       
   714 		TUint q = value/aRadix;
       
   715 		TUint c = value - (q*aRadix);
       
   716 
       
   717 		// Convert digit to character and insert into the buffer.
       
   718 		( c > 9 ) ? c += (KAChar-10) : c += KZeroChar;
       
   719 		buf[index] = STATIC_CAST(TUint8, c);
       
   720 
       
   721 		// Update the value left to convert.
       
   722 		value = q;
       
   723 		} while( value > 0 );
       
   724 
       
   725 	// Add the '-' sign if number was negative
       
   726 	if( negative )
       
   727 		buf[--index] = KMinusSign;
       
   728 
       
   729 	// Create the output buffer...
       
   730 	TPtrC8 number = buf.Mid(index);
       
   731 	aBuffer = HBufCType::NewL(number.Length());
       
   732 	aBuffer->Des().Copy(number);
       
   733 	}
       
   734 
       
   735 /**
       
   736 	Converts the character representation of an integer into its numeric value.
       
   737 	Preceeding whitespace is ignored and the integer is delimited by either the
       
   738 	end of the data, whitespace or any other character other than 0 to 9.
       
   739 	
       
   740 	@param			aData	A descriptor pointer with the data.
       
   741 	@param			aInt	An output argument in which the numeric value of the
       
   742 	data is placed.
       
   743 	@param			aRadix		enum value.	
       
   744 	@return			The number of consumed characters that contributed to the 
       
   745 					integer value, including any whitespace before the integer. 
       
   746 					If the data is empty the error code KUriUtilsErrEmptyData 
       
   747 					is returned. If there are no digits at the beginning of the
       
   748 					data the error code KUriUtilsErrNoIntergerInData is returned.
       
   749 */
       
   750 template<class TPtrCType>
       
   751 TInt DoConvertDescriptorToInt(const TPtrCType& aData, TInt& aInt, TRadix aRadix)
       
   752 	{
       
   753 	// Remove any whitespace before the digits
       
   754 	TPtrCType data = aData;
       
   755 	TInt consumed = InetProtTextUtils::RemoveWhiteSpace(data, InetProtTextUtils::ERemoveLeft);
       
   756 
       
   757 	// Ensure that there are some digits to convert
       
   758 	TInt length = data.Length();
       
   759 	if( length == 0 )
       
   760 		{
       
   761 		return KUriUtilsErrEmptyData;
       
   762 		}
       
   763 
       
   764 	// Search for digits and calculate value - stop when non-digit found
       
   765 	TInt value = 0;
       
   766 	TBool done = EFalse;
       
   767 	
       
   768 	TBool negative=EFalse;
       
   769 
       
   770 	if(data[0]==KMinusSign)
       
   771 	   {
       
   772 		negative=ETrue;
       
   773 	   }	
       
   774 	
       
   775 	TInt i=0;
       
   776 	
       
   777 	// Length is verifying as user input may be just only '-' sign.
       
   778 	if( negative && length > 1 )
       
   779 		{
       
   780 		i = 1;	
       
   781 		}
       
   782 	while( !done )
       
   783 		{
       
   784 		// Get the current char and see if it is a digit
       
   785 		TChar c = data[i];
       
   786 
       
   787 		if( c.IsHexDigit() )
       
   788 			{
       
   789 			// Need to convert char to its numeric value
       
   790 			TInt digit = c - KZeroChar;
       
   791 
       
   792 			// Was the char in the A-F range?
       
   793 			if( digit > 9 )
       
   794 				digit = c.GetUpperCase() - (KAChar - 10);
       
   795 			
       
   796 			if( digit > aRadix )
       
   797 				{
       
   798 				// The character is too large for the radix - end of data.
       
   799 				done = ETrue;
       
   800 				}
       
   801 			else
       
   802 				{
       
   803 				// Update running total
       
   804 				value *= aRadix;
       
   805 				value += digit;
       
   806 				}
       
   807 			}
       
   808 		else
       
   809 			{
       
   810 			// Non-digit found - we're done!
       
   811 			done = ETrue;
       
   812 			}
       
   813 		// Check for end of data
       
   814 		done = done || !(++i < length);
       
   815 		}
       
   816 	// Set up outputs
       
   817 	if( i == 0 )
       
   818 		{
       
   819 		// No digits found in data - do not set aInt
       
   820 		return KUriUtilsErrNoIntegerInData;
       
   821 		}
       
   822 	// Set the value of the interger
       
   823 	if( negative )
       
   824 		aInt = -value;
       
   825 	else
       
   826 		aInt = value;
       
   827 
       
   828 	// Return consumed characters
       
   829 	return i + consumed;
       
   830 	}