genericservices/httputils/DelimitedParser/DelimitedParser.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 <delimitedparser8.h>
       
    17 #include <delimitedparser16.h>
       
    18 #include "DelimitedParserInternal.h"
       
    19 #include <uriutilscommon.h>
       
    20 
       
    21 // Panic category
       
    22 //
       
    23 _LIT(KDelimitedParserPanicCategory,"DELIM-PARSER"); 
       
    24 
       
    25 //
       
    26 //
       
    27 // Implementation of TDelimitedParserBase8
       
    28 //
       
    29 //
       
    30 
       
    31 /**
       
    32 	Constructor.
       
    33 	
       
    34 	@since			6.0
       
    35 */
       
    36 EXPORT_C TDelimitedParserBase8::TDelimitedParserBase8()
       
    37 : iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
       
    38 	{
       
    39 	}
       
    40 
       
    41 /**
       
    42 	Resets the internal pointer position to the start or end or the descriptor
       
    43 	depending on whether the decriptor is parsing mode.
       
    44 	
       
    45 	@warning		There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has 
       
    46 	not been correctly set.
       
    47  */
       
    48 EXPORT_C void TDelimitedParserBase8::Reset() const
       
    49 	{
       
    50 	iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
       
    51 	}
       
    52 
       
    53 /**
       
    54 	Retrieves the current segment and then parses the data to the next one.
       
    55 	
       
    56 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
    57 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
    58 	been set.
       
    59 	@since			6.0
       
    60 	@param			aSegment	This is an output argument that is set to the current segment.
       
    61 	@return			A error value of KErrNotFound if there is no current segment. The 
       
    62 	value KErrNone if there is a current segment.
       
    63 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
    64 	@post			The current segment is updated to the next one.
       
    65 */
       
    66 EXPORT_C TInt TDelimitedParserBase8::GetNext(TPtrC8& aSegment) const
       
    67 	{
       
    68 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
    69 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
    70 
       
    71 	// Check that there is a segment
       
    72 	if( iNextSegmentPos == KErrNotFound )
       
    73 		{
       
    74 		// There is no segment
       
    75 		return KErrNotFound;
       
    76 		}
       
    77 	// There is one - set aSegment
       
    78 	aSegment.Set(iCurrentSegment);
       
    79 	// Parse the next segment
       
    80 	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
       
    81 	return KErrNone;
       
    82 	}
       
    83 
       
    84 /**
       
    85 	Parses to the next segment.
       
    86 	
       
    87 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
    88 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
    89 	been set.
       
    90 	@since			6.0
       
    91 	@return			A error value of KErrNotFound if there is no current segment. The 
       
    92 	value KErrNone if there is a current segment.
       
    93 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
    94 	@post			The current segment is updated to the next one.
       
    95  */	
       
    96 EXPORT_C TInt TDelimitedParserBase8::Inc() const
       
    97 	{
       
    98 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
    99 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   100 
       
   101 	// Check that there is a segment
       
   102 	if( iNextSegmentPos == KErrNotFound )
       
   103 		{
       
   104 		// There is no segment
       
   105 		return KErrNotFound;
       
   106 		}
       
   107 	// Parse the next segment
       
   108 	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
       
   109 	return KErrNone;
       
   110 	}
       
   111 
       
   112 /**
       
   113 	Parses back to the previous segment.
       
   114 	
       
   115 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   116 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   117 	been set.
       
   118 	@since			6.0
       
   119 	@return			A error value of KErrNotFound if the current segment is the initial 
       
   120 	segment. The value KErrNone if the data has been parsed to the previous segment.
       
   121 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
   122 	@post			If the parse was successful then the  current segment is updated 
       
   123 	to the previous one. Otherwise there is no change.
       
   124 */
       
   125 EXPORT_C TInt TDelimitedParserBase8::Dec() const
       
   126 	{
       
   127 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   128 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   129 
       
   130 	// Find position of previous delimiter 
       
   131 	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
       
   132 
       
   133 	// Get the previous segment
       
   134 	if( FindPrevSegment(prev) == KErrNotFound )
       
   135 		{
       
   136 		// There is no previous segment - set to start of data
       
   137 		return KErrNotFound;
       
   138 		}
       
   139 	// Update next segment position
       
   140 	iNextSegmentPos = prev;
       
   141 	return KErrNone;
       
   142 	}
       
   143 
       
   144 /**
       
   145 	Retrieves the current segment.
       
   146 	
       
   147 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   148 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   149 	been set.
       
   150 	@since			6.0
       
   151 	@param			aSegment	This is an output argument that is set to the current segment.
       
   152 	@return			A error value of KErrNotFound if there is no current segment. The 
       
   153 	value KErrNone if there is a current segment.
       
   154 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
   155 */
       
   156 EXPORT_C TInt TDelimitedParserBase8::Peek(TPtrC8& aSegment) const
       
   157 	{
       
   158 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   159 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   160 
       
   161 	// Check that there is a segment
       
   162 	if( iNextSegmentPos == KErrNotFound )
       
   163 		{
       
   164 		// There is no segment
       
   165 		return KErrNotFound;
       
   166 		}
       
   167 	// There is one - set aSegment
       
   168 	aSegment.Set(iCurrentSegment);
       
   169 	return KErrNone;
       
   170 	}
       
   171 
       
   172 /**
       
   173 	Indicates whether the end of the data has been reached and there are no more segments 
       
   174 	to parse.
       
   175 	
       
   176 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   177 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   178 	been set.
       
   179 	@since			6.0
       
   180 	@return			A boolean value of ETrue if the end of the data has been reached,
       
   181 	or EFalse if there are more segements to parse.
       
   182 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
   183 */
       
   184 EXPORT_C TBool TDelimitedParserBase8::Eos() const
       
   185 	{
       
   186 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   187 
       
   188 	TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
       
   189 	return eos;
       
   190 	}
       
   191 
       
   192 /**
       
   193 	Checks for a delimiter at the front (left) of the data.
       
   194 	
       
   195 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   196 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
   197 	@since			6.0
       
   198 	@return			A boolean of value ETrue if there is a front delimiter, or EFalse 
       
   199 	if there is no front delimiter.
       
   200 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
   201 */
       
   202 EXPORT_C TBool TDelimitedParserBase8::FrontDelimiter() const
       
   203 	{
       
   204 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   205 
       
   206 	return (iDataDes.Locate(iDelimiter) == 0);
       
   207 	}
       
   208 
       
   209 /**
       
   210 	Checks for a delimiter at the back (right) of the data.
       
   211 	
       
   212 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   213 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   214 	been set.
       
   215 	@since			6.0
       
   216 	@return			A boolean of value ETrue if there is a back delimiter, or EFalse 
       
   217 	if there is no back delimiter.
       
   218 	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
       
   219 */
       
   220 EXPORT_C TBool TDelimitedParserBase8::BackDelimiter() const
       
   221 	{
       
   222 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   223 
       
   224 	TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
       
   225 	if( delimiterPos == KErrNotFound )
       
   226 		return EFalse;
       
   227 	return (delimiterPos == iDataDes.Length() - 1);
       
   228 	}
       
   229 
       
   230 /**
       
   231 	Retrieves the descriptor reference with the data
       
   232 	
       
   233 	@since			6.0
       
   234 	@return			A const descriptor reference with the data.
       
   235 */
       
   236 EXPORT_C const TDesC8& TDelimitedParserBase8::Des() const
       
   237 	{
       
   238 	return iDataDes;
       
   239 	}
       
   240 
       
   241 /**
       
   242 	Gives the remainder of the data from (and including) the current segment. Any other segments 
       
   243 	that have parsed through are not included.
       
   244 	
       
   245 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   246 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   247 	been set.
       
   248 	@since			6.0
       
   249 	@param			aRemainder	This is an output argument that is set to the remaining data.
       
   250 	@return			An error value of KErrNotFound if there is no remaining data, or 
       
   251 	value of KErrNone if there is remaining data.
       
   252 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
   253  */
       
   254 EXPORT_C TInt TDelimitedParserBase8::Remainder(TPtrC8& aRemainder) const
       
   255 	{
       
   256 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   257 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   258 
       
   259 	// Check to see if there is a segment left
       
   260 	if( iNextSegmentPos == KErrNotFound )
       
   261 		{
       
   262 		// There is no segment
       
   263 		return KErrNotFound;
       
   264 		}
       
   265 	// Find the previous delimiter -> the start of the current segment
       
   266 	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
       
   267 
       
   268 	// Need to see which direction the parsing is going to set the remainder
       
   269 	switch(iMode)
       
   270 		{
       
   271 	case EDelimitedDataForward:
       
   272 		{
       
   273 		aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
       
   274 		} break;
       
   275 	case EDelimitedDataReverse:
       
   276 		{
       
   277 		aRemainder.Set(iDataDes.Left(prev));
       
   278 		} break;
       
   279 	default:
       
   280 		// Bad mode!
       
   281 		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
       
   282 		break;
       
   283 		}
       
   284 	return KErrNone;
       
   285 	}
       
   286 
       
   287 /**
       
   288 	This parses the data into segments from left to right.
       
   289 
       
   290 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
   291 	has not been set.
       
   292 	@since			6.0
       
   293 	@param			aData	A descriptor containing the data.
       
   294 	@pre 			The delimiter must have been set.
       
   295 	@post			The current segment is the leftmost segment and the direction of 
       
   296 	parsing is set from left to right (EDelimitedDataFroward).
       
   297  */
       
   298 EXPORT_C void TDelimitedParserBase8::Parse(const TDesC8& aData)
       
   299 	{
       
   300 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   301 
       
   302 	// Initialise data for EForward direction
       
   303 	iMode = EDelimitedDataForward;
       
   304 	DoParse(aData);
       
   305 	}
       
   306 
       
   307 /**
       
   308 	This parses the data into segments from lright to left.
       
   309 
       
   310 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
   311 	has not been set.
       
   312 	@since			6.0
       
   313 	@param			aData	A descriptor containing the data.
       
   314 	@pre 			The delimiter must have been set.
       
   315 	@post			The current segment is the leftmost segment and the direction of 
       
   316 	parsing is set from right to left (EDelimitedDataReverse).
       
   317  */
       
   318 EXPORT_C void TDelimitedParserBase8::ParseReverse(const TDesC8& aData)
       
   319 	{
       
   320 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   321 
       
   322 	// Initialise data for EReverse direction
       
   323 	iMode = EDelimitedDataReverse;
       
   324 	DoParse(aData);
       
   325 	}
       
   326 
       
   327 /**
       
   328 	Sets the delimiting character.
       
   329 	
       
   330 	@since			6.0
       
   331 	@param			aDelimiter	The delimiting character.
       
   332 	@post			The delimiting character is set.
       
   333 */
       
   334 EXPORT_C void TDelimitedParserBase8::SetDelimiter(TChar aDelimiter)
       
   335 	{
       
   336 	iDelimiter = aDelimiter;
       
   337 	}
       
   338 
       
   339 /**
       
   340 	Initialises the parsing of the data.
       
   341 	
       
   342 	@since			6.0
       
   343 	@param			aData	A descriptor reference with the data.
       
   344 	@pre 			The delimiting character has been set.
       
   345 	@post			The data descriptor is set to the input argument. The current 
       
   346 	segment refers to the initial segment of the data.
       
   347 */
       
   348 void TDelimitedParserBase8::DoParse(const TDesC8& aData)
       
   349 	{
       
   350 	// Reset the segment information, then set the new Data - set pointer to NULL and length to zero
       
   351 	iCurrentSegment.Set(NULL,0);
       
   352 	iDataDes.Set(aData);
       
   353 
       
   354 	// Check that there is a string!
       
   355 	if( iDataDes.Length() == 0 )
       
   356 		{
       
   357 		// No string - ensure functionality blocked for this descriptor
       
   358 		iNextSegmentPos = KErrNotFound;
       
   359 		return;
       
   360 		}
       
   361 	// Find the segment - search from initial start position
       
   362 	iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
       
   363 	}
       
   364 
       
   365 /**
       
   366 	Finds the next segment from the given start position.
       
   367 	
       
   368 	@since			6.0
       
   369 	@param			aStartPos	The position from where to start the search for the
       
   370 	next segment.
       
   371 	@return			The position of delimiter after the specified start position, or 
       
   372 	an error value of KErrNotFound if no more delimiters are found.
       
   373 */
       
   374 TInt TDelimitedParserBase8::FindNextSegment(TInt aStartPos) const
       
   375 	{
       
   376 	// Find position of next delimiter
       
   377 	TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
       
   378 
       
   379 	if( next != KErrNotFound )
       
   380 		{
       
   381 		TInt startPos = next < aStartPos ? next : aStartPos;
       
   382 		TInt endPos = next < aStartPos ? aStartPos : next;
       
   383 		if( iDataDes[startPos] == iDelimiter )
       
   384 			{
       
   385 			// Move past delimiter
       
   386 			++startPos;
       
   387 			}
       
   388 		TInt length = endPos - startPos;
       
   389 		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
       
   390 		}
       
   391 	return next;
       
   392 	}
       
   393 
       
   394 /**
       
   395 	Finds the previous segment from the given start position.
       
   396 	
       
   397 	@since			6.0
       
   398 	@param			aStartPos	The position from where to start the search for the
       
   399 					previous segment.
       
   400 	@return			The position of delimiter before the specified start position, or 
       
   401 	an error value of KErrNotFound if no more delimiters are found.
       
   402 */
       
   403 TInt TDelimitedParserBase8::FindPrevSegment(TInt aStartPos) const
       
   404 	{
       
   405 	// Find position of previous delimiter 
       
   406 	TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
       
   407 	
       
   408 	if( prev != KErrNotFound )
       
   409 		{
       
   410 		TInt startPos = prev < aStartPos ? prev : aStartPos;
       
   411 		TInt endPos = prev < aStartPos ? aStartPos : prev;
       
   412 		if( iDataDes[startPos] == iDelimiter )
       
   413 			{
       
   414 			// Move past delimiter
       
   415 			++startPos;
       
   416 			}
       
   417 		TInt length = endPos - startPos;
       
   418 		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
       
   419 		}
       
   420 	return prev;
       
   421 	}
       
   422 
       
   423 //
       
   424 //
       
   425 // Implementation of CDelimitedDataBase8
       
   426 //
       
   427 //
       
   428 
       
   429 /**
       
   430 	Destructor.
       
   431 	
       
   432 	@since			6.0
       
   433 */
       
   434 EXPORT_C CDelimitedDataBase8::~CDelimitedDataBase8()
       
   435 	{
       
   436 	delete iDataBuf;
       
   437 	}
       
   438 
       
   439 /**
       
   440 	Inserts the new segment in a position before the current parsed	segment. The new 
       
   441 	segment can be made up of several segments and have delimiters at either extreme. 
       
   442 	The insert functionality will ensure that there is always a delimiter at the front 
       
   443 	of the new segment. The parser is left in a state where its current segment is the 
       
   444 	same one as before the insertion.
       
   445 	
       
   446 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been 
       
   447 	parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
   448 	@since			6.0
       
   449 	@param			aSegment	A descriptor with the new segment to be inserted.
       
   450 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
   451 	@post			The data will have been extended to include the new segment. The 
       
   452 	current segment will remain as the one before the insertion.
       
   453 */
       
   454 EXPORT_C void CDelimitedDataBase8::InsertCurrentL(const TDesC8& aSegment)
       
   455 	{
       
   456 	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   457 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   458 
       
   459 	DoInsertL(aSegment);
       
   460 	}
       
   461 
       
   462 /**
       
   463 	Removes the current segment. After removing the segment, the parser's new current segment 
       
   464 	will be the next segment. If the last segment is the one that is removed then the parser 
       
   465 	will be set to the end of the data.
       
   466 	
       
   467 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   468 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   469 	been set.
       
   470 	@since			6.0
       
   471 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
   472 	@post			The data will have been reduced to exclude the removed segment.
       
   473 	The current segment will be set to what was the next segment. If the removed segment was 
       
   474 	the last segment, the parser is at the end of the data.
       
   475 */
       
   476 EXPORT_C void CDelimitedDataBase8::RemoveCurrentL()
       
   477 	{
       
   478 	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   479 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   480 
       
   481 	DoRemoveL();
       
   482 	}
       
   483 
       
   484 /**
       
   485 	Adds a new segment to the end of the data. The new segment can be made up of several segments 
       
   486 	and have  delimiters at either extreme. The insert functionality will ensure that there is 
       
   487 	always a delimiter at the front of the new segment. The data must re-parsed to ensure that the 
       
   488 	parser is valid.
       
   489 						
       
   490 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   491 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   492 	been set. A re-parse is required to ensure that the parser is valid.
       
   493 	@since			6.0
       
   494 	@param			aSegment	A descriptor with the new segment to be inserted.
       
   495 	@pre 			The delimiter must have been set. 
       
   496 	@post			The data will have been extended to include the new segment.
       
   497 */
       
   498 EXPORT_C void CDelimitedDataBase8::PushBackL(const TDesC8& aSegment)
       
   499 	{
       
   500 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   501 
       
   502 	// Parse the string in reverse direction - sets last segment as current
       
   503 	iParser.ParseReverse(*iDataBuf);
       
   504 
       
   505 	// Insert the segment
       
   506 	DoInsertL(aSegment);
       
   507 
       
   508 	// Make sure that a re-parse is required
       
   509 	iParser.iMode = EDelimitedDataNotParsed;
       
   510 	}
       
   511 
       
   512 /**
       
   513 	Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
       
   514 						
       
   515 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   516 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   517 	been set. A re-parse is required to ensure that the parser is valid.
       
   518 	@since			6.0
       
   519 	@pre 			The delimiter must have been set.
       
   520 	@post			The data will have been reduced to exclude the last segment. 
       
   521 */
       
   522 EXPORT_C void CDelimitedDataBase8::PopBackL()
       
   523 	{
       
   524 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   525 
       
   526 	// Parse the string in reverse direction - sets last segment as current
       
   527 	iParser.ParseReverse(*iDataBuf);
       
   528 
       
   529 	// Remove the current segment
       
   530 	DoRemoveL();
       
   531 
       
   532 	// Make sure that a re-parse is required
       
   533 	iParser.iMode = EDelimitedDataNotParsed;
       
   534 	}
       
   535 
       
   536 /**
       
   537 	Adds a new segment to the front of the data. The new segment can be made up of several segments 
       
   538 	and have delimiters at either extreme. The insert functionality will ensure that there is always 
       
   539 	a delimiter at the front of the new segment. The data must re-parsed to ensure that the parser 
       
   540 	is valid.
       
   541 						
       
   542 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   543 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   544 	been set. A re-parse is required to ensure that the parser is valid.					
       
   545 	@since			6.0
       
   546 	@param			aSegment	A descriptor with the new segment to be inserted.
       
   547 	@pre 			The delimiter must have been set. 
       
   548 	@post			The data will have been extended to include the new segment.
       
   549 */
       
   550 EXPORT_C void CDelimitedDataBase8::PushFrontL(const TDesC8& aSegment)
       
   551 	{
       
   552 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   553 
       
   554 	// Parse the string in forward direction - sets first segment as current
       
   555 	iParser.Parse(*iDataBuf);
       
   556 
       
   557 	// Insert the segment
       
   558 	DoInsertL(aSegment);
       
   559 
       
   560 	// Make sure that a re-parse is required
       
   561 	iParser.iMode = EDelimitedDataNotParsed;
       
   562 	}
       
   563 
       
   564 /**
       
   565 	Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
       
   566 	
       
   567 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   568 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   569 	been set. A re-parse is required to ensure that the parser is valid.
       
   570 	@since			6.0
       
   571 	@pre 			The delimiter must have been set.
       
   572 	@post			The data will have been reduced to exclude the last segment. 
       
   573 */
       
   574 EXPORT_C void CDelimitedDataBase8::PopFrontL()
       
   575 	{
       
   576 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   577 
       
   578 	// Parse the string in forward direction - sets first segment as current
       
   579 	iParser.Parse(*iDataBuf);
       
   580 
       
   581 	// Remove the current segment
       
   582 	DoRemoveL();
       
   583 
       
   584 	// Make sure that a re-parse is required
       
   585 	iParser.iMode = EDelimitedDataNotParsed;
       
   586 	}
       
   587 
       
   588 /**
       
   589 	Removes the front delimiter (if exists) from the data.
       
   590 	
       
   591 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   592 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   593 	been set. A re-parse is required to ensure that the parser is valid.
       
   594 	@since			6.0
       
   595 	@pre 			The delimiter must have been set.
       
   596 	@post			The data might have been reduced to exclude the front delimiter. 
       
   597 */
       
   598 EXPORT_C void CDelimitedDataBase8::TrimFrontDelimiterL()
       
   599 	{
       
   600 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   601 
       
   602 	// Search for delimiter
       
   603 	if( iParser.FrontDelimiter() )
       
   604 		{
       
   605 		// Remove front delimiter and update member data
       
   606 		SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
       
   607 		}
       
   608 	// Make sure that a re-parse is required
       
   609 	iParser.iMode = EDelimitedDataNotParsed;
       
   610 	}
       
   611 
       
   612 /**
       
   613 	Adds a delimiter to the front of the data (if it doesn't exist).
       
   614 	
       
   615 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   616 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   617 	been set. A re-parse is required to ensure that the parser is valid.
       
   618 	@since			6.0
       
   619 	@pre 			The delimiter must have been set.
       
   620 	@post			The data might have been extended to include a front delimiter. 
       
   621 */
       
   622 EXPORT_C void CDelimitedDataBase8::AddFrontDelimiterL()
       
   623 	{
       
   624 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   625 
       
   626 	if( !iParser.FrontDelimiter() )
       
   627 		{
       
   628 		// Create a new buffer of correct size
       
   629 		HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
       
   630 		TPtr8 str = buf->Des();
       
   631 
       
   632 		// Append a delimiter, then append the current string
       
   633 		str.Append(iParser.iDelimiter);
       
   634 		str.Append(iParser.iDataDes);
       
   635 
       
   636 		// Set buffer to this new string
       
   637 		SetData(buf);
       
   638 		}
       
   639 	// Make sure that a re-parse is required
       
   640 	iParser.iMode = EDelimitedDataNotParsed;
       
   641 	}
       
   642 
       
   643 /**
       
   644 	Removes the back delimiter (if exists) from the data.
       
   645 	
       
   646 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   647 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   648 	been set. A re-parse is required to ensure that the parser is valid.
       
   649 	@since			6.0
       
   650 	@pre 			The delimiter must have been set.
       
   651 	@post			The data might have been reduced to exclude the front delimiter. 
       
   652 */
       
   653 EXPORT_C void CDelimitedDataBase8::TrimBackDelimiterL()
       
   654 	{
       
   655 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   656 
       
   657 	// Search for delimiter
       
   658 	if( iParser.BackDelimiter() )
       
   659 		{
       
   660 		// Remove back delimiter and update member data
       
   661 		SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
       
   662 		}
       
   663 	// Make sure that a re-parse is required
       
   664 	iParser.iMode = EDelimitedDataNotParsed;
       
   665 	}
       
   666 
       
   667 /**
       
   668 	Adds a delimiter to the back of the data (if it doesn't exist).
       
   669 	
       
   670 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
       
   671 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
   672 	been set. A re-parse is required to ensure that the parser is valid.
       
   673 	@since			6.0
       
   674 	@pre 			The delimiter must have been set.
       
   675 	@post			The data might have been extended to include a front delimiter. 
       
   676 */
       
   677 EXPORT_C void CDelimitedDataBase8::AddBackDelimiterL()
       
   678 	{
       
   679 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   680 
       
   681 	if( !iParser.BackDelimiter() )
       
   682 		{
       
   683 		// Create a new buffer of correct size
       
   684 		HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
       
   685 		TPtr8 str = buf->Des();
       
   686 
       
   687 		// Append the current string, then append a delimiter
       
   688 		str.Append(iParser.iDataDes);
       
   689 		str.Append(iParser.iDelimiter);
       
   690 
       
   691 		// Set buffer to this new string
       
   692 		SetData(buf);
       
   693 		}
       
   694 	// Make sure that a re-parse is required
       
   695 	iParser.iMode = EDelimitedDataNotParsed;
       
   696 	}
       
   697 
       
   698 /**
       
   699 	This parses the data into segments from left to right.
       
   700 	
       
   701 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
   702 	has not been set.
       
   703 	@since			6.0
       
   704 	@pre 			The delimiter must have been set.
       
   705 	@post			The current segment is the leftmost segment and the direction of 
       
   706 	parsing is set from left to right (EDelimitedDataFroward).
       
   707 */
       
   708 EXPORT_C void CDelimitedDataBase8::Parse()
       
   709 	{
       
   710 	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
       
   711 	iParser.Parse(*iDataBuf);
       
   712 	}
       
   713 
       
   714 /**
       
   715 	This parses the string into segments from right to left.
       
   716 	
       
   717 	@since			6.0
       
   718 	@pre 			The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if 
       
   719 	the delimiter has not been initialized.
       
   720 	@post			The current segment is the leftmost segment and the direction of parsing is right to left.
       
   721 */
       
   722 EXPORT_C void CDelimitedDataBase8::ParseReverse()
       
   723 	{
       
   724 	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
       
   725 	iParser.ParseReverse(*iDataBuf);
       
   726 	}
       
   727 
       
   728 /**
       
   729 	Retrieves a const reference to the delimited data parser. 
       
   730 	
       
   731 	@since			6.0
       
   732 	@return			A const reference to the delimited data parser. 
       
   733 */
       
   734 EXPORT_C const TDelimitedParserBase8& CDelimitedDataBase8::Parser() const
       
   735 	{
       
   736 	return iParser;
       
   737 	}
       
   738 
       
   739 /**
       
   740 	Sets the delimiting character.
       
   741 	
       
   742 	@since			6.0
       
   743 	@param			aDelimiter	The delimiting character.
       
   744 	@post			The delimiting character is updated.
       
   745 */
       
   746 EXPORT_C void CDelimitedDataBase8::SetDelimiter(TChar aDelimiter)
       
   747 	{
       
   748 	iParser.SetDelimiter(aDelimiter);
       
   749 	}
       
   750 
       
   751 /**
       
   752 	Constructor. First phase of two-phase construction method. Does non-allocating construction.
       
   753 						
       
   754 	@since			6.0
       
   755 */
       
   756 EXPORT_C CDelimitedDataBase8::CDelimitedDataBase8()
       
   757 	{
       
   758 	}
       
   759 
       
   760 /**
       
   761 	Second phase of two-phase construction method. Does any allocations required to fully construct 
       
   762 	the object.
       
   763 						
       
   764 	@since			6.0
       
   765 	@param			aData	A descriptor with the initial string.
       
   766 	@pre 			First phase of construction is complete.
       
   767 	@post			The object is fully constructed.
       
   768 */
       
   769 EXPORT_C void CDelimitedDataBase8::ConstructL(const TDesC8& aData)
       
   770 	{
       
   771 	// Create copy of string and set descriptor in the parser
       
   772 	SetDataL(aData);
       
   773 	}
       
   774 
       
   775 /**
       
   776 	Inserts the new segment in a position before the current segment. The new segment can be made up 
       
   777 	of several segments and have delimiters at either extreme. The insert functionality will ensure 
       
   778 	that there is always a delimiter at the front of the new segment. The parser will be left in a 
       
   779 	state where its current segment is the same one as before the insertion.
       
   780 						
       
   781 	@since			6.0
       
   782 	@param			aSegment	The descriptor with the segment to be inserted.
       
   783 	@pre 			The string must have been parsed.
       
   784 	@post			The string will have been extended to include the new segment. The current segment will
       
   785 	remain as the one before the insertion.
       
   786 */
       
   787 void CDelimitedDataBase8::DoInsertL(const TDesC8& aSegment)
       
   788 	{
       
   789 	// Get previous delimiter to split the current string into prefix and suffix to the new segment
       
   790 	TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
       
   791 	TPtrC8 prefix = iParser.iDataDes.Left(prevPos);
       
   792 
       
   793 	TInt suffixLength = iParser.iDataDes.Length() - prevPos;
       
   794 	TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
       
   795 	if( suffixLength && suffix[0] == iParser.iDelimiter )
       
   796 		{
       
   797 		// Remove front delimiter on suffix
       
   798 		suffix.Set(suffix.Right(--suffixLength));
       
   799 		}	
       
   800 
       
   801 	// Check for delimiters
       
   802 	TPtrC8 segment = aSegment;
       
   803 	TInt segmentLength = segment.Length();
       
   804 	TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
       
   805 	if( segmentBackDelimiter )
       
   806 		{
       
   807 		// Remove back delimiter from the segment
       
   808 		segment.Set(segment.Left(--segmentLength));
       
   809 		}
       
   810 	if( segmentLength && segment[0] == iParser.iDelimiter )
       
   811 		{
       
   812 		// Remove front delimiter from the segment
       
   813 		segment.Set(segment.Right(--segmentLength));
       
   814 		}
       
   815 
       
   816 	// Check if a back delimiter is needed - NOTE always add a front delimiter
       
   817 	TInt extra = 1;
       
   818 	TBool needBackDelimiter = EFalse;
       
   819 	if( suffix.Length() || segmentBackDelimiter )
       
   820 		{
       
   821 		++extra;
       
   822 		needBackDelimiter = ETrue;
       
   823 		}
       
   824 	// Create space for new string
       
   825 	HBufC8* buf = HBufC8::NewL(prevPos + segmentLength + suffixLength + extra);
       
   826 	TPtr8 str = buf->Des();
       
   827 
       
   828 	// Form the new string
       
   829 	str.Append(prefix);
       
   830 	str.Append(iParser.iDelimiter);
       
   831 	str.Append(segment);
       
   832 	if( needBackDelimiter )
       
   833 		str.Append(iParser.iDelimiter);
       
   834 	str.Append(suffix);
       
   835 
       
   836 	// Update string data
       
   837 	SetData(buf);
       
   838 
       
   839 	// Check to see if the internal parser object (iParser) has been parsed
       
   840 	// (can tell if it has if the data pointer in iCurrentSegment is not NULL)
       
   841 	// If so update iCurrentSegment to ensure that iParser remains valid
       
   842 	if( iParser.iCurrentSegment.Ptr() )
       
   843 		{
       
   844 		// Ensure parser is in correct position and current segment is correct
       
   845 		iParser.iNextSegmentPos = prevPos;
       
   846 		if( iParser.iMode == EDelimitedDataForward )
       
   847 			{
       
   848 			// Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
       
   849 			iParser.iNextSegmentPos += segmentLength + 1;
       
   850 			}
       
   851 		// Get the next segment
       
   852 		iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
       
   853 		}
       
   854 	}
       
   855 
       
   856 /**
       
   857 	Removes the current segment. After removing the segment, the parser's new current segment will be 
       
   858 	the next segment. If the last segment is the one that is removed then the parser will be set to the 
       
   859 	end of the data.
       
   860 						
       
   861 	@since			6.0
       
   862 	@pre 			The data must have been parsed.
       
   863 	@post			The data will have been reduced to exclude the removed data. The 
       
   864 	current segment is set to what was the next segment. If the removed segment was 
       
   865 	the last segment, the parser is at the end of the data.
       
   866 */
       
   867 void CDelimitedDataBase8::DoRemoveL()
       
   868 	{
       
   869 	// Check if there is anything to remove
       
   870 	if( iParser.iDataDes.Length() == 0 )
       
   871 		{
       
   872 		return;
       
   873 		}
       
   874 	// Find the previous delimiter
       
   875 	TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
       
   876 
       
   877 	// Set up the start and end position of current segment
       
   878 	TInt endPos = iParser.iNextSegmentPos;
       
   879 	TInt startPos = iParser.iNextSegmentPos;
       
   880 	if( prev < iParser.iNextSegmentPos )
       
   881 		startPos = prev;
       
   882 	else
       
   883 		endPos = prev;
       
   884 
       
   885 	// Ok, get the prefix and suffix parts
       
   886 	TPtrC8 prefix = iParser.iDataDes.Left(startPos);
       
   887 	TInt suffixLength = iParser.iDataDes.Length() - endPos;
       
   888 	TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
       
   889 
       
   890 	// Create the space
       
   891 	HBufC8* buf = HBufC8::NewL(startPos + suffixLength);
       
   892 	TPtr8 str = buf->Des();
       
   893 
       
   894 	// Form the new string
       
   895 	str.Append(prefix);
       
   896 	str.Append(suffix);
       
   897 
       
   898 	// Update string data
       
   899 	SetData(buf);
       
   900 
       
   901 	// Ensure parser is in correct position
       
   902 	iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
       
   903 	}
       
   904 
       
   905 /**
       
   906 	Updates internal data buffer with the new data. Creates a copy of the new data.
       
   907 						
       
   908 	@since			6.0
       
   909 	@param			aData	A descriptor with the new string.
       
   910 	@post			The internal data buffer now contains a copy of the new data and the 
       
   911 	parser is set to the new data.
       
   912 */
       
   913 void CDelimitedDataBase8::SetDataL(const TDesC8& aData)
       
   914     {
       
   915 	// Cleanup old data and set new
       
   916 	HBufC8* buf =  aData.AllocL();
       
   917 	SetData(buf);
       
   918 	}
       
   919 
       
   920 /**
       
   921 	Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. 
       
   922 	The parser is set to the new data.						
       
   923 	
       
   924 	@since			6.0
       
   925 	@param			aDataBuf	A pointer to a decriptor buffer with the new data.
       
   926 	@post			The internal data buffer now points to the new buffer and the parser 
       
   927 	is set to the data in the new buffer..
       
   928 */
       
   929 void CDelimitedDataBase8::SetData(HBufC8* aDataBuf)
       
   930 	{
       
   931 	delete iDataBuf;
       
   932 	iDataBuf = aDataBuf;
       
   933 	iParser.iDataDes.Set(*iDataBuf);
       
   934 	}
       
   935 
       
   936 //
       
   937 //
       
   938 // Implementation of TDelimitedParserBase16
       
   939 //
       
   940 //
       
   941 /**
       
   942 	Constructor.
       
   943 	
       
   944 	@since			6.0
       
   945  */
       
   946 EXPORT_C TDelimitedParserBase16::TDelimitedParserBase16()
       
   947 : iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
       
   948 	{
       
   949 	}
       
   950 
       
   951 /**
       
   952 	Resets the internal pointer position to the start or end or the descriptor depending 
       
   953 	on whether the decriptor is parsing mode.
       
   954 	
       
   955 	@warning		There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has 
       
   956 	not been correctly set.
       
   957  */
       
   958 EXPORT_C void TDelimitedParserBase16::Reset() const
       
   959 	{
       
   960 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   961 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   962 
       
   963 	iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
       
   964 	}
       
   965 /**
       
   966 	Retrieves the current segment and then parses the data to the next one.
       
   967 						
       
   968 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
   969 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
   970 	@since			6.0
       
   971 	@param			aSegment	This is an output argument that is set to the current segment.
       
   972 	@return			A error value of KErrNotFound if there is no current segment. The
       
   973 	value KErrNone if there is a current segment.
       
   974 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
   975 	@post			The current segment is updated to the next one.
       
   976  */
       
   977 EXPORT_C TInt TDelimitedParserBase16::GetNext(TPtrC16& aSegment) const
       
   978 	{
       
   979 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
   980 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
   981 
       
   982 	// Check that there is a segment
       
   983 	if( iNextSegmentPos == KErrNotFound )
       
   984 		{
       
   985 		// There is no segment
       
   986 		return KErrNotFound;
       
   987 		}
       
   988 	// There is one - set aSegment
       
   989 	aSegment.Set(iCurrentSegment);
       
   990 	// Parse the next segment
       
   991 	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
       
   992 	return KErrNone;
       
   993 	}
       
   994 	
       
   995 /**
       
   996 	Parses to the next segment.
       
   997 	
       
   998 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
   999 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1000 	@since			6.0
       
  1001 	@return			A error value of KErrNotFound if there is no current segment. The
       
  1002 	value KErrNone if there is a current segment.
       
  1003 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1004 	@post			The current segment is updated to the next one.
       
  1005  */
       
  1006 EXPORT_C TInt TDelimitedParserBase16::Inc() const
       
  1007 	{
       
  1008 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1009 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1010 
       
  1011 	// Check that there is a segment
       
  1012 	if( iNextSegmentPos == KErrNotFound )
       
  1013 		{
       
  1014 		// There is no segment
       
  1015 		return KErrNotFound;
       
  1016 		}
       
  1017 	// Parse the next segment
       
  1018 	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
       
  1019 	return KErrNone;
       
  1020 	}
       
  1021 	
       
  1022 /**
       
  1023 	Parses back to the previous segment.
       
  1024 	
       
  1025 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1026 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1027 	@since			6.0
       
  1028 	@return			A error value of KErrNotFound if the current segment is the initial
       
  1029 	segment. The value KErrNone if the data has been parsed to the previous segment.
       
  1030 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1031 	@post			If the parse was successful then the  current segment is updated
       
  1032 	to the previous one. Otherwise there is no change.
       
  1033  */
       
  1034 EXPORT_C TInt TDelimitedParserBase16::Dec() const
       
  1035 	{
       
  1036 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1037 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1038 
       
  1039 	// Find position of previous delimiter 
       
  1040 	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
       
  1041 
       
  1042 	// Get the previous segment
       
  1043 	if( FindPrevSegment(prev) == KErrNotFound )
       
  1044 		{
       
  1045 		// There is no previous segment - set to start of data
       
  1046 		return KErrNotFound;
       
  1047 		}
       
  1048 	// Update next segment position
       
  1049 	iNextSegmentPos = prev;
       
  1050 	return KErrNone;
       
  1051 	}
       
  1052 
       
  1053 /**
       
  1054 	Retrieves the current segment.
       
  1055 	
       
  1056 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1057 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1058 	@since			6.0
       
  1059 	@param			aSegment	This is an output argument that is set to the current segment.
       
  1060 	@return			A error value of KErrNotFound if there is no current segment. The
       
  1061 					value KErrNone if there is a current segment.
       
  1062 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1063  */
       
  1064 EXPORT_C TInt TDelimitedParserBase16::Peek(TPtrC16& aSegment) const
       
  1065 	{
       
  1066 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1067 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1068 
       
  1069 	// Check that there is a segment
       
  1070 	if( iNextSegmentPos == KErrNotFound )
       
  1071 		{
       
  1072 		// There is no segment
       
  1073 		return KErrNotFound;
       
  1074 		}
       
  1075 	// There is one - set aSegment
       
  1076 	aSegment.Set(iCurrentSegment);
       
  1077 	return KErrNone;
       
  1078 	}
       
  1079 	
       
  1080 /**
       
  1081 	Indicates whether the end of the data has been reached and there are no more segments to parse.
       
  1082 						
       
  1083 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1084 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1085 	@since			6.0
       
  1086 	@return			A boolean value of ETrue if the end of the data has been reached,
       
  1087 	or EFalse if there are more segements to parse.
       
  1088 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1089  */
       
  1090 EXPORT_C TBool TDelimitedParserBase16::Eos() const
       
  1091 	{
       
  1092 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1093 
       
  1094 	TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
       
  1095 	return eos;
       
  1096 	}
       
  1097 	
       
  1098 /**
       
  1099 	Checks for a delimiter at the front (left) of the data.
       
  1100 	
       
  1101 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1102 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1103 	@since			6.0
       
  1104 	@return			A boolean of value ETrue if there is a front delimiter, or EFalse
       
  1105 	if there is no front delimiter.
       
  1106 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1107  */
       
  1108 EXPORT_C TBool TDelimitedParserBase16::FrontDelimiter() const
       
  1109 	{
       
  1110 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1111 
       
  1112 	return (iDataDes.Locate(iDelimiter) == 0);
       
  1113 	}
       
  1114 
       
  1115 /**
       
  1116 	Checks for a delimiter at the back (right) of the data.
       
  1117 	
       
  1118 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1119 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1120 	@since			6.0
       
  1121 	@return			A boolean of value ETrue if there is a back delimiter, or EFalse
       
  1122 	if there is no back delimiter.
       
  1123 	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
       
  1124  */
       
  1125 EXPORT_C TBool TDelimitedParserBase16::BackDelimiter() const
       
  1126 	{
       
  1127 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1128 
       
  1129 	TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
       
  1130 	if( delimiterPos == KErrNotFound )
       
  1131 		return EFalse;
       
  1132 	return (delimiterPos == iDataDes.Length() - 1);
       
  1133 	}
       
  1134 	
       
  1135 /**
       
  1136 	Retrieves the descriptor reference with the data
       
  1137 	
       
  1138 	@since			6.0
       
  1139 	@return			A const descriptor reference with the data.
       
  1140  */
       
  1141 EXPORT_C const TDesC16& TDelimitedParserBase16::Des() const
       
  1142 	{
       
  1143 	return iDataDes;
       
  1144 	}
       
  1145 	
       
  1146 /**
       
  1147 	Gives the remainder of the data from (and including) the current segment. Any other segments that 
       
  1148 	have parsed through are not included.
       
  1149 						
       
  1150 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
       
  1151 	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1152 	@since			6.0
       
  1153 	@param			aRemainder	This is an output argument that is set to the remaining data.
       
  1154 	@return			An error value of KErrNotFound if there is no remaining data, or value of KErrNone 
       
  1155 	if there is remaining data.
       
  1156 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
  1157  */
       
  1158 EXPORT_C TInt TDelimitedParserBase16::Remainder(TPtrC16& aRemainder) const
       
  1159 	{
       
  1160 	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1161 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1162 
       
  1163 	// Check to see if there is a segment left
       
  1164 	if( iNextSegmentPos == KErrNotFound )
       
  1165 		{
       
  1166 		// There is no segment
       
  1167 		return KErrNotFound;
       
  1168 		}
       
  1169 	// Find the previous delimiter -> the start of the current segment
       
  1170 	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
       
  1171 
       
  1172 	// Need to see which direction the parsing is going to set the remainder
       
  1173 	switch(iMode)
       
  1174 		{
       
  1175 	case EDelimitedDataForward:
       
  1176 		{
       
  1177 		aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
       
  1178 		} break;
       
  1179 	case EDelimitedDataReverse:
       
  1180 		{
       
  1181 		aRemainder.Set(iDataDes.Left(prev));
       
  1182 		} break;
       
  1183 	default:
       
  1184 		// Bad mode!
       
  1185 		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
       
  1186 		break;
       
  1187 		}
       
  1188 	return KErrNone;
       
  1189 	}
       
  1190 	
       
  1191 /**
       
  1192 	This parses the data into segments from left to right.
       
  1193 	
       
  1194 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
  1195 	has not been set.
       
  1196 	@since			6.0
       
  1197 	@param			aData	A descriptor containing the data.
       
  1198 	@pre 			The delimiter must have been set.
       
  1199 	@post			The current segment is the leftmost segment and the direction of
       
  1200 	parsing is set from left to right (EDelimitedDataFroward).
       
  1201  */
       
  1202 EXPORT_C void TDelimitedParserBase16::Parse(const TDesC16& aData)
       
  1203 	{
       
  1204 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1205 
       
  1206 	// Initialise data for EForward direction
       
  1207 	iMode = EDelimitedDataForward;
       
  1208 	DoParse(aData);
       
  1209 	}
       
  1210 
       
  1211 /**
       
  1212 	This parses the data into segments from lright to left.
       
  1213 	
       
  1214 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
  1215 	has not been set.
       
  1216 	@since			6.0
       
  1217 	@param			aData	A descriptor containing the data.
       
  1218 	@pre 			The delimiter must have been set.
       
  1219 	@post			The current segment is the leftmost segment and the direction of
       
  1220 	parsing is set from right to left (EDelimitedDataReverse).
       
  1221  */
       
  1222 EXPORT_C void TDelimitedParserBase16::ParseReverse(const TDesC16& aData)
       
  1223 	{
       
  1224 	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1225 
       
  1226 	// Initialise data for EReverse direction
       
  1227 	iMode = EDelimitedDataReverse;
       
  1228 	DoParse(aData);
       
  1229 	}
       
  1230 
       
  1231 /**
       
  1232 	Sets the delimiting character.
       
  1233 	
       
  1234 	@since			6.0
       
  1235 	@param			aDelimiter	The delimiting character.
       
  1236 	@post			The delimiting character is set.
       
  1237 */
       
  1238 EXPORT_C void TDelimitedParserBase16::SetDelimiter(TChar aDelimiter)
       
  1239 	{
       
  1240 	iDelimiter = aDelimiter;
       
  1241 	}
       
  1242 
       
  1243 /**
       
  1244 	Initialises the parsing of the data.
       
  1245 	
       
  1246 	@since			6.0
       
  1247 	@param			aData	A descriptor reference with the data.
       
  1248 	@pre 			The delimiting character has been set.
       
  1249 	@post			The data descriptor is set to the input argument. The current segment 
       
  1250 	refers to the initial segment of the data.
       
  1251  */
       
  1252 void TDelimitedParserBase16::DoParse(const TDesC16& aData)
       
  1253 	{
       
  1254 	// Reset the segment information, then set the new Data - set pointer to NULL and length to zero
       
  1255 	iCurrentSegment.Set(NULL,0);
       
  1256 	iDataDes.Set(aData);
       
  1257 
       
  1258 	// Check that there is a string!
       
  1259 	if( iDataDes.Length() == 0 )
       
  1260 		{
       
  1261 		// No string - ensure functionality blocked for this descriptor
       
  1262 		iNextSegmentPos = KErrNotFound;
       
  1263 		return;
       
  1264 		}
       
  1265 	// Find the segment - search from initial start position
       
  1266 	iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
       
  1267 	}
       
  1268 
       
  1269 /**
       
  1270 	Finds the next segment from the given start position.
       
  1271 	
       
  1272 	@since			6.0
       
  1273 	@param			aStartPos	The position from where to start the search for the
       
  1274 	next segment.
       
  1275 	@return			The position of delimiter after the specified start position, or
       
  1276 	an error value of KErrNotFound if no more delimiters are found.
       
  1277  */
       
  1278 TInt TDelimitedParserBase16::FindNextSegment(TInt aStartPos) const
       
  1279 	{
       
  1280 	// Find position of next delimiter
       
  1281 	TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
       
  1282 
       
  1283 	if( next != KErrNotFound )
       
  1284 		{
       
  1285 		TInt startPos = next < aStartPos ? next : aStartPos;
       
  1286 		TInt endPos = next < aStartPos ? aStartPos : next;
       
  1287 		if( iDataDes[startPos] == iDelimiter )
       
  1288 			{
       
  1289 			// Move past delimiter
       
  1290 			++startPos;
       
  1291 			}
       
  1292 		TInt length = endPos - startPos;
       
  1293 		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
       
  1294 		}
       
  1295 	return next;
       
  1296 	}
       
  1297 	
       
  1298 /**
       
  1299 	Finds the previous segment from the given start position.
       
  1300 	
       
  1301 	@since			6.0
       
  1302 	@param			aStartPos	The position from where to start the search for the
       
  1303 	previous segment.
       
  1304 	@return			The position of delimiter before the specified start position, or
       
  1305 	an error value of KErrNotFound if no more delimiters are found.
       
  1306 */
       
  1307 TInt TDelimitedParserBase16::FindPrevSegment(TInt aStartPos) const
       
  1308 	{
       
  1309 	// Find position of previous delimiter 
       
  1310 	TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
       
  1311 	
       
  1312 	if( prev != KErrNotFound )
       
  1313 		{
       
  1314 		TInt startPos = prev < aStartPos ? prev : aStartPos;
       
  1315 		TInt endPos = prev < aStartPos ? aStartPos : prev;
       
  1316 		if( iDataDes[startPos] == iDelimiter )
       
  1317 			{
       
  1318 			// Move past delimiter
       
  1319 			++startPos;
       
  1320 			}
       
  1321 		TInt length = endPos - startPos;
       
  1322 		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
       
  1323 		}
       
  1324 	return prev;
       
  1325 	}
       
  1326 
       
  1327 //
       
  1328 //
       
  1329 // Implementation of CDelimitedDataBase16
       
  1330 //
       
  1331 //
       
  1332 
       
  1333 /**
       
  1334 	Destructor.
       
  1335 	
       
  1336 	@since			6.0
       
  1337  */
       
  1338 EXPORT_C CDelimitedDataBase16::~CDelimitedDataBase16()
       
  1339 	{
       
  1340 	delete iDataBuf;
       
  1341 	}
       
  1342 
       
  1343 /**
       
  1344 	Inserts the new segment in a position before the current parsed	segment. The new segment can be 
       
  1345 	made up of several segments and have delimiters at either extreme. The insert functionality will 
       
  1346 	ensure that there is always a delimiter at the front of the new segment. The parser is left in a 
       
  1347 	state where its current segment is the same one as before the insertion.
       
  1348 						
       
  1349 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
       
  1350 	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1351 	@since			6.0
       
  1352 	@param			aSegment	A descriptor with the new segment to be inserted.
       
  1353 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
  1354 	@post			The data will have been extended to include the new segment. The current segment 
       
  1355 	will remain as the one before the insertion.
       
  1356  */
       
  1357 EXPORT_C void CDelimitedDataBase16::InsertCurrentL(const TDesC16& aSegment)
       
  1358 	{
       
  1359 	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1360 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1361 
       
  1362 	DoInsertL(aSegment);
       
  1363 	}
       
  1364 	
       
  1365 /**
       
  1366 	Removes the current segment. After removing the segment, the parser's new current segment will be the 
       
  1367 	next segment. If the last segment is the one that is removed then the parser will be set to the end of 
       
  1368 	the data.
       
  1369 						
       
  1370 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and 
       
  1371 	a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
       
  1372 	@since			6.0
       
  1373 	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
       
  1374 	@post			The data will have been reduced to exclude the removed segment.	The current segment will 
       
  1375 	be set to what was the next segment. If the removed segment was the last segment, the parser is at the end 
       
  1376 	of the data.
       
  1377  */
       
  1378 EXPORT_C void CDelimitedDataBase16::RemoveCurrentL()
       
  1379 	{
       
  1380 	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
       
  1381 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1382 
       
  1383 	DoRemoveL();
       
  1384 	}
       
  1385 
       
  1386 /**
       
  1387 	Adds a new segment to the end of the data. The new segment can be made up of several segments and have  
       
  1388 	delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at 
       
  1389 	the front of the new segment. The data must re-parsed to ensure that the parser is valid.
       
  1390 						
       
  1391 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and a 
       
  1392 	KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure 
       
  1393 	that the parser is valid.
       
  1394 	@since			6.0
       
  1395 	@param			aSegment	A descriptor with the new segment to be inserted.
       
  1396 	@pre 			The delimiter must have been set.
       
  1397 	@post			The data will have been extended to include the new segment.
       
  1398  */
       
  1399 EXPORT_C void CDelimitedDataBase16::PushBackL(const TDesC16& aSegment)
       
  1400 	{
       
  1401 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1402 
       
  1403 	// Parse the string in reverse direction - sets last segment as current
       
  1404 	iParser.ParseReverse(*iDataBuf);
       
  1405 
       
  1406 	// Insert the segment
       
  1407 	DoInsertL(aSegment);
       
  1408 
       
  1409 	// Make sure that a re-parse is required
       
  1410 	iParser.iMode = EDelimitedDataNotParsed;
       
  1411 	}
       
  1412 
       
  1413 /**
       
  1414 	Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
       
  1415 						
       
  1416 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
       
  1417 	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required 
       
  1418 	to ensure that the parser is valid.
       
  1419 	@since			6.0
       
  1420 	@pre 			The delimiter must have been set.
       
  1421 	@post			The data will have been reduced to exclude the last segment.
       
  1422  */
       
  1423 EXPORT_C void CDelimitedDataBase16::PopBackL()
       
  1424 	{
       
  1425 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1426 
       
  1427 	// Parse the string in reverse direction - sets last segment as current
       
  1428 	iParser.ParseReverse(*iDataBuf);
       
  1429 
       
  1430 	// Remove the current segment
       
  1431 	DoRemoveL();
       
  1432 
       
  1433 	// Make sure that a re-parse is required
       
  1434 	iParser.iMode = EDelimitedDataNotParsed;
       
  1435 	}
       
  1436 
       
  1437 
       
  1438 /**
       
  1439 	Adds a new segment to the front of the data. The new segment can be made up of several segments and have  
       
  1440 	delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at 
       
  1441 	the front of the new segment. The data must re-parsed to ensure that the parser is valid.
       
  1442 							
       
  1443 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and 
       
  1444 	a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure 
       
  1445 	that the parser is valid.
       
  1446 	@since			6.0
       
  1447 	@param			aSegment	A descriptor with the new segment to be inserted.
       
  1448 	@pre 			The delimiter must have been set.
       
  1449 	@post			The data will have been extended to include the new segment.
       
  1450  */
       
  1451 EXPORT_C void CDelimitedDataBase16::PushFrontL(const TDesC16& aSegment)
       
  1452 	{
       
  1453 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1454 
       
  1455 	// Parse the string in forward direction - sets first segment as current
       
  1456 	iParser.Parse(*iDataBuf);
       
  1457 
       
  1458 	// Insert the segment
       
  1459 	DoInsertL(aSegment);
       
  1460 
       
  1461 	// Make sure that a re-parse is required
       
  1462 	iParser.iMode = EDelimitedDataNotParsed;
       
  1463 	}
       
  1464 
       
  1465 /**
       
  1466 	Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
       
  1467 						
       
  1468 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has	not been 
       
  1469 	parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse 
       
  1470 	is required to ensure that the parser is valid.
       
  1471 	@since			6.0
       
  1472 	@pre 			The delimiter must have been set.
       
  1473 	@post			The data will have been reduced to exclude the last segment.
       
  1474  */
       
  1475 EXPORT_C void CDelimitedDataBase16::PopFrontL()
       
  1476 	{
       
  1477 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1478 
       
  1479 	// Parse the string in forward direction - sets first segment as current
       
  1480 	iParser.Parse(*iDataBuf);
       
  1481 
       
  1482 	// Remove the current segment
       
  1483 	DoRemoveL();
       
  1484 
       
  1485 	// Make sure that a re-parse is required
       
  1486 	iParser.iMode = EDelimitedDataNotParsed;
       
  1487 	}
       
  1488 
       
  1489 
       
  1490 /**
       
  1491 	Removes the front delimiter (if exists) from the data.
       
  1492 	
       
  1493 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has
       
  1494 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
  1495 	been set. A re-parse is required to ensure that the parser is valid.
       
  1496 	@since			6.0
       
  1497 	@pre 			The delimiter must have been set.
       
  1498 	@post			The data might have been reduced to exclude the front delimiter.
       
  1499  */
       
  1500 EXPORT_C void CDelimitedDataBase16::TrimFrontDelimiterL()
       
  1501 	{
       
  1502 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1503 
       
  1504 	// Search for delimiter
       
  1505 	if( iParser.FrontDelimiter() )
       
  1506 		{
       
  1507 		// Remove front delimiter and update member data
       
  1508 		SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
       
  1509 		}
       
  1510 	// Make sure that a re-parse is required
       
  1511 	iParser.iMode = EDelimitedDataNotParsed;
       
  1512 	}
       
  1513 
       
  1514 /**
       
  1515 	Adds a delimiter to the front of the data (if it doesn't exist).
       
  1516 
       
  1517 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not
       
  1518 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. 
       
  1519 	A re-parse is required to ensure that the parser is valid.
       
  1520 	@since			6.0
       
  1521 	@pre 			The delimiter must have been set.
       
  1522 	@post			The data might have been extended to include a front delimiter.
       
  1523  */
       
  1524 EXPORT_C void CDelimitedDataBase16::AddFrontDelimiterL()
       
  1525 	{
       
  1526 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1527 
       
  1528 	if( !iParser.FrontDelimiter() )
       
  1529 		{
       
  1530 		// Create a new buffer of correct size
       
  1531 		HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
       
  1532 		TPtr16 str = buf->Des();
       
  1533 
       
  1534 		// Append a delimiter, then append the current string
       
  1535 		str.Append(iParser.iDelimiter);
       
  1536 		str.Append(iParser.iDataDes);
       
  1537 
       
  1538 		// Set buffer to this new string
       
  1539 		SetData(buf);
       
  1540 		}
       
  1541 	// Make sure that a re-parse is required
       
  1542 	iParser.iMode = EDelimitedDataNotParsed;
       
  1543 	}
       
  1544 
       
  1545 /**
       
  1546 	Removes the back delimiter (if exists) from the data.
       
  1547 
       
  1548 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has
       
  1549 	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
       
  1550 	been set. A re-parse is required to ensure that the parser is valid.
       
  1551 	@since			6.0
       
  1552 	@pre 			The delimiter must have been set.
       
  1553 	@post			The data might have been reduced to exclude the front delimiter.
       
  1554  */
       
  1555 EXPORT_C void CDelimitedDataBase16::TrimBackDelimiterL()
       
  1556 	{
       
  1557 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1558 
       
  1559 	// Search for delimiter
       
  1560 	if( iParser.BackDelimiter() )
       
  1561 		{
       
  1562 		// Remove back delimiter and update member data
       
  1563 		SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
       
  1564 		}
       
  1565 	// Make sure that a re-parse is required
       
  1566 	iParser.iMode = EDelimitedDataNotParsed;
       
  1567 	}
       
  1568 
       
  1569 /**
       
  1570 	Adds a delimiter to the back of the data (if it doesn't exist).
       
  1571 
       
  1572 	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
       
  1573 	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. 
       
  1574 	A re-parse is required to ensure that the parser is valid.
       
  1575 	@since			6.0
       
  1576 	@pre 			The delimiter must have been set.
       
  1577 	@post			The data might have been extended to include a front delimiter.
       
  1578  */
       
  1579 EXPORT_C void CDelimitedDataBase16::AddBackDelimiterL()
       
  1580 	{
       
  1581 	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
       
  1582 
       
  1583 	if( !iParser.BackDelimiter() )
       
  1584 		{
       
  1585 		// Create a new buffer of correct size
       
  1586 		HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
       
  1587 		TPtr16 str = buf->Des();
       
  1588 
       
  1589 		// Append the current string, then append a delimiter
       
  1590 		str.Append(iParser.iDataDes);
       
  1591 		str.Append(iParser.iDelimiter);
       
  1592 
       
  1593 		// Set buffer to this new string
       
  1594 		SetData(buf);
       
  1595 		}
       
  1596 	// Make sure that a re-parse is required
       
  1597 	iParser.iMode = EDelimitedDataNotParsed;
       
  1598 	}
       
  1599 	
       
  1600 /**
       
  1601 	This parses the data into segments from left to right.
       
  1602 
       
  1603 	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
       
  1604 	has not been set.
       
  1605 	@since			6.0
       
  1606 	@pre 			The delimiter must have been set.
       
  1607 	@post			The current segment is the leftmost segment and the direction of
       
  1608 	parsing is set from left to right (EDelimitedDataFroward).
       
  1609  */
       
  1610 EXPORT_C void CDelimitedDataBase16::Parse()
       
  1611 	{
       
  1612 	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
       
  1613 	iParser.Parse(*iDataBuf);
       
  1614 	}
       
  1615 
       
  1616 /**
       
  1617 	This parses the string into segments from right to left.
       
  1618 	
       
  1619 	@since			6.0
       
  1620 	@pre 			The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
       
  1621 	the delimiter has not been initialized.
       
  1622 	@post			The current segment is the leftmost segment and the direction of parsing is right to left.
       
  1623  */
       
  1624 EXPORT_C void CDelimitedDataBase16::ParseReverse()
       
  1625 	{
       
  1626 	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
       
  1627 	iParser.ParseReverse(*iDataBuf);
       
  1628 	}
       
  1629 	
       
  1630 /**
       
  1631 	Retrieves a const reference to the delimited data parser.
       
  1632 
       
  1633 	@since			6.0
       
  1634 	@return			A const reference to the delimited data parser.
       
  1635  */
       
  1636 EXPORT_C const TDelimitedParserBase16& CDelimitedDataBase16::Parser() const
       
  1637 	{
       
  1638 	return iParser;
       
  1639 	}
       
  1640 	
       
  1641 /**
       
  1642 	Sets the delimiting character.
       
  1643 	
       
  1644 	@since			6.0
       
  1645 	@param			aDelimiter	The delimiting character.
       
  1646 	@post			The delimiting character is updated.
       
  1647  */
       
  1648 EXPORT_C void CDelimitedDataBase16::SetDelimiter(TChar aDelimiter)
       
  1649 	{
       
  1650 	iParser.SetDelimiter(aDelimiter);
       
  1651 	}
       
  1652 
       
  1653 /**
       
  1654 	Constructor. First phase of two-phase construction method. Does non-allocating construction.
       
  1655 	
       
  1656 	@since			6.0
       
  1657  */
       
  1658 EXPORT_C CDelimitedDataBase16::CDelimitedDataBase16()
       
  1659 	{
       
  1660 	}
       
  1661 	
       
  1662 /**
       
  1663 	Second phase of two-phase construction method. Does any	allocations required to fully construct 
       
  1664 	the object.
       
  1665 						
       
  1666 	@since			6.0
       
  1667 	@param			aData	A descriptor with the initial string.
       
  1668 	@pre 			First phase of construction is complete.
       
  1669 	@post			The object is fully constructed.
       
  1670  */
       
  1671 EXPORT_C void CDelimitedDataBase16::ConstructL(const TDesC16& aData)
       
  1672 	{
       
  1673 	// Create copy of string and set descriptor in the parser
       
  1674 	SetDataL(aData);
       
  1675 	}
       
  1676 	
       
  1677 /**
       
  1678 	Inserts the new segment in a position before the current segment. The new segment can be made up of 
       
  1679 	several segments and have delimiters at either extreme. The insert functionality will ensure that 
       
  1680 	there is always a delimiter at the front of the	new segment. The parser will be left in a state where 
       
  1681 	its current segment is the same one as before the insertion.
       
  1682 						
       
  1683 	@since			6.0
       
  1684 	@param			aSegment	The descriptor with the segment to be inserted.
       
  1685 	@pre 			The string must have been parsed.
       
  1686 	@post			The string will have been extended to include the new segment. The current segment will
       
  1687 	remain as the one before the insertion.
       
  1688  */
       
  1689 void CDelimitedDataBase16::DoInsertL(const TDesC16& aSegment)
       
  1690 	{
       
  1691 	TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
       
  1692 	TPtrC16 prefix = iParser.iDataDes.Left(prevPos);
       
  1693 
       
  1694 	TInt suffixLength = iParser.iDataDes.Length() - prevPos;
       
  1695 	TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
       
  1696 	if( suffixLength && suffix[0] == iParser.iDelimiter )
       
  1697 		{
       
  1698 		// Remove front delimiter on suffix
       
  1699 		suffix.Set(suffix.Right(--suffixLength));
       
  1700 		}	
       
  1701 
       
  1702 	// Check for delimiters...
       
  1703 	TPtrC16 segment = aSegment;
       
  1704 	TInt segmentLength = segment.Length();
       
  1705 	// Check the last character in segment
       
  1706 	TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
       
  1707 	if( segmentBackDelimiter )
       
  1708 		{
       
  1709 		// Remove back delimiter from the segment
       
  1710 		segment.Set(segment.Left(--segmentLength));
       
  1711 		}
       
  1712 	// Check the first character in segment...
       
  1713 	if( segmentLength && segment[0] == iParser.iDelimiter )
       
  1714 		{
       
  1715 		// Remove front delimiter from the segment
       
  1716 		segment.Set(segment.Right(--segmentLength));
       
  1717 		}
       
  1718 
       
  1719 	// Check if a back delimiter is needed - NOTE always add a front delimiter
       
  1720 	TInt extra = 1;
       
  1721 	TBool needBackDelimiter = EFalse;
       
  1722 	if( suffix.Length() || segmentBackDelimiter )
       
  1723 		{
       
  1724 		++extra;
       
  1725 		needBackDelimiter = ETrue;
       
  1726 		}
       
  1727 	// Create space for new string
       
  1728 	HBufC16* buf = HBufC16::NewL(prevPos + segmentLength + suffixLength + extra);
       
  1729 	TPtr16 str = buf->Des();
       
  1730 
       
  1731 	// Form the new string
       
  1732 	str.Append(prefix);
       
  1733 	str.Append(iParser.iDelimiter);
       
  1734 	str.Append(segment);
       
  1735 	if( needBackDelimiter )
       
  1736 		str.Append(iParser.iDelimiter);
       
  1737 	str.Append(suffix);
       
  1738 
       
  1739 	// Update string data
       
  1740 	SetData(buf);
       
  1741 
       
  1742 	// Check to see if the internal parser object (iParser) has been parsed
       
  1743 	// (can tell if it has if the data pointer in iCurrentSegment is not NULL)
       
  1744 	// If so update iCurrentSegment to ensure that iParser remains valid
       
  1745 	if( iParser.iCurrentSegment.Ptr() )
       
  1746 		{
       
  1747 		// Ensure parser is in correct position and current segment is correct
       
  1748 		iParser.iNextSegmentPos = prevPos;
       
  1749 		if( iParser.iMode == EDelimitedDataForward )
       
  1750 			{
       
  1751 			// Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
       
  1752 			iParser.iNextSegmentPos += segmentLength + 1;
       
  1753 			}
       
  1754 		// Get the next segment
       
  1755 		iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
       
  1756 		}
       
  1757 	}
       
  1758 
       
  1759 /**
       
  1760 	Removes the current segment. After removing the segment, the parser's new current segment will be the 
       
  1761 	next segment. If the last segment is the one that is removed then the parser will be set to the end of 
       
  1762 	the data.
       
  1763 						
       
  1764 	@since			6.0
       
  1765 	@pre 			The data must have been parsed.
       
  1766 	@post			The data will have been reduced to exclude the removed data. The current segment 
       
  1767 	is set to what was the next segment. If the removed segment was	the last segment, the parser is 
       
  1768 	at the end of the data.
       
  1769  */
       
  1770 void CDelimitedDataBase16::DoRemoveL()
       
  1771 	{
       
  1772 	// Check if there is anything to remove
       
  1773 	if( iParser.iDataDes.Length() == 0 )
       
  1774 		{
       
  1775 		return;
       
  1776 		}
       
  1777 	// Find the previous delimiter
       
  1778 	TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
       
  1779 
       
  1780 	// Set up the start and end position of current segment
       
  1781 	TInt endPos = iParser.iNextSegmentPos;
       
  1782 	TInt startPos = iParser.iNextSegmentPos;
       
  1783 	if( prev < iParser.iNextSegmentPos )
       
  1784 		startPos = prev;
       
  1785 	else
       
  1786 		endPos = prev;
       
  1787 
       
  1788 	// Ok, get the prefix and suffix parts
       
  1789 	TPtrC16 prefix = iParser.iDataDes.Left(startPos);
       
  1790 	TInt suffixLength = iParser.iDataDes.Length() - endPos;
       
  1791 	TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
       
  1792 
       
  1793 	// Create the space
       
  1794 	HBufC16* buf = HBufC16::NewL(startPos + suffixLength);
       
  1795 	TPtr16 str = buf->Des();
       
  1796 
       
  1797 	// Form the new string
       
  1798 	str.Append(prefix);
       
  1799 	str.Append(suffix);
       
  1800 
       
  1801 	// Update string data
       
  1802 	SetData(buf);
       
  1803 
       
  1804 	// Ensure parser is in correct position
       
  1805 	iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
       
  1806 	}
       
  1807 
       
  1808 /**
       
  1809 	Updates internal data buffer with the new data. Creates a copy of the new data.
       
  1810 						
       
  1811 	@since			6.0
       
  1812 	@param			aData	A descriptor with the new string.
       
  1813 	@post			The internal data buffer now contains a copy of the new data and the
       
  1814 	parser is set to the new data.
       
  1815  */
       
  1816 void CDelimitedDataBase16::SetDataL(const TDesC16& aData)
       
  1817 	{
       
  1818 	// Cleanup old data and set new
       
  1819 	HBufC16* buf =  aData.AllocL();
       
  1820 	SetData(buf);
       
  1821 	}
       
  1822 	
       
  1823 /**
       
  1824 	Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. The 
       
  1825 	parser is set to the new data.
       
  1826 						
       
  1827 	@since			6.0
       
  1828 	@param			aDataBuf	A pointer to a decriptor buffer with the new data.
       
  1829 	@post			The internal data buffer now points to the new buffer and the parser
       
  1830 	is set to the data in the new buffer..
       
  1831  */
       
  1832 void CDelimitedDataBase16::SetData(HBufC16* aDataBuf)
       
  1833 	{
       
  1834 	delete iDataBuf;
       
  1835 	iDataBuf = aDataBuf;
       
  1836 	iParser.iDataDes.Set(*iDataBuf);
       
  1837 	}
       
  1838 
       
  1839 //
       
  1840 //
       
  1841 // Implementation of LOCAL functions
       
  1842 //
       
  1843 //
       
  1844 
       
  1845 /**
       
  1846 	Finds the position of the next delimiter in the data.
       
  1847 	
       
  1848 	@since			6.0
       
  1849 	@param			aData		A descriptor with the delimited data.
       
  1850 	@param			aStartPos	The position from where to start the search for the delimiter.
       
  1851 	@param			aDelimiter	The delimiting character.
       
  1852 	@param			aMode		The parsing mode.
       
  1853 	@return			The position of delimiter after the specified start position, or 
       
  1854 	an error value of KErrNotFound if no more delimiters are found.	
       
  1855 	@pre			None
       
  1856 	@post			Unspecified
       
  1857  */
       
  1858 template<class TDesCType>
       
  1859 TInt NextDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
       
  1860 	{
       
  1861 	if( aStartPos == KErrNotFound )
       
  1862 		{
       
  1863 		// Have got to the end - initialise the iterator
       
  1864 		return InitialDelimiterPosition(aData, aMode);
       
  1865 		}
       
  1866 	TInt next = KErrNotFound;
       
  1867 	switch( aMode )
       
  1868 		{
       
  1869 	case EDelimitedDataForward:
       
  1870 		{
       
  1871 		// Search parsed string for next delimiter
       
  1872 		next = LeftDelimiterPosition(aData, aStartPos, aDelimiter);
       
  1873 		} break;
       
  1874 	case EDelimitedDataReverse:
       
  1875 		{
       
  1876 		// Search parsed string for next delimiter
       
  1877 		next = RightDelimiterPosition(aData, aStartPos, aDelimiter);
       
  1878 		} break;
       
  1879 	default:
       
  1880 		// Bad mode!
       
  1881 		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
       
  1882 		break;
       
  1883 		}
       
  1884 	return next;
       
  1885 	}
       
  1886 
       
  1887 
       
  1888 /**
       
  1889 	Finds the position of the previous delimiter in the data from the given start position.
       
  1890 	
       
  1891 	@since			6.0
       
  1892 	@param			aData		A descriptor with the delimited data.
       
  1893 	@param			aStartPos	The position from where to start the search for the delimiter.
       
  1894 	@param			aDelimiter	The delimiting character.
       
  1895 	@param			aMode		The parsing mode.
       
  1896 	@return			The position of delimiter before the specified start position, or 
       
  1897 	an error value of KErrNotFound if no more delimiters are found.	
       
  1898 	@pre			None
       
  1899 	@post			Unspecified
       
  1900  */
       
  1901 template<class TDesCType>
       
  1902 TInt PrevDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
       
  1903 	{
       
  1904 	// Switch modes, then find the next delimiter, switch back
       
  1905 	TDelimitedDataParseMode mode = aMode == EDelimitedDataForward ? EDelimitedDataReverse : EDelimitedDataForward;
       
  1906 	return NextDelimiterPosition(aData, aStartPos, aDelimiter, mode);
       
  1907 	}
       
  1908 
       
  1909 /**
       
  1910 	Finds the position of the delimiter to the right of the given start position.
       
  1911 	
       
  1912 	@since			6.0
       
  1913 	@param			aData		A descriptor with the delimited data.
       
  1914 	@param			aStartPos	The position from where to start the search for the delimiter.
       
  1915 	@param			aDelimiter	The delimiting character.
       
  1916 	@return			The position of delimiter to the right of the specified start position, or 
       
  1917 	an error value of KErrNotFound if no more delimiters are found.	
       
  1918 	@pre			None
       
  1919 	@post			Unspecified
       
  1920  */
       
  1921 template<class TDesCType>
       
  1922 TInt RightDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
       
  1923 	{
       
  1924 	// Find position of right-most delimiter in the descriptor data to left of aStartPos
       
  1925 	if( aStartPos == 0 )
       
  1926 		{
       
  1927 		// There is no data
       
  1928 		return KErrNotFound;
       
  1929 		}
       
  1930 	TInt rightDelimiterPos = aData.Left(aStartPos).LocateReverse(aDelimiter);
       
  1931 
       
  1932 	// See if a delimiter was found
       
  1933 	if( rightDelimiterPos == KErrNotFound )
       
  1934 		{
       
  1935 		// No - start of string delimits
       
  1936 		rightDelimiterPos = 0;
       
  1937 		}
       
  1938 	return rightDelimiterPos;
       
  1939 	}
       
  1940 
       
  1941 /**
       
  1942 	Finds the position of the delimiter to the left of the given start position.
       
  1943 	
       
  1944 	@since			6.0
       
  1945 	@param			aData		A descriptor with the delimited data.
       
  1946 	@param			aStartPos	The position from where to start the search for the delimiter.
       
  1947 	@param			aDelimiter	The delimiting character.
       
  1948 	@return			The position of delimiter to the left of the specified start position, or 
       
  1949 	an error value of KErrNotFound if no more delimiters are found.	
       
  1950 	@pre			None
       
  1951 	@post			Unspecified
       
  1952  */
       
  1953 template<class TDesCType>
       
  1954 TInt LeftDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
       
  1955 	{
       
  1956 	// Find position of left-most delimiter in the descriptor data to right of aStartPos
       
  1957 	const TInt length = aData.Length();
       
  1958 	TInt rightLength = length - aStartPos;
       
  1959 	if( rightLength == 0 )
       
  1960 		{
       
  1961 		// There is no data
       
  1962 		return KErrNotFound;
       
  1963 		}
       
  1964 	// Ok there is some string to search - remove delimiter
       
  1965 	--rightLength;
       
  1966 	TInt leftDelimiterPos = aData.Right(rightLength).Locate(aDelimiter);
       
  1967 
       
  1968 	// See if a delimiter was found
       
  1969 	if( leftDelimiterPos == KErrNotFound )
       
  1970 		{
       
  1971 		// No - end of string delimits
       
  1972 		leftDelimiterPos = length;
       
  1973 		}
       
  1974 	else
       
  1975 		{
       
  1976 		// Offset the delimiter found - include delimiter that was removed
       
  1977 		leftDelimiterPos += aStartPos + 1;
       
  1978 		}
       
  1979 	return leftDelimiterPos;
       
  1980 	}
       
  1981 
       
  1982 /**
       
  1983 	Retrieves the initial position for searching delimited data for a given parsing mode.
       
  1984 	
       
  1985 	@since			6.0
       
  1986 	@param			aData		A descriptor with the delimited data.
       
  1987 	@param			aMode		The parsing mode.
       
  1988 	@return			The initial position for parsing the data.
       
  1989 	@pre			None
       
  1990 	@post			Unspecified
       
  1991  */
       
  1992 template<class TDesCType>
       
  1993 TInt InitialDelimiterPosition(const TDesCType& aData, TDelimitedDataParseMode aMode)
       
  1994 //
       
  1995 // Initialises iNextSegmentPos
       
  1996 	{
       
  1997 	TInt initPos = KErrNotFound;
       
  1998 	switch( aMode )
       
  1999 		{
       
  2000 	case EDelimitedDataForward:
       
  2001 		{
       
  2002 		// Search parsed string for next delimiter
       
  2003 		initPos = 0;
       
  2004 		} break;
       
  2005 	case EDelimitedDataReverse:
       
  2006 		{
       
  2007 		// Search parsed string for next delimiter
       
  2008 		initPos = aData.Length();
       
  2009 		} break;
       
  2010 	default:
       
  2011 		// Bad mode!
       
  2012 		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
       
  2013 		break;
       
  2014 		}
       
  2015 	return initPos;
       
  2016 	}
       
  2017