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