genericservices/httputils/DelimitedParser/DelimitedParser.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/httputils/DelimitedParser/DelimitedParser.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,2017 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <delimitedparser8.h>
+#include <delimitedparser16.h>
+#include "DelimitedParserInternal.h"
+#include <uriutilscommon.h>
+
+// Panic category
+//
+_LIT(KDelimitedParserPanicCategory,"DELIM-PARSER"); 
+
+//
+//
+// Implementation of TDelimitedParserBase8
+//
+//
+
+/**
+	Constructor.
+	
+	@since			6.0
+*/
+EXPORT_C TDelimitedParserBase8::TDelimitedParserBase8()
+: iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
+	{
+	}
+
+/**
+	Resets the internal pointer position to the start or end or the descriptor
+	depending on whether the decriptor is parsing mode.
+	
+	@warning		There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has 
+	not been correctly set.
+ */
+EXPORT_C void TDelimitedParserBase8::Reset() const
+	{
+	iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
+	}
+
+/**
+	Retrieves the current segment and then parses the data to the next one.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@param			aSegment	This is an output argument that is set to the current segment.
+	@return			A error value of KErrNotFound if there is no current segment. The 
+	value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+	@post			The current segment is updated to the next one.
+*/
+EXPORT_C TInt TDelimitedParserBase8::GetNext(TPtrC8& aSegment) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// There is one - set aSegment
+	aSegment.Set(iCurrentSegment);
+	// Parse the next segment
+	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
+	return KErrNone;
+	}
+
+/**
+	Parses to the next segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@return			A error value of KErrNotFound if there is no current segment. The 
+	value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+	@post			The current segment is updated to the next one.
+ */	
+EXPORT_C TInt TDelimitedParserBase8::Inc() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// Parse the next segment
+	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
+	return KErrNone;
+	}
+
+/**
+	Parses back to the previous segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@return			A error value of KErrNotFound if the current segment is the initial 
+	segment. The value KErrNone if the data has been parsed to the previous segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+	@post			If the parse was successful then the  current segment is updated 
+	to the previous one. Otherwise there is no change.
+*/
+EXPORT_C TInt TDelimitedParserBase8::Dec() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Find position of previous delimiter 
+	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
+
+	// Get the previous segment
+	if( FindPrevSegment(prev) == KErrNotFound )
+		{
+		// There is no previous segment - set to start of data
+		return KErrNotFound;
+		}
+	// Update next segment position
+	iNextSegmentPos = prev;
+	return KErrNone;
+	}
+
+/**
+	Retrieves the current segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@param			aSegment	This is an output argument that is set to the current segment.
+	@return			A error value of KErrNotFound if there is no current segment. The 
+	value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+*/
+EXPORT_C TInt TDelimitedParserBase8::Peek(TPtrC8& aSegment) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// There is one - set aSegment
+	aSegment.Set(iCurrentSegment);
+	return KErrNone;
+	}
+
+/**
+	Indicates whether the end of the data has been reached and there are no more segments 
+	to parse.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@return			A boolean value of ETrue if the end of the data has been reached,
+	or EFalse if there are more segements to parse.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+*/
+EXPORT_C TBool TDelimitedParserBase8::Eos() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+
+	TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
+	return eos;
+	}
+
+/**
+	Checks for a delimiter at the front (left) of the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A boolean of value ETrue if there is a front delimiter, or EFalse 
+	if there is no front delimiter.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+*/
+EXPORT_C TBool TDelimitedParserBase8::FrontDelimiter() const
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	return (iDataDes.Locate(iDelimiter) == 0);
+	}
+
+/**
+	Checks for a delimiter at the back (right) of the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@return			A boolean of value ETrue if there is a back delimiter, or EFalse 
+	if there is no back delimiter.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse(). 
+*/
+EXPORT_C TBool TDelimitedParserBase8::BackDelimiter() const
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
+	if( delimiterPos == KErrNotFound )
+		return EFalse;
+	return (delimiterPos == iDataDes.Length() - 1);
+	}
+
+/**
+	Retrieves the descriptor reference with the data
+	
+	@since			6.0
+	@return			A const descriptor reference with the data.
+*/
+EXPORT_C const TDesC8& TDelimitedParserBase8::Des() const
+	{
+	return iDataDes;
+	}
+
+/**
+	Gives the remainder of the data from (and including) the current segment. Any other segments 
+	that have parsed through are not included.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@param			aRemainder	This is an output argument that is set to the remaining data.
+	@return			An error value of KErrNotFound if there is no remaining data, or 
+	value of KErrNone if there is remaining data.
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TInt TDelimitedParserBase8::Remainder(TPtrC8& aRemainder) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check to see if there is a segment left
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// Find the previous delimiter -> the start of the current segment
+	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
+
+	// Need to see which direction the parsing is going to set the remainder
+	switch(iMode)
+		{
+	case EDelimitedDataForward:
+		{
+		aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
+		} break;
+	case EDelimitedDataReverse:
+		{
+		aRemainder.Set(iDataDes.Left(prev));
+		} break;
+	default:
+		// Bad mode!
+		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
+		break;
+		}
+	return KErrNone;
+	}
+
+/**
+	This parses the data into segments from left to right.
+
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@param			aData	A descriptor containing the data.
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of 
+	parsing is set from left to right (EDelimitedDataFroward).
+ */
+EXPORT_C void TDelimitedParserBase8::Parse(const TDesC8& aData)
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Initialise data for EForward direction
+	iMode = EDelimitedDataForward;
+	DoParse(aData);
+	}
+
+/**
+	This parses the data into segments from lright to left.
+
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@param			aData	A descriptor containing the data.
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of 
+	parsing is set from right to left (EDelimitedDataReverse).
+ */
+EXPORT_C void TDelimitedParserBase8::ParseReverse(const TDesC8& aData)
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Initialise data for EReverse direction
+	iMode = EDelimitedDataReverse;
+	DoParse(aData);
+	}
+
+/**
+	Sets the delimiting character.
+	
+	@since			6.0
+	@param			aDelimiter	The delimiting character.
+	@post			The delimiting character is set.
+*/
+EXPORT_C void TDelimitedParserBase8::SetDelimiter(TChar aDelimiter)
+	{
+	iDelimiter = aDelimiter;
+	}
+
+/**
+	Initialises the parsing of the data.
+	
+	@since			6.0
+	@param			aData	A descriptor reference with the data.
+	@pre 			The delimiting character has been set.
+	@post			The data descriptor is set to the input argument. The current 
+	segment refers to the initial segment of the data.
+*/
+void TDelimitedParserBase8::DoParse(const TDesC8& aData)
+	{
+	// Reset the segment information, then set the new Data - set pointer to NULL and length to zero
+	iCurrentSegment.Set(NULL,0);
+	iDataDes.Set(aData);
+
+	// Check that there is a string!
+	if( iDataDes.Length() == 0 )
+		{
+		// No string - ensure functionality blocked for this descriptor
+		iNextSegmentPos = KErrNotFound;
+		return;
+		}
+	// Find the segment - search from initial start position
+	iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
+	}
+
+/**
+	Finds the next segment from the given start position.
+	
+	@since			6.0
+	@param			aStartPos	The position from where to start the search for the
+	next segment.
+	@return			The position of delimiter after the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.
+*/
+TInt TDelimitedParserBase8::FindNextSegment(TInt aStartPos) const
+	{
+	// Find position of next delimiter
+	TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
+
+	if( next != KErrNotFound )
+		{
+		TInt startPos = next < aStartPos ? next : aStartPos;
+		TInt endPos = next < aStartPos ? aStartPos : next;
+		if( iDataDes[startPos] == iDelimiter )
+			{
+			// Move past delimiter
+			++startPos;
+			}
+		TInt length = endPos - startPos;
+		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
+		}
+	return next;
+	}
+
+/**
+	Finds the previous segment from the given start position.
+	
+	@since			6.0
+	@param			aStartPos	The position from where to start the search for the
+					previous segment.
+	@return			The position of delimiter before the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.
+*/
+TInt TDelimitedParserBase8::FindPrevSegment(TInt aStartPos) const
+	{
+	// Find position of previous delimiter 
+	TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
+	
+	if( prev != KErrNotFound )
+		{
+		TInt startPos = prev < aStartPos ? prev : aStartPos;
+		TInt endPos = prev < aStartPos ? aStartPos : prev;
+		if( iDataDes[startPos] == iDelimiter )
+			{
+			// Move past delimiter
+			++startPos;
+			}
+		TInt length = endPos - startPos;
+		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
+		}
+	return prev;
+	}
+
+//
+//
+// Implementation of CDelimitedDataBase8
+//
+//
+
+/**
+	Destructor.
+	
+	@since			6.0
+*/
+EXPORT_C CDelimitedDataBase8::~CDelimitedDataBase8()
+	{
+	delete iDataBuf;
+	}
+
+/**
+	Inserts the new segment in a position before the current parsed	segment. The new 
+	segment can be made up of several segments and have delimiters at either extreme. 
+	The insert functionality will ensure that there is always a delimiter at the front 
+	of the new segment. The parser is left in a state where its current segment is the 
+	same one as before the insertion.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been 
+	parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+	@post			The data will have been extended to include the new segment. The 
+	current segment will remain as the one before the insertion.
+*/
+EXPORT_C void CDelimitedDataBase8::InsertCurrentL(const TDesC8& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	DoInsertL(aSegment);
+	}
+
+/**
+	Removes the current segment. After removing the segment, the parser's new current segment 
+	will be the next segment. If the last segment is the one that is removed then the parser 
+	will be set to the end of the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set.
+	@since			6.0
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+	@post			The data will have been reduced to exclude the removed segment.
+	The current segment will be set to what was the next segment. If the removed segment was 
+	the last segment, the parser is at the end of the data.
+*/
+EXPORT_C void CDelimitedDataBase8::RemoveCurrentL()
+	{
+	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	DoRemoveL();
+	}
+
+/**
+	Adds a new segment to the end of the data. The new segment can be made up of several segments 
+	and have  delimiters at either extreme. The insert functionality will ensure that there is 
+	always a delimiter at the front of the new segment. The data must re-parsed to ensure that the 
+	parser is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The delimiter must have been set. 
+	@post			The data will have been extended to include the new segment.
+*/
+EXPORT_C void CDelimitedDataBase8::PushBackL(const TDesC8& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in reverse direction - sets last segment as current
+	iParser.ParseReverse(*iDataBuf);
+
+	// Insert the segment
+	DoInsertL(aSegment);
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data will have been reduced to exclude the last segment. 
+*/
+EXPORT_C void CDelimitedDataBase8::PopBackL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in reverse direction - sets last segment as current
+	iParser.ParseReverse(*iDataBuf);
+
+	// Remove the current segment
+	DoRemoveL();
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Adds a new segment to the front of the data. The new segment can be made up of several segments 
+	and have delimiters at either extreme. The insert functionality will ensure that there is always 
+	a delimiter at the front of the new segment. The data must re-parsed to ensure that the parser 
+	is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.					
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The delimiter must have been set. 
+	@post			The data will have been extended to include the new segment.
+*/
+EXPORT_C void CDelimitedDataBase8::PushFrontL(const TDesC8& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in forward direction - sets first segment as current
+	iParser.Parse(*iDataBuf);
+
+	// Insert the segment
+	DoInsertL(aSegment);
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data will have been reduced to exclude the last segment. 
+*/
+EXPORT_C void CDelimitedDataBase8::PopFrontL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in forward direction - sets first segment as current
+	iParser.Parse(*iDataBuf);
+
+	// Remove the current segment
+	DoRemoveL();
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the front delimiter (if exists) from the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been reduced to exclude the front delimiter. 
+*/
+EXPORT_C void CDelimitedDataBase8::TrimFrontDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Search for delimiter
+	if( iParser.FrontDelimiter() )
+		{
+		// Remove front delimiter and update member data
+		SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Adds a delimiter to the front of the data (if it doesn't exist).
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been extended to include a front delimiter. 
+*/
+EXPORT_C void CDelimitedDataBase8::AddFrontDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	if( !iParser.FrontDelimiter() )
+		{
+		// Create a new buffer of correct size
+		HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
+		TPtr8 str = buf->Des();
+
+		// Append a delimiter, then append the current string
+		str.Append(iParser.iDelimiter);
+		str.Append(iParser.iDataDes);
+
+		// Set buffer to this new string
+		SetData(buf);
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the back delimiter (if exists) from the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been reduced to exclude the front delimiter. 
+*/
+EXPORT_C void CDelimitedDataBase8::TrimBackDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Search for delimiter
+	if( iParser.BackDelimiter() )
+		{
+		// Remove back delimiter and update member data
+		SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Adds a delimiter to the back of the data (if it doesn't exist).
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has 
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been extended to include a front delimiter. 
+*/
+EXPORT_C void CDelimitedDataBase8::AddBackDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	if( !iParser.BackDelimiter() )
+		{
+		// Create a new buffer of correct size
+		HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
+		TPtr8 str = buf->Des();
+
+		// Append the current string, then append a delimiter
+		str.Append(iParser.iDataDes);
+		str.Append(iParser.iDelimiter);
+
+		// Set buffer to this new string
+		SetData(buf);
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	This parses the data into segments from left to right.
+	
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of 
+	parsing is set from left to right (EDelimitedDataFroward).
+*/
+EXPORT_C void CDelimitedDataBase8::Parse()
+	{
+	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
+	iParser.Parse(*iDataBuf);
+	}
+
+/**
+	This parses the string into segments from right to left.
+	
+	@since			6.0
+	@pre 			The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if 
+	the delimiter has not been initialized.
+	@post			The current segment is the leftmost segment and the direction of parsing is right to left.
+*/
+EXPORT_C void CDelimitedDataBase8::ParseReverse()
+	{
+	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
+	iParser.ParseReverse(*iDataBuf);
+	}
+
+/**
+	Retrieves a const reference to the delimited data parser. 
+	
+	@since			6.0
+	@return			A const reference to the delimited data parser. 
+*/
+EXPORT_C const TDelimitedParserBase8& CDelimitedDataBase8::Parser() const
+	{
+	return iParser;
+	}
+
+/**
+	Sets the delimiting character.
+	
+	@since			6.0
+	@param			aDelimiter	The delimiting character.
+	@post			The delimiting character is updated.
+*/
+EXPORT_C void CDelimitedDataBase8::SetDelimiter(TChar aDelimiter)
+	{
+	iParser.SetDelimiter(aDelimiter);
+	}
+
+/**
+	Constructor. First phase of two-phase construction method. Does non-allocating construction.
+						
+	@since			6.0
+*/
+EXPORT_C CDelimitedDataBase8::CDelimitedDataBase8()
+	{
+	}
+
+/**
+	Second phase of two-phase construction method. Does any allocations required to fully construct 
+	the object.
+						
+	@since			6.0
+	@param			aData	A descriptor with the initial string.
+	@pre 			First phase of construction is complete.
+	@post			The object is fully constructed.
+*/
+EXPORT_C void CDelimitedDataBase8::ConstructL(const TDesC8& aData)
+	{
+	// Create copy of string and set descriptor in the parser
+	SetDataL(aData);
+	}
+
+/**
+	Inserts the new segment in a position before the current segment. The new segment can be made up 
+	of several segments and have delimiters at either extreme. The insert functionality will ensure 
+	that there is always a delimiter at the front of the new segment. The parser will be left in a 
+	state where its current segment is the same one as before the insertion.
+						
+	@since			6.0
+	@param			aSegment	The descriptor with the segment to be inserted.
+	@pre 			The string must have been parsed.
+	@post			The string will have been extended to include the new segment. The current segment will
+	remain as the one before the insertion.
+*/
+void CDelimitedDataBase8::DoInsertL(const TDesC8& aSegment)
+	{
+	// Get previous delimiter to split the current string into prefix and suffix to the new segment
+	TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
+	TPtrC8 prefix = iParser.iDataDes.Left(prevPos);
+
+	TInt suffixLength = iParser.iDataDes.Length() - prevPos;
+	TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
+	if( suffixLength && suffix[0] == iParser.iDelimiter )
+		{
+		// Remove front delimiter on suffix
+		suffix.Set(suffix.Right(--suffixLength));
+		}	
+
+	// Check for delimiters
+	TPtrC8 segment = aSegment;
+	TInt segmentLength = segment.Length();
+	TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
+	if( segmentBackDelimiter )
+		{
+		// Remove back delimiter from the segment
+		segment.Set(segment.Left(--segmentLength));
+		}
+	if( segmentLength && segment[0] == iParser.iDelimiter )
+		{
+		// Remove front delimiter from the segment
+		segment.Set(segment.Right(--segmentLength));
+		}
+
+	// Check if a back delimiter is needed - NOTE always add a front delimiter
+	TInt extra = 1;
+	TBool needBackDelimiter = EFalse;
+	if( suffix.Length() || segmentBackDelimiter )
+		{
+		++extra;
+		needBackDelimiter = ETrue;
+		}
+	// Create space for new string
+	HBufC8* buf = HBufC8::NewL(prevPos + segmentLength + suffixLength + extra);
+	TPtr8 str = buf->Des();
+
+	// Form the new string
+	str.Append(prefix);
+	str.Append(iParser.iDelimiter);
+	str.Append(segment);
+	if( needBackDelimiter )
+		str.Append(iParser.iDelimiter);
+	str.Append(suffix);
+
+	// Update string data
+	SetData(buf);
+
+	// Check to see if the internal parser object (iParser) has been parsed
+	// (can tell if it has if the data pointer in iCurrentSegment is not NULL)
+	// If so update iCurrentSegment to ensure that iParser remains valid
+	if( iParser.iCurrentSegment.Ptr() )
+		{
+		// Ensure parser is in correct position and current segment is correct
+		iParser.iNextSegmentPos = prevPos;
+		if( iParser.iMode == EDelimitedDataForward )
+			{
+			// Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
+			iParser.iNextSegmentPos += segmentLength + 1;
+			}
+		// Get the next segment
+		iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
+		}
+	}
+
+/**
+	Removes the current segment. After removing the segment, the parser's new current segment will be 
+	the next segment. If the last segment is the one that is removed then the parser will be set to the 
+	end of the data.
+						
+	@since			6.0
+	@pre 			The data must have been parsed.
+	@post			The data will have been reduced to exclude the removed data. The 
+	current segment is set to what was the next segment. If the removed segment was 
+	the last segment, the parser is at the end of the data.
+*/
+void CDelimitedDataBase8::DoRemoveL()
+	{
+	// Check if there is anything to remove
+	if( iParser.iDataDes.Length() == 0 )
+		{
+		return;
+		}
+	// Find the previous delimiter
+	TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
+
+	// Set up the start and end position of current segment
+	TInt endPos = iParser.iNextSegmentPos;
+	TInt startPos = iParser.iNextSegmentPos;
+	if( prev < iParser.iNextSegmentPos )
+		startPos = prev;
+	else
+		endPos = prev;
+
+	// Ok, get the prefix and suffix parts
+	TPtrC8 prefix = iParser.iDataDes.Left(startPos);
+	TInt suffixLength = iParser.iDataDes.Length() - endPos;
+	TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
+
+	// Create the space
+	HBufC8* buf = HBufC8::NewL(startPos + suffixLength);
+	TPtr8 str = buf->Des();
+
+	// Form the new string
+	str.Append(prefix);
+	str.Append(suffix);
+
+	// Update string data
+	SetData(buf);
+
+	// Ensure parser is in correct position
+	iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
+	}
+
+/**
+	Updates internal data buffer with the new data. Creates a copy of the new data.
+						
+	@since			6.0
+	@param			aData	A descriptor with the new string.
+	@post			The internal data buffer now contains a copy of the new data and the 
+	parser is set to the new data.
+*/
+void CDelimitedDataBase8::SetDataL(const TDesC8& aData)
+    {
+	// Cleanup old data and set new
+	HBufC8* buf =  aData.AllocL();
+	SetData(buf);
+	}
+
+/**
+	Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. 
+	The parser is set to the new data.						
+	
+	@since			6.0
+	@param			aDataBuf	A pointer to a decriptor buffer with the new data.
+	@post			The internal data buffer now points to the new buffer and the parser 
+	is set to the data in the new buffer..
+*/
+void CDelimitedDataBase8::SetData(HBufC8* aDataBuf)
+	{
+	delete iDataBuf;
+	iDataBuf = aDataBuf;
+	iParser.iDataDes.Set(*iDataBuf);
+	}
+
+//
+//
+// Implementation of TDelimitedParserBase16
+//
+//
+/**
+	Constructor.
+	
+	@since			6.0
+ */
+EXPORT_C TDelimitedParserBase16::TDelimitedParserBase16()
+: iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
+	{
+	}
+
+/**
+	Resets the internal pointer position to the start or end or the descriptor depending 
+	on whether the decriptor is parsing mode.
+	
+	@warning		There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has 
+	not been correctly set.
+ */
+EXPORT_C void TDelimitedParserBase16::Reset() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
+	}
+/**
+	Retrieves the current segment and then parses the data to the next one.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@param			aSegment	This is an output argument that is set to the current segment.
+	@return			A error value of KErrNotFound if there is no current segment. The
+	value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+	@post			The current segment is updated to the next one.
+ */
+EXPORT_C TInt TDelimitedParserBase16::GetNext(TPtrC16& aSegment) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// There is one - set aSegment
+	aSegment.Set(iCurrentSegment);
+	// Parse the next segment
+	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
+	return KErrNone;
+	}
+	
+/**
+	Parses to the next segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A error value of KErrNotFound if there is no current segment. The
+	value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+	@post			The current segment is updated to the next one.
+ */
+EXPORT_C TInt TDelimitedParserBase16::Inc() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// Parse the next segment
+	iNextSegmentPos = FindNextSegment(iNextSegmentPos);
+	return KErrNone;
+	}
+	
+/**
+	Parses back to the previous segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A error value of KErrNotFound if the current segment is the initial
+	segment. The value KErrNone if the data has been parsed to the previous segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+	@post			If the parse was successful then the  current segment is updated
+	to the previous one. Otherwise there is no change.
+ */
+EXPORT_C TInt TDelimitedParserBase16::Dec() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Find position of previous delimiter 
+	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
+
+	// Get the previous segment
+	if( FindPrevSegment(prev) == KErrNotFound )
+		{
+		// There is no previous segment - set to start of data
+		return KErrNotFound;
+		}
+	// Update next segment position
+	iNextSegmentPos = prev;
+	return KErrNone;
+	}
+
+/**
+	Retrieves the current segment.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@param			aSegment	This is an output argument that is set to the current segment.
+	@return			A error value of KErrNotFound if there is no current segment. The
+					value KErrNone if there is a current segment.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TInt TDelimitedParserBase16::Peek(TPtrC16& aSegment) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check that there is a segment
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// There is one - set aSegment
+	aSegment.Set(iCurrentSegment);
+	return KErrNone;
+	}
+	
+/**
+	Indicates whether the end of the data has been reached and there are no more segments to parse.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A boolean value of ETrue if the end of the data has been reached,
+	or EFalse if there are more segements to parse.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TBool TDelimitedParserBase16::Eos() const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+
+	TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
+	return eos;
+	}
+	
+/**
+	Checks for a delimiter at the front (left) of the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A boolean of value ETrue if there is a front delimiter, or EFalse
+	if there is no front delimiter.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TBool TDelimitedParserBase16::FrontDelimiter() const
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	return (iDataDes.Locate(iDelimiter) == 0);
+	}
+
+/**
+	Checks for a delimiter at the back (right) of the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@return			A boolean of value ETrue if there is a back delimiter, or EFalse
+	if there is no back delimiter.
+	@pre 			The string must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TBool TDelimitedParserBase16::BackDelimiter() const
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
+	if( delimiterPos == KErrNotFound )
+		return EFalse;
+	return (delimiterPos == iDataDes.Length() - 1);
+	}
+	
+/**
+	Retrieves the descriptor reference with the data
+	
+	@since			6.0
+	@return			A const descriptor reference with the data.
+ */
+EXPORT_C const TDesC16& TDelimitedParserBase16::Des() const
+	{
+	return iDataDes;
+	}
+	
+/**
+	Gives the remainder of the data from (and including) the current segment. Any other segments that 
+	have parsed through are not included.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
+	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@param			aRemainder	This is an output argument that is set to the remaining data.
+	@return			An error value of KErrNotFound if there is no remaining data, or value of KErrNone 
+	if there is remaining data.
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+ */
+EXPORT_C TInt TDelimitedParserBase16::Remainder(TPtrC16& aRemainder) const
+	{
+	__ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Check to see if there is a segment left
+	if( iNextSegmentPos == KErrNotFound )
+		{
+		// There is no segment
+		return KErrNotFound;
+		}
+	// Find the previous delimiter -> the start of the current segment
+	TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
+
+	// Need to see which direction the parsing is going to set the remainder
+	switch(iMode)
+		{
+	case EDelimitedDataForward:
+		{
+		aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
+		} break;
+	case EDelimitedDataReverse:
+		{
+		aRemainder.Set(iDataDes.Left(prev));
+		} break;
+	default:
+		// Bad mode!
+		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
+		break;
+		}
+	return KErrNone;
+	}
+	
+/**
+	This parses the data into segments from left to right.
+	
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@param			aData	A descriptor containing the data.
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of
+	parsing is set from left to right (EDelimitedDataFroward).
+ */
+EXPORT_C void TDelimitedParserBase16::Parse(const TDesC16& aData)
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Initialise data for EForward direction
+	iMode = EDelimitedDataForward;
+	DoParse(aData);
+	}
+
+/**
+	This parses the data into segments from lright to left.
+	
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@param			aData	A descriptor containing the data.
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of
+	parsing is set from right to left (EDelimitedDataReverse).
+ */
+EXPORT_C void TDelimitedParserBase16::ParseReverse(const TDesC16& aData)
+	{
+	__ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Initialise data for EReverse direction
+	iMode = EDelimitedDataReverse;
+	DoParse(aData);
+	}
+
+/**
+	Sets the delimiting character.
+	
+	@since			6.0
+	@param			aDelimiter	The delimiting character.
+	@post			The delimiting character is set.
+*/
+EXPORT_C void TDelimitedParserBase16::SetDelimiter(TChar aDelimiter)
+	{
+	iDelimiter = aDelimiter;
+	}
+
+/**
+	Initialises the parsing of the data.
+	
+	@since			6.0
+	@param			aData	A descriptor reference with the data.
+	@pre 			The delimiting character has been set.
+	@post			The data descriptor is set to the input argument. The current segment 
+	refers to the initial segment of the data.
+ */
+void TDelimitedParserBase16::DoParse(const TDesC16& aData)
+	{
+	// Reset the segment information, then set the new Data - set pointer to NULL and length to zero
+	iCurrentSegment.Set(NULL,0);
+	iDataDes.Set(aData);
+
+	// Check that there is a string!
+	if( iDataDes.Length() == 0 )
+		{
+		// No string - ensure functionality blocked for this descriptor
+		iNextSegmentPos = KErrNotFound;
+		return;
+		}
+	// Find the segment - search from initial start position
+	iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
+	}
+
+/**
+	Finds the next segment from the given start position.
+	
+	@since			6.0
+	@param			aStartPos	The position from where to start the search for the
+	next segment.
+	@return			The position of delimiter after the specified start position, or
+	an error value of KErrNotFound if no more delimiters are found.
+ */
+TInt TDelimitedParserBase16::FindNextSegment(TInt aStartPos) const
+	{
+	// Find position of next delimiter
+	TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
+
+	if( next != KErrNotFound )
+		{
+		TInt startPos = next < aStartPos ? next : aStartPos;
+		TInt endPos = next < aStartPos ? aStartPos : next;
+		if( iDataDes[startPos] == iDelimiter )
+			{
+			// Move past delimiter
+			++startPos;
+			}
+		TInt length = endPos - startPos;
+		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
+		}
+	return next;
+	}
+	
+/**
+	Finds the previous segment from the given start position.
+	
+	@since			6.0
+	@param			aStartPos	The position from where to start the search for the
+	previous segment.
+	@return			The position of delimiter before the specified start position, or
+	an error value of KErrNotFound if no more delimiters are found.
+*/
+TInt TDelimitedParserBase16::FindPrevSegment(TInt aStartPos) const
+	{
+	// Find position of previous delimiter 
+	TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
+	
+	if( prev != KErrNotFound )
+		{
+		TInt startPos = prev < aStartPos ? prev : aStartPos;
+		TInt endPos = prev < aStartPos ? aStartPos : prev;
+		if( iDataDes[startPos] == iDelimiter )
+			{
+			// Move past delimiter
+			++startPos;
+			}
+		TInt length = endPos - startPos;
+		iCurrentSegment.Set(iDataDes.Mid(startPos, length));
+		}
+	return prev;
+	}
+
+//
+//
+// Implementation of CDelimitedDataBase16
+//
+//
+
+/**
+	Destructor.
+	
+	@since			6.0
+ */
+EXPORT_C CDelimitedDataBase16::~CDelimitedDataBase16()
+	{
+	delete iDataBuf;
+	}
+
+/**
+	Inserts the new segment in a position before the current parsed	segment. The new segment can be 
+	made up of several segments and have delimiters at either extreme. The insert functionality will 
+	ensure that there is always a delimiter at the front of the new segment. The parser is left in a 
+	state where its current segment is the same one as before the insertion.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
+	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+	@post			The data will have been extended to include the new segment. The current segment 
+	will remain as the one before the insertion.
+ */
+EXPORT_C void CDelimitedDataBase16::InsertCurrentL(const TDesC16& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	DoInsertL(aSegment);
+	}
+	
+/**
+	Removes the current segment. After removing the segment, the parser's new current segment will be the 
+	next segment. If the last segment is the one that is removed then the parser will be set to the end of 
+	the data.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and 
+	a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
+	@since			6.0
+	@pre 			The data must have been initially parsed by Parse() or ParseReverse().
+	@post			The data will have been reduced to exclude the removed segment.	The current segment will 
+	be set to what was the next segment. If the removed segment was the last segment, the parser is at the end 
+	of the data.
+ */
+EXPORT_C void CDelimitedDataBase16::RemoveCurrentL()
+	{
+	__ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	DoRemoveL();
+	}
+
+/**
+	Adds a new segment to the end of the data. The new segment can be made up of several segments and have  
+	delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at 
+	the front of the new segment. The data must re-parsed to ensure that the parser is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and a 
+	KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure 
+	that the parser is valid.
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The delimiter must have been set.
+	@post			The data will have been extended to include the new segment.
+ */
+EXPORT_C void CDelimitedDataBase16::PushBackL(const TDesC16& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in reverse direction - sets last segment as current
+	iParser.ParseReverse(*iDataBuf);
+
+	// Insert the segment
+	DoInsertL(aSegment);
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, 
+	and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required 
+	to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data will have been reduced to exclude the last segment.
+ */
+EXPORT_C void CDelimitedDataBase16::PopBackL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in reverse direction - sets last segment as current
+	iParser.ParseReverse(*iDataBuf);
+
+	// Remove the current segment
+	DoRemoveL();
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+
+/**
+	Adds a new segment to the front of the data. The new segment can be made up of several segments and have  
+	delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at 
+	the front of the new segment. The data must re-parsed to ensure that the parser is valid.
+							
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and 
+	a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure 
+	that the parser is valid.
+	@since			6.0
+	@param			aSegment	A descriptor with the new segment to be inserted.
+	@pre 			The delimiter must have been set.
+	@post			The data will have been extended to include the new segment.
+ */
+EXPORT_C void CDelimitedDataBase16::PushFrontL(const TDesC16& aSegment)
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in forward direction - sets first segment as current
+	iParser.Parse(*iDataBuf);
+
+	// Insert the segment
+	DoInsertL(aSegment);
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
+						
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has	not been 
+	parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse 
+	is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data will have been reduced to exclude the last segment.
+ */
+EXPORT_C void CDelimitedDataBase16::PopFrontL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Parse the string in forward direction - sets first segment as current
+	iParser.Parse(*iDataBuf);
+
+	// Remove the current segment
+	DoRemoveL();
+
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+
+/**
+	Removes the front delimiter (if exists) from the data.
+	
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been reduced to exclude the front delimiter.
+ */
+EXPORT_C void CDelimitedDataBase16::TrimFrontDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Search for delimiter
+	if( iParser.FrontDelimiter() )
+		{
+		// Remove front delimiter and update member data
+		SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Adds a delimiter to the front of the data (if it doesn't exist).
+
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. 
+	A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been extended to include a front delimiter.
+ */
+EXPORT_C void CDelimitedDataBase16::AddFrontDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	if( !iParser.FrontDelimiter() )
+		{
+		// Create a new buffer of correct size
+		HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
+		TPtr16 str = buf->Des();
+
+		// Append a delimiter, then append the current string
+		str.Append(iParser.iDelimiter);
+		str.Append(iParser.iDataDes);
+
+		// Set buffer to this new string
+		SetData(buf);
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Removes the back delimiter (if exists) from the data.
+
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has
+	not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not 
+	been set. A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been reduced to exclude the front delimiter.
+ */
+EXPORT_C void CDelimitedDataBase16::TrimBackDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	// Search for delimiter
+	if( iParser.BackDelimiter() )
+		{
+		// Remove back delimiter and update member data
+		SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+
+/**
+	Adds a delimiter to the back of the data (if it doesn't exist).
+
+	@warning		There will be a KDelimitedParserErrNotParsed panic if the data has not 
+	been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. 
+	A re-parse is required to ensure that the parser is valid.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The data might have been extended to include a front delimiter.
+ */
+EXPORT_C void CDelimitedDataBase16::AddBackDelimiterL()
+	{
+	__ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
+
+	if( !iParser.BackDelimiter() )
+		{
+		// Create a new buffer of correct size
+		HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
+		TPtr16 str = buf->Des();
+
+		// Append the current string, then append a delimiter
+		str.Append(iParser.iDataDes);
+		str.Append(iParser.iDelimiter);
+
+		// Set buffer to this new string
+		SetData(buf);
+		}
+	// Make sure that a re-parse is required
+	iParser.iMode = EDelimitedDataNotParsed;
+	}
+	
+/**
+	This parses the data into segments from left to right.
+
+	@warning		There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
+	has not been set.
+	@since			6.0
+	@pre 			The delimiter must have been set.
+	@post			The current segment is the leftmost segment and the direction of
+	parsing is set from left to right (EDelimitedDataFroward).
+ */
+EXPORT_C void CDelimitedDataBase16::Parse()
+	{
+	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
+	iParser.Parse(*iDataBuf);
+	}
+
+/**
+	This parses the string into segments from right to left.
+	
+	@since			6.0
+	@pre 			The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
+	the delimiter has not been initialized.
+	@post			The current segment is the leftmost segment and the direction of parsing is right to left.
+ */
+EXPORT_C void CDelimitedDataBase16::ParseReverse()
+	{
+	// This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
+	iParser.ParseReverse(*iDataBuf);
+	}
+	
+/**
+	Retrieves a const reference to the delimited data parser.
+
+	@since			6.0
+	@return			A const reference to the delimited data parser.
+ */
+EXPORT_C const TDelimitedParserBase16& CDelimitedDataBase16::Parser() const
+	{
+	return iParser;
+	}
+	
+/**
+	Sets the delimiting character.
+	
+	@since			6.0
+	@param			aDelimiter	The delimiting character.
+	@post			The delimiting character is updated.
+ */
+EXPORT_C void CDelimitedDataBase16::SetDelimiter(TChar aDelimiter)
+	{
+	iParser.SetDelimiter(aDelimiter);
+	}
+
+/**
+	Constructor. First phase of two-phase construction method. Does non-allocating construction.
+	
+	@since			6.0
+ */
+EXPORT_C CDelimitedDataBase16::CDelimitedDataBase16()
+	{
+	}
+	
+/**
+	Second phase of two-phase construction method. Does any	allocations required to fully construct 
+	the object.
+						
+	@since			6.0
+	@param			aData	A descriptor with the initial string.
+	@pre 			First phase of construction is complete.
+	@post			The object is fully constructed.
+ */
+EXPORT_C void CDelimitedDataBase16::ConstructL(const TDesC16& aData)
+	{
+	// Create copy of string and set descriptor in the parser
+	SetDataL(aData);
+	}
+	
+/**
+	Inserts the new segment in a position before the current segment. The new segment can be made up of 
+	several segments and have delimiters at either extreme. The insert functionality will ensure that 
+	there is always a delimiter at the front of the	new segment. The parser will be left in a state where 
+	its current segment is the same one as before the insertion.
+						
+	@since			6.0
+	@param			aSegment	The descriptor with the segment to be inserted.
+	@pre 			The string must have been parsed.
+	@post			The string will have been extended to include the new segment. The current segment will
+	remain as the one before the insertion.
+ */
+void CDelimitedDataBase16::DoInsertL(const TDesC16& aSegment)
+	{
+	TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
+	TPtrC16 prefix = iParser.iDataDes.Left(prevPos);
+
+	TInt suffixLength = iParser.iDataDes.Length() - prevPos;
+	TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
+	if( suffixLength && suffix[0] == iParser.iDelimiter )
+		{
+		// Remove front delimiter on suffix
+		suffix.Set(suffix.Right(--suffixLength));
+		}	
+
+	// Check for delimiters...
+	TPtrC16 segment = aSegment;
+	TInt segmentLength = segment.Length();
+	// Check the last character in segment
+	TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
+	if( segmentBackDelimiter )
+		{
+		// Remove back delimiter from the segment
+		segment.Set(segment.Left(--segmentLength));
+		}
+	// Check the first character in segment...
+	if( segmentLength && segment[0] == iParser.iDelimiter )
+		{
+		// Remove front delimiter from the segment
+		segment.Set(segment.Right(--segmentLength));
+		}
+
+	// Check if a back delimiter is needed - NOTE always add a front delimiter
+	TInt extra = 1;
+	TBool needBackDelimiter = EFalse;
+	if( suffix.Length() || segmentBackDelimiter )
+		{
+		++extra;
+		needBackDelimiter = ETrue;
+		}
+	// Create space for new string
+	HBufC16* buf = HBufC16::NewL(prevPos + segmentLength + suffixLength + extra);
+	TPtr16 str = buf->Des();
+
+	// Form the new string
+	str.Append(prefix);
+	str.Append(iParser.iDelimiter);
+	str.Append(segment);
+	if( needBackDelimiter )
+		str.Append(iParser.iDelimiter);
+	str.Append(suffix);
+
+	// Update string data
+	SetData(buf);
+
+	// Check to see if the internal parser object (iParser) has been parsed
+	// (can tell if it has if the data pointer in iCurrentSegment is not NULL)
+	// If so update iCurrentSegment to ensure that iParser remains valid
+	if( iParser.iCurrentSegment.Ptr() )
+		{
+		// Ensure parser is in correct position and current segment is correct
+		iParser.iNextSegmentPos = prevPos;
+		if( iParser.iMode == EDelimitedDataForward )
+			{
+			// Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
+			iParser.iNextSegmentPos += segmentLength + 1;
+			}
+		// Get the next segment
+		iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
+		}
+	}
+
+/**
+	Removes the current segment. After removing the segment, the parser's new current segment will be the 
+	next segment. If the last segment is the one that is removed then the parser will be set to the end of 
+	the data.
+						
+	@since			6.0
+	@pre 			The data must have been parsed.
+	@post			The data will have been reduced to exclude the removed data. The current segment 
+	is set to what was the next segment. If the removed segment was	the last segment, the parser is 
+	at the end of the data.
+ */
+void CDelimitedDataBase16::DoRemoveL()
+	{
+	// Check if there is anything to remove
+	if( iParser.iDataDes.Length() == 0 )
+		{
+		return;
+		}
+	// Find the previous delimiter
+	TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
+
+	// Set up the start and end position of current segment
+	TInt endPos = iParser.iNextSegmentPos;
+	TInt startPos = iParser.iNextSegmentPos;
+	if( prev < iParser.iNextSegmentPos )
+		startPos = prev;
+	else
+		endPos = prev;
+
+	// Ok, get the prefix and suffix parts
+	TPtrC16 prefix = iParser.iDataDes.Left(startPos);
+	TInt suffixLength = iParser.iDataDes.Length() - endPos;
+	TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
+
+	// Create the space
+	HBufC16* buf = HBufC16::NewL(startPos + suffixLength);
+	TPtr16 str = buf->Des();
+
+	// Form the new string
+	str.Append(prefix);
+	str.Append(suffix);
+
+	// Update string data
+	SetData(buf);
+
+	// Ensure parser is in correct position
+	iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
+	}
+
+/**
+	Updates internal data buffer with the new data. Creates a copy of the new data.
+						
+	@since			6.0
+	@param			aData	A descriptor with the new string.
+	@post			The internal data buffer now contains a copy of the new data and the
+	parser is set to the new data.
+ */
+void CDelimitedDataBase16::SetDataL(const TDesC16& aData)
+	{
+	// Cleanup old data and set new
+	HBufC16* buf =  aData.AllocL();
+	SetData(buf);
+	}
+	
+/**
+	Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. The 
+	parser is set to the new data.
+						
+	@since			6.0
+	@param			aDataBuf	A pointer to a decriptor buffer with the new data.
+	@post			The internal data buffer now points to the new buffer and the parser
+	is set to the data in the new buffer..
+ */
+void CDelimitedDataBase16::SetData(HBufC16* aDataBuf)
+	{
+	delete iDataBuf;
+	iDataBuf = aDataBuf;
+	iParser.iDataDes.Set(*iDataBuf);
+	}
+
+//
+//
+// Implementation of LOCAL functions
+//
+//
+
+/**
+	Finds the position of the next delimiter in the data.
+	
+	@since			6.0
+	@param			aData		A descriptor with the delimited data.
+	@param			aStartPos	The position from where to start the search for the delimiter.
+	@param			aDelimiter	The delimiting character.
+	@param			aMode		The parsing mode.
+	@return			The position of delimiter after the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.	
+	@pre			None
+	@post			Unspecified
+ */
+template<class TDesCType>
+TInt NextDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
+	{
+	if( aStartPos == KErrNotFound )
+		{
+		// Have got to the end - initialise the iterator
+		return InitialDelimiterPosition(aData, aMode);
+		}
+	TInt next = KErrNotFound;
+	switch( aMode )
+		{
+	case EDelimitedDataForward:
+		{
+		// Search parsed string for next delimiter
+		next = LeftDelimiterPosition(aData, aStartPos, aDelimiter);
+		} break;
+	case EDelimitedDataReverse:
+		{
+		// Search parsed string for next delimiter
+		next = RightDelimiterPosition(aData, aStartPos, aDelimiter);
+		} break;
+	default:
+		// Bad mode!
+		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
+		break;
+		}
+	return next;
+	}
+
+
+/**
+	Finds the position of the previous delimiter in the data from the given start position.
+	
+	@since			6.0
+	@param			aData		A descriptor with the delimited data.
+	@param			aStartPos	The position from where to start the search for the delimiter.
+	@param			aDelimiter	The delimiting character.
+	@param			aMode		The parsing mode.
+	@return			The position of delimiter before the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.	
+	@pre			None
+	@post			Unspecified
+ */
+template<class TDesCType>
+TInt PrevDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
+	{
+	// Switch modes, then find the next delimiter, switch back
+	TDelimitedDataParseMode mode = aMode == EDelimitedDataForward ? EDelimitedDataReverse : EDelimitedDataForward;
+	return NextDelimiterPosition(aData, aStartPos, aDelimiter, mode);
+	}
+
+/**
+	Finds the position of the delimiter to the right of the given start position.
+	
+	@since			6.0
+	@param			aData		A descriptor with the delimited data.
+	@param			aStartPos	The position from where to start the search for the delimiter.
+	@param			aDelimiter	The delimiting character.
+	@return			The position of delimiter to the right of the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.	
+	@pre			None
+	@post			Unspecified
+ */
+template<class TDesCType>
+TInt RightDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
+	{
+	// Find position of right-most delimiter in the descriptor data to left of aStartPos
+	if( aStartPos == 0 )
+		{
+		// There is no data
+		return KErrNotFound;
+		}
+	TInt rightDelimiterPos = aData.Left(aStartPos).LocateReverse(aDelimiter);
+
+	// See if a delimiter was found
+	if( rightDelimiterPos == KErrNotFound )
+		{
+		// No - start of string delimits
+		rightDelimiterPos = 0;
+		}
+	return rightDelimiterPos;
+	}
+
+/**
+	Finds the position of the delimiter to the left of the given start position.
+	
+	@since			6.0
+	@param			aData		A descriptor with the delimited data.
+	@param			aStartPos	The position from where to start the search for the delimiter.
+	@param			aDelimiter	The delimiting character.
+	@return			The position of delimiter to the left of the specified start position, or 
+	an error value of KErrNotFound if no more delimiters are found.	
+	@pre			None
+	@post			Unspecified
+ */
+template<class TDesCType>
+TInt LeftDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
+	{
+	// Find position of left-most delimiter in the descriptor data to right of aStartPos
+	const TInt length = aData.Length();
+	TInt rightLength = length - aStartPos;
+	if( rightLength == 0 )
+		{
+		// There is no data
+		return KErrNotFound;
+		}
+	// Ok there is some string to search - remove delimiter
+	--rightLength;
+	TInt leftDelimiterPos = aData.Right(rightLength).Locate(aDelimiter);
+
+	// See if a delimiter was found
+	if( leftDelimiterPos == KErrNotFound )
+		{
+		// No - end of string delimits
+		leftDelimiterPos = length;
+		}
+	else
+		{
+		// Offset the delimiter found - include delimiter that was removed
+		leftDelimiterPos += aStartPos + 1;
+		}
+	return leftDelimiterPos;
+	}
+
+/**
+	Retrieves the initial position for searching delimited data for a given parsing mode.
+	
+	@since			6.0
+	@param			aData		A descriptor with the delimited data.
+	@param			aMode		The parsing mode.
+	@return			The initial position for parsing the data.
+	@pre			None
+	@post			Unspecified
+ */
+template<class TDesCType>
+TInt InitialDelimiterPosition(const TDesCType& aData, TDelimitedDataParseMode aMode)
+//
+// Initialises iNextSegmentPos
+	{
+	TInt initPos = KErrNotFound;
+	switch( aMode )
+		{
+	case EDelimitedDataForward:
+		{
+		// Search parsed string for next delimiter
+		initPos = 0;
+		} break;
+	case EDelimitedDataReverse:
+		{
+		// Search parsed string for next delimiter
+		initPos = aData.Length();
+		} break;
+	default:
+		// Bad mode!
+		User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
+		break;
+		}
+	return initPos;
+	}
+