First public contribution.
1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <delimitedparser8.h>
17 #include <delimitedparser16.h>
18 #include "DelimitedParserInternal.h"
19 #include <uriutilscommon.h>
23 _LIT(KDelimitedParserPanicCategory,"DELIM-PARSER");
27 // Implementation of TDelimitedParserBase8
36 EXPORT_C TDelimitedParserBase8::TDelimitedParserBase8()
37 : iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
42 Resets the internal pointer position to the start or end or the descriptor
43 depending on whether the decriptor is parsing mode.
45 @warning There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has
46 not been correctly set.
48 EXPORT_C void TDelimitedParserBase8::Reset() const
50 iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
54 Retrieves the current segment and then parses the data to the next one.
56 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
57 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
60 @param aSegment This is an output argument that is set to the current segment.
61 @return A error value of KErrNotFound if there is no current segment. The
62 value KErrNone if there is a current segment.
63 @pre The string must have been initially parsed by Parse() or ParseReverse().
64 @post The current segment is updated to the next one.
66 EXPORT_C TInt TDelimitedParserBase8::GetNext(TPtrC8& aSegment) const
68 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
69 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
71 // Check that there is a segment
72 if( iNextSegmentPos == KErrNotFound )
74 // There is no segment
77 // There is one - set aSegment
78 aSegment.Set(iCurrentSegment);
79 // Parse the next segment
80 iNextSegmentPos = FindNextSegment(iNextSegmentPos);
85 Parses to the next segment.
87 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
88 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
91 @return A error value of KErrNotFound if there is no current segment. The
92 value KErrNone if there is a current segment.
93 @pre The string must have been initially parsed by Parse() or ParseReverse().
94 @post The current segment is updated to the next one.
96 EXPORT_C TInt TDelimitedParserBase8::Inc() const
98 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
99 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
101 // Check that there is a segment
102 if( iNextSegmentPos == KErrNotFound )
104 // There is no segment
107 // Parse the next segment
108 iNextSegmentPos = FindNextSegment(iNextSegmentPos);
113 Parses back to the previous segment.
115 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
116 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
119 @return A error value of KErrNotFound if the current segment is the initial
120 segment. The value KErrNone if the data has been parsed to the previous segment.
121 @pre The string must have been initially parsed by Parse() or ParseReverse().
122 @post If the parse was successful then the current segment is updated
123 to the previous one. Otherwise there is no change.
125 EXPORT_C TInt TDelimitedParserBase8::Dec() const
127 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
128 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
130 // Find position of previous delimiter
131 TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
133 // Get the previous segment
134 if( FindPrevSegment(prev) == KErrNotFound )
136 // There is no previous segment - set to start of data
139 // Update next segment position
140 iNextSegmentPos = prev;
145 Retrieves the current segment.
147 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
148 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
151 @param aSegment This is an output argument that is set to the current segment.
152 @return A error value of KErrNotFound if there is no current segment. The
153 value KErrNone if there is a current segment.
154 @pre The string must have been initially parsed by Parse() or ParseReverse().
156 EXPORT_C TInt TDelimitedParserBase8::Peek(TPtrC8& aSegment) const
158 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
159 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
161 // Check that there is a segment
162 if( iNextSegmentPos == KErrNotFound )
164 // There is no segment
167 // There is one - set aSegment
168 aSegment.Set(iCurrentSegment);
173 Indicates whether the end of the data has been reached and there are no more segments
176 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
177 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
180 @return A boolean value of ETrue if the end of the data has been reached,
181 or EFalse if there are more segements to parse.
182 @pre The string must have been initially parsed by Parse() or ParseReverse().
184 EXPORT_C TBool TDelimitedParserBase8::Eos() const
186 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
188 TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
193 Checks for a delimiter at the front (left) of the data.
195 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
196 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
198 @return A boolean of value ETrue if there is a front delimiter, or EFalse
199 if there is no front delimiter.
200 @pre The string must have been initially parsed by Parse() or ParseReverse().
202 EXPORT_C TBool TDelimitedParserBase8::FrontDelimiter() const
204 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
206 return (iDataDes.Locate(iDelimiter) == 0);
210 Checks for a delimiter at the back (right) of the data.
212 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
213 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
216 @return A boolean of value ETrue if there is a back delimiter, or EFalse
217 if there is no back delimiter.
218 @pre The string must have been initially parsed by Parse() or ParseReverse().
220 EXPORT_C TBool TDelimitedParserBase8::BackDelimiter() const
222 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
224 TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
225 if( delimiterPos == KErrNotFound )
227 return (delimiterPos == iDataDes.Length() - 1);
231 Retrieves the descriptor reference with the data
234 @return A const descriptor reference with the data.
236 EXPORT_C const TDesC8& TDelimitedParserBase8::Des() const
242 Gives the remainder of the data from (and including) the current segment. Any other segments
243 that have parsed through are not included.
245 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
246 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
249 @param aRemainder This is an output argument that is set to the remaining data.
250 @return An error value of KErrNotFound if there is no remaining data, or
251 value of KErrNone if there is remaining data.
252 @pre The data must have been initially parsed by Parse() or ParseReverse().
254 EXPORT_C TInt TDelimitedParserBase8::Remainder(TPtrC8& aRemainder) const
256 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
257 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
259 // Check to see if there is a segment left
260 if( iNextSegmentPos == KErrNotFound )
262 // There is no segment
265 // Find the previous delimiter -> the start of the current segment
266 TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
268 // Need to see which direction the parsing is going to set the remainder
271 case EDelimitedDataForward:
273 aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
275 case EDelimitedDataReverse:
277 aRemainder.Set(iDataDes.Left(prev));
281 User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
288 This parses the data into segments from left to right.
290 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
293 @param aData A descriptor containing the data.
294 @pre The delimiter must have been set.
295 @post The current segment is the leftmost segment and the direction of
296 parsing is set from left to right (EDelimitedDataFroward).
298 EXPORT_C void TDelimitedParserBase8::Parse(const TDesC8& aData)
300 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
302 // Initialise data for EForward direction
303 iMode = EDelimitedDataForward;
308 This parses the data into segments from lright to left.
310 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
313 @param aData A descriptor containing the data.
314 @pre The delimiter must have been set.
315 @post The current segment is the leftmost segment and the direction of
316 parsing is set from right to left (EDelimitedDataReverse).
318 EXPORT_C void TDelimitedParserBase8::ParseReverse(const TDesC8& aData)
320 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
322 // Initialise data for EReverse direction
323 iMode = EDelimitedDataReverse;
328 Sets the delimiting character.
331 @param aDelimiter The delimiting character.
332 @post The delimiting character is set.
334 EXPORT_C void TDelimitedParserBase8::SetDelimiter(TChar aDelimiter)
336 iDelimiter = aDelimiter;
340 Initialises the parsing of the data.
343 @param aData A descriptor reference with the data.
344 @pre The delimiting character has been set.
345 @post The data descriptor is set to the input argument. The current
346 segment refers to the initial segment of the data.
348 void TDelimitedParserBase8::DoParse(const TDesC8& aData)
350 // Reset the segment information, then set the new Data - set pointer to NULL and length to zero
351 iCurrentSegment.Set(NULL,0);
354 // Check that there is a string!
355 if( iDataDes.Length() == 0 )
357 // No string - ensure functionality blocked for this descriptor
358 iNextSegmentPos = KErrNotFound;
361 // Find the segment - search from initial start position
362 iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
366 Finds the next segment from the given start position.
369 @param aStartPos The position from where to start the search for the
371 @return The position of delimiter after the specified start position, or
372 an error value of KErrNotFound if no more delimiters are found.
374 TInt TDelimitedParserBase8::FindNextSegment(TInt aStartPos) const
376 // Find position of next delimiter
377 TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
379 if( next != KErrNotFound )
381 TInt startPos = next < aStartPos ? next : aStartPos;
382 TInt endPos = next < aStartPos ? aStartPos : next;
383 if( iDataDes[startPos] == iDelimiter )
385 // Move past delimiter
388 TInt length = endPos - startPos;
389 iCurrentSegment.Set(iDataDes.Mid(startPos, length));
395 Finds the previous segment from the given start position.
398 @param aStartPos The position from where to start the search for the
400 @return The position of delimiter before the specified start position, or
401 an error value of KErrNotFound if no more delimiters are found.
403 TInt TDelimitedParserBase8::FindPrevSegment(TInt aStartPos) const
405 // Find position of previous delimiter
406 TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
408 if( prev != KErrNotFound )
410 TInt startPos = prev < aStartPos ? prev : aStartPos;
411 TInt endPos = prev < aStartPos ? aStartPos : prev;
412 if( iDataDes[startPos] == iDelimiter )
414 // Move past delimiter
417 TInt length = endPos - startPos;
418 iCurrentSegment.Set(iDataDes.Mid(startPos, length));
425 // Implementation of CDelimitedDataBase8
434 EXPORT_C CDelimitedDataBase8::~CDelimitedDataBase8()
440 Inserts the new segment in a position before the current parsed segment. The new
441 segment can be made up of several segments and have delimiters at either extreme.
442 The insert functionality will ensure that there is always a delimiter at the front
443 of the new segment. The parser is left in a state where its current segment is the
444 same one as before the insertion.
446 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been
447 parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
449 @param aSegment A descriptor with the new segment to be inserted.
450 @pre The data must have been initially parsed by Parse() or ParseReverse().
451 @post The data will have been extended to include the new segment. The
452 current segment will remain as the one before the insertion.
454 EXPORT_C void CDelimitedDataBase8::InsertCurrentL(const TDesC8& aSegment)
456 __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
457 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
463 Removes the current segment. After removing the segment, the parser's new current segment
464 will be the next segment. If the last segment is the one that is removed then the parser
465 will be set to the end of the data.
467 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
468 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
471 @pre The data must have been initially parsed by Parse() or ParseReverse().
472 @post The data will have been reduced to exclude the removed segment.
473 The current segment will be set to what was the next segment. If the removed segment was
474 the last segment, the parser is at the end of the data.
476 EXPORT_C void CDelimitedDataBase8::RemoveCurrentL()
478 __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
479 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
485 Adds a new segment to the end of the data. The new segment can be made up of several segments
486 and have delimiters at either extreme. The insert functionality will ensure that there is
487 always a delimiter at the front of the new segment. The data must re-parsed to ensure that the
490 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
491 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
492 been set. A re-parse is required to ensure that the parser is valid.
494 @param aSegment A descriptor with the new segment to be inserted.
495 @pre The delimiter must have been set.
496 @post The data will have been extended to include the new segment.
498 EXPORT_C void CDelimitedDataBase8::PushBackL(const TDesC8& aSegment)
500 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
502 // Parse the string in reverse direction - sets last segment as current
503 iParser.ParseReverse(*iDataBuf);
505 // Insert the segment
508 // Make sure that a re-parse is required
509 iParser.iMode = EDelimitedDataNotParsed;
513 Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
515 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
516 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
517 been set. A re-parse is required to ensure that the parser is valid.
519 @pre The delimiter must have been set.
520 @post The data will have been reduced to exclude the last segment.
522 EXPORT_C void CDelimitedDataBase8::PopBackL()
524 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
526 // Parse the string in reverse direction - sets last segment as current
527 iParser.ParseReverse(*iDataBuf);
529 // Remove the current segment
532 // Make sure that a re-parse is required
533 iParser.iMode = EDelimitedDataNotParsed;
537 Adds a new segment to the front of the data. The new segment can be made up of several segments
538 and have delimiters at either extreme. The insert functionality will ensure that there is always
539 a delimiter at the front of the new segment. The data must re-parsed to ensure that the parser
542 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
543 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
544 been set. A re-parse is required to ensure that the parser is valid.
546 @param aSegment A descriptor with the new segment to be inserted.
547 @pre The delimiter must have been set.
548 @post The data will have been extended to include the new segment.
550 EXPORT_C void CDelimitedDataBase8::PushFrontL(const TDesC8& aSegment)
552 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
554 // Parse the string in forward direction - sets first segment as current
555 iParser.Parse(*iDataBuf);
557 // Insert the segment
560 // Make sure that a re-parse is required
561 iParser.iMode = EDelimitedDataNotParsed;
565 Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
567 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
568 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
569 been set. A re-parse is required to ensure that the parser is valid.
571 @pre The delimiter must have been set.
572 @post The data will have been reduced to exclude the last segment.
574 EXPORT_C void CDelimitedDataBase8::PopFrontL()
576 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
578 // Parse the string in forward direction - sets first segment as current
579 iParser.Parse(*iDataBuf);
581 // Remove the current segment
584 // Make sure that a re-parse is required
585 iParser.iMode = EDelimitedDataNotParsed;
589 Removes the front delimiter (if exists) from the data.
591 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
592 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
593 been set. A re-parse is required to ensure that the parser is valid.
595 @pre The delimiter must have been set.
596 @post The data might have been reduced to exclude the front delimiter.
598 EXPORT_C void CDelimitedDataBase8::TrimFrontDelimiterL()
600 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
602 // Search for delimiter
603 if( iParser.FrontDelimiter() )
605 // Remove front delimiter and update member data
606 SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
608 // Make sure that a re-parse is required
609 iParser.iMode = EDelimitedDataNotParsed;
613 Adds a delimiter to the front of the data (if it doesn't exist).
615 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
616 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
617 been set. A re-parse is required to ensure that the parser is valid.
619 @pre The delimiter must have been set.
620 @post The data might have been extended to include a front delimiter.
622 EXPORT_C void CDelimitedDataBase8::AddFrontDelimiterL()
624 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
626 if( !iParser.FrontDelimiter() )
628 // Create a new buffer of correct size
629 HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
630 TPtr8 str = buf->Des();
632 // Append a delimiter, then append the current string
633 str.Append(iParser.iDelimiter);
634 str.Append(iParser.iDataDes);
636 // Set buffer to this new string
639 // Make sure that a re-parse is required
640 iParser.iMode = EDelimitedDataNotParsed;
644 Removes the back delimiter (if exists) from the data.
646 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
647 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
648 been set. A re-parse is required to ensure that the parser is valid.
650 @pre The delimiter must have been set.
651 @post The data might have been reduced to exclude the front delimiter.
653 EXPORT_C void CDelimitedDataBase8::TrimBackDelimiterL()
655 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
657 // Search for delimiter
658 if( iParser.BackDelimiter() )
660 // Remove back delimiter and update member data
661 SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
663 // Make sure that a re-parse is required
664 iParser.iMode = EDelimitedDataNotParsed;
668 Adds a delimiter to the back of the data (if it doesn't exist).
670 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
671 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
672 been set. A re-parse is required to ensure that the parser is valid.
674 @pre The delimiter must have been set.
675 @post The data might have been extended to include a front delimiter.
677 EXPORT_C void CDelimitedDataBase8::AddBackDelimiterL()
679 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
681 if( !iParser.BackDelimiter() )
683 // Create a new buffer of correct size
684 HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
685 TPtr8 str = buf->Des();
687 // Append the current string, then append a delimiter
688 str.Append(iParser.iDataDes);
689 str.Append(iParser.iDelimiter);
691 // Set buffer to this new string
694 // Make sure that a re-parse is required
695 iParser.iMode = EDelimitedDataNotParsed;
699 This parses the data into segments from left to right.
701 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
704 @pre The delimiter must have been set.
705 @post The current segment is the leftmost segment and the direction of
706 parsing is set from left to right (EDelimitedDataFroward).
708 EXPORT_C void CDelimitedDataBase8::Parse()
710 // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
711 iParser.Parse(*iDataBuf);
715 This parses the string into segments from right to left.
718 @pre The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
719 the delimiter has not been initialized.
720 @post The current segment is the leftmost segment and the direction of parsing is right to left.
722 EXPORT_C void CDelimitedDataBase8::ParseReverse()
724 // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
725 iParser.ParseReverse(*iDataBuf);
729 Retrieves a const reference to the delimited data parser.
732 @return A const reference to the delimited data parser.
734 EXPORT_C const TDelimitedParserBase8& CDelimitedDataBase8::Parser() const
740 Sets the delimiting character.
743 @param aDelimiter The delimiting character.
744 @post The delimiting character is updated.
746 EXPORT_C void CDelimitedDataBase8::SetDelimiter(TChar aDelimiter)
748 iParser.SetDelimiter(aDelimiter);
752 Constructor. First phase of two-phase construction method. Does non-allocating construction.
756 EXPORT_C CDelimitedDataBase8::CDelimitedDataBase8()
761 Second phase of two-phase construction method. Does any allocations required to fully construct
765 @param aData A descriptor with the initial string.
766 @pre First phase of construction is complete.
767 @post The object is fully constructed.
769 EXPORT_C void CDelimitedDataBase8::ConstructL(const TDesC8& aData)
771 // Create copy of string and set descriptor in the parser
776 Inserts the new segment in a position before the current segment. The new segment can be made up
777 of several segments and have delimiters at either extreme. The insert functionality will ensure
778 that there is always a delimiter at the front of the new segment. The parser will be left in a
779 state where its current segment is the same one as before the insertion.
782 @param aSegment The descriptor with the segment to be inserted.
783 @pre The string must have been parsed.
784 @post The string will have been extended to include the new segment. The current segment will
785 remain as the one before the insertion.
787 void CDelimitedDataBase8::DoInsertL(const TDesC8& aSegment)
789 // Get previous delimiter to split the current string into prefix and suffix to the new segment
790 TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
791 TPtrC8 prefix = iParser.iDataDes.Left(prevPos);
793 TInt suffixLength = iParser.iDataDes.Length() - prevPos;
794 TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
795 if( suffixLength && suffix[0] == iParser.iDelimiter )
797 // Remove front delimiter on suffix
798 suffix.Set(suffix.Right(--suffixLength));
801 // Check for delimiters
802 TPtrC8 segment = aSegment;
803 TInt segmentLength = segment.Length();
804 TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
805 if( segmentBackDelimiter )
807 // Remove back delimiter from the segment
808 segment.Set(segment.Left(--segmentLength));
810 if( segmentLength && segment[0] == iParser.iDelimiter )
812 // Remove front delimiter from the segment
813 segment.Set(segment.Right(--segmentLength));
816 // Check if a back delimiter is needed - NOTE always add a front delimiter
818 TBool needBackDelimiter = EFalse;
819 if( suffix.Length() || segmentBackDelimiter )
822 needBackDelimiter = ETrue;
824 // Create space for new string
825 HBufC8* buf = HBufC8::NewL(prevPos + segmentLength + suffixLength + extra);
826 TPtr8 str = buf->Des();
828 // Form the new string
830 str.Append(iParser.iDelimiter);
832 if( needBackDelimiter )
833 str.Append(iParser.iDelimiter);
836 // Update string data
839 // Check to see if the internal parser object (iParser) has been parsed
840 // (can tell if it has if the data pointer in iCurrentSegment is not NULL)
841 // If so update iCurrentSegment to ensure that iParser remains valid
842 if( iParser.iCurrentSegment.Ptr() )
844 // Ensure parser is in correct position and current segment is correct
845 iParser.iNextSegmentPos = prevPos;
846 if( iParser.iMode == EDelimitedDataForward )
848 // Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
849 iParser.iNextSegmentPos += segmentLength + 1;
851 // Get the next segment
852 iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
857 Removes the current segment. After removing the segment, the parser's new current segment will be
858 the next segment. If the last segment is the one that is removed then the parser will be set to the
862 @pre The data must have been parsed.
863 @post The data will have been reduced to exclude the removed data. The
864 current segment is set to what was the next segment. If the removed segment was
865 the last segment, the parser is at the end of the data.
867 void CDelimitedDataBase8::DoRemoveL()
869 // Check if there is anything to remove
870 if( iParser.iDataDes.Length() == 0 )
874 // Find the previous delimiter
875 TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
877 // Set up the start and end position of current segment
878 TInt endPos = iParser.iNextSegmentPos;
879 TInt startPos = iParser.iNextSegmentPos;
880 if( prev < iParser.iNextSegmentPos )
885 // Ok, get the prefix and suffix parts
886 TPtrC8 prefix = iParser.iDataDes.Left(startPos);
887 TInt suffixLength = iParser.iDataDes.Length() - endPos;
888 TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
891 HBufC8* buf = HBufC8::NewL(startPos + suffixLength);
892 TPtr8 str = buf->Des();
894 // Form the new string
898 // Update string data
901 // Ensure parser is in correct position
902 iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
906 Updates internal data buffer with the new data. Creates a copy of the new data.
909 @param aData A descriptor with the new string.
910 @post The internal data buffer now contains a copy of the new data and the
911 parser is set to the new data.
913 void CDelimitedDataBase8::SetDataL(const TDesC8& aData)
915 // Cleanup old data and set new
916 HBufC8* buf = aData.AllocL();
921 Sets internal data buffer and parser. Cleans up the old data and uses the data buffer.
922 The parser is set to the new data.
925 @param aDataBuf A pointer to a decriptor buffer with the new data.
926 @post The internal data buffer now points to the new buffer and the parser
927 is set to the data in the new buffer..
929 void CDelimitedDataBase8::SetData(HBufC8* aDataBuf)
933 iParser.iDataDes.Set(*iDataBuf);
938 // Implementation of TDelimitedParserBase16
946 EXPORT_C TDelimitedParserBase16::TDelimitedParserBase16()
947 : iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
952 Resets the internal pointer position to the start or end or the descriptor depending
953 on whether the decriptor is parsing mode.
955 @warning There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has
956 not been correctly set.
958 EXPORT_C void TDelimitedParserBase16::Reset() const
960 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
961 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
963 iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
966 Retrieves the current segment and then parses the data to the next one.
968 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
969 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
971 @param aSegment This is an output argument that is set to the current segment.
972 @return A error value of KErrNotFound if there is no current segment. The
973 value KErrNone if there is a current segment.
974 @pre The string must have been initially parsed by Parse() or ParseReverse().
975 @post The current segment is updated to the next one.
977 EXPORT_C TInt TDelimitedParserBase16::GetNext(TPtrC16& aSegment) const
979 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
980 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
982 // Check that there is a segment
983 if( iNextSegmentPos == KErrNotFound )
985 // There is no segment
988 // There is one - set aSegment
989 aSegment.Set(iCurrentSegment);
990 // Parse the next segment
991 iNextSegmentPos = FindNextSegment(iNextSegmentPos);
996 Parses to the next segment.
998 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
999 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1001 @return A error value of KErrNotFound if there is no current segment. The
1002 value KErrNone if there is a current segment.
1003 @pre The string must have been initially parsed by Parse() or ParseReverse().
1004 @post The current segment is updated to the next one.
1006 EXPORT_C TInt TDelimitedParserBase16::Inc() const
1008 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1009 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1011 // Check that there is a segment
1012 if( iNextSegmentPos == KErrNotFound )
1014 // There is no segment
1015 return KErrNotFound;
1017 // Parse the next segment
1018 iNextSegmentPos = FindNextSegment(iNextSegmentPos);
1023 Parses back to the previous segment.
1025 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1026 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1028 @return A error value of KErrNotFound if the current segment is the initial
1029 segment. The value KErrNone if the data has been parsed to the previous segment.
1030 @pre The string must have been initially parsed by Parse() or ParseReverse().
1031 @post If the parse was successful then the current segment is updated
1032 to the previous one. Otherwise there is no change.
1034 EXPORT_C TInt TDelimitedParserBase16::Dec() const
1036 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1037 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1039 // Find position of previous delimiter
1040 TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1042 // Get the previous segment
1043 if( FindPrevSegment(prev) == KErrNotFound )
1045 // There is no previous segment - set to start of data
1046 return KErrNotFound;
1048 // Update next segment position
1049 iNextSegmentPos = prev;
1054 Retrieves the current segment.
1056 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1057 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1059 @param aSegment This is an output argument that is set to the current segment.
1060 @return A error value of KErrNotFound if there is no current segment. The
1061 value KErrNone if there is a current segment.
1062 @pre The string must have been initially parsed by Parse() or ParseReverse().
1064 EXPORT_C TInt TDelimitedParserBase16::Peek(TPtrC16& aSegment) const
1066 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1067 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1069 // Check that there is a segment
1070 if( iNextSegmentPos == KErrNotFound )
1072 // There is no segment
1073 return KErrNotFound;
1075 // There is one - set aSegment
1076 aSegment.Set(iCurrentSegment);
1081 Indicates whether the end of the data has been reached and there are no more segments to parse.
1083 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1084 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1086 @return A boolean value of ETrue if the end of the data has been reached,
1087 or EFalse if there are more segements to parse.
1088 @pre The string must have been initially parsed by Parse() or ParseReverse().
1090 EXPORT_C TBool TDelimitedParserBase16::Eos() const
1092 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1094 TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
1099 Checks for a delimiter at the front (left) of the data.
1101 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1102 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1104 @return A boolean of value ETrue if there is a front delimiter, or EFalse
1105 if there is no front delimiter.
1106 @pre The string must have been initially parsed by Parse() or ParseReverse().
1108 EXPORT_C TBool TDelimitedParserBase16::FrontDelimiter() const
1110 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1112 return (iDataDes.Locate(iDelimiter) == 0);
1116 Checks for a delimiter at the back (right) of the data.
1118 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1119 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1121 @return A boolean of value ETrue if there is a back delimiter, or EFalse
1122 if there is no back delimiter.
1123 @pre The string must have been initially parsed by Parse() or ParseReverse().
1125 EXPORT_C TBool TDelimitedParserBase16::BackDelimiter() const
1127 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1129 TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
1130 if( delimiterPos == KErrNotFound )
1132 return (delimiterPos == iDataDes.Length() - 1);
1136 Retrieves the descriptor reference with the data
1139 @return A const descriptor reference with the data.
1141 EXPORT_C const TDesC16& TDelimitedParserBase16::Des() const
1147 Gives the remainder of the data from (and including) the current segment. Any other segments that
1148 have parsed through are not included.
1150 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1151 and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1153 @param aRemainder This is an output argument that is set to the remaining data.
1154 @return An error value of KErrNotFound if there is no remaining data, or value of KErrNone
1155 if there is remaining data.
1156 @pre The data must have been initially parsed by Parse() or ParseReverse().
1158 EXPORT_C TInt TDelimitedParserBase16::Remainder(TPtrC16& aRemainder) const
1160 __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1161 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1163 // Check to see if there is a segment left
1164 if( iNextSegmentPos == KErrNotFound )
1166 // There is no segment
1167 return KErrNotFound;
1169 // Find the previous delimiter -> the start of the current segment
1170 TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1172 // Need to see which direction the parsing is going to set the remainder
1175 case EDelimitedDataForward:
1177 aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
1179 case EDelimitedDataReverse:
1181 aRemainder.Set(iDataDes.Left(prev));
1185 User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1192 This parses the data into segments from left to right.
1194 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1197 @param aData A descriptor containing the data.
1198 @pre The delimiter must have been set.
1199 @post The current segment is the leftmost segment and the direction of
1200 parsing is set from left to right (EDelimitedDataFroward).
1202 EXPORT_C void TDelimitedParserBase16::Parse(const TDesC16& aData)
1204 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1206 // Initialise data for EForward direction
1207 iMode = EDelimitedDataForward;
1212 This parses the data into segments from lright to left.
1214 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1217 @param aData A descriptor containing the data.
1218 @pre The delimiter must have been set.
1219 @post The current segment is the leftmost segment and the direction of
1220 parsing is set from right to left (EDelimitedDataReverse).
1222 EXPORT_C void TDelimitedParserBase16::ParseReverse(const TDesC16& aData)
1224 __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1226 // Initialise data for EReverse direction
1227 iMode = EDelimitedDataReverse;
1232 Sets the delimiting character.
1235 @param aDelimiter The delimiting character.
1236 @post The delimiting character is set.
1238 EXPORT_C void TDelimitedParserBase16::SetDelimiter(TChar aDelimiter)
1240 iDelimiter = aDelimiter;
1244 Initialises the parsing of the data.
1247 @param aData A descriptor reference with the data.
1248 @pre The delimiting character has been set.
1249 @post The data descriptor is set to the input argument. The current segment
1250 refers to the initial segment of the data.
1252 void TDelimitedParserBase16::DoParse(const TDesC16& aData)
1254 // Reset the segment information, then set the new Data - set pointer to NULL and length to zero
1255 iCurrentSegment.Set(NULL,0);
1256 iDataDes.Set(aData);
1258 // Check that there is a string!
1259 if( iDataDes.Length() == 0 )
1261 // No string - ensure functionality blocked for this descriptor
1262 iNextSegmentPos = KErrNotFound;
1265 // Find the segment - search from initial start position
1266 iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
1270 Finds the next segment from the given start position.
1273 @param aStartPos The position from where to start the search for the
1275 @return The position of delimiter after the specified start position, or
1276 an error value of KErrNotFound if no more delimiters are found.
1278 TInt TDelimitedParserBase16::FindNextSegment(TInt aStartPos) const
1280 // Find position of next delimiter
1281 TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1283 if( next != KErrNotFound )
1285 TInt startPos = next < aStartPos ? next : aStartPos;
1286 TInt endPos = next < aStartPos ? aStartPos : next;
1287 if( iDataDes[startPos] == iDelimiter )
1289 // Move past delimiter
1292 TInt length = endPos - startPos;
1293 iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1299 Finds the previous segment from the given start position.
1302 @param aStartPos The position from where to start the search for the
1304 @return The position of delimiter before the specified start position, or
1305 an error value of KErrNotFound if no more delimiters are found.
1307 TInt TDelimitedParserBase16::FindPrevSegment(TInt aStartPos) const
1309 // Find position of previous delimiter
1310 TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1312 if( prev != KErrNotFound )
1314 TInt startPos = prev < aStartPos ? prev : aStartPos;
1315 TInt endPos = prev < aStartPos ? aStartPos : prev;
1316 if( iDataDes[startPos] == iDelimiter )
1318 // Move past delimiter
1321 TInt length = endPos - startPos;
1322 iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1329 // Implementation of CDelimitedDataBase16
1338 EXPORT_C CDelimitedDataBase16::~CDelimitedDataBase16()
1344 Inserts the new segment in a position before the current parsed segment. The new segment can be
1345 made up of several segments and have delimiters at either extreme. The insert functionality will
1346 ensure that there is always a delimiter at the front of the new segment. The parser is left in a
1347 state where its current segment is the same one as before the insertion.
1349 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1350 and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1352 @param aSegment A descriptor with the new segment to be inserted.
1353 @pre The data must have been initially parsed by Parse() or ParseReverse().
1354 @post The data will have been extended to include the new segment. The current segment
1355 will remain as the one before the insertion.
1357 EXPORT_C void CDelimitedDataBase16::InsertCurrentL(const TDesC16& aSegment)
1359 __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1360 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1362 DoInsertL(aSegment);
1366 Removes the current segment. After removing the segment, the parser's new current segment will be the
1367 next segment. If the last segment is the one that is removed then the parser will be set to the end of
1370 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and
1371 a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1373 @pre The data must have been initially parsed by Parse() or ParseReverse().
1374 @post The data will have been reduced to exclude the removed segment. The current segment will
1375 be set to what was the next segment. If the removed segment was the last segment, the parser is at the end
1378 EXPORT_C void CDelimitedDataBase16::RemoveCurrentL()
1380 __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1381 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1387 Adds a new segment to the end of the data. The new segment can be made up of several segments and have
1388 delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at
1389 the front of the new segment. The data must re-parsed to ensure that the parser is valid.
1391 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and a
1392 KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure
1393 that the parser is valid.
1395 @param aSegment A descriptor with the new segment to be inserted.
1396 @pre The delimiter must have been set.
1397 @post The data will have been extended to include the new segment.
1399 EXPORT_C void CDelimitedDataBase16::PushBackL(const TDesC16& aSegment)
1401 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1403 // Parse the string in reverse direction - sets last segment as current
1404 iParser.ParseReverse(*iDataBuf);
1406 // Insert the segment
1407 DoInsertL(aSegment);
1409 // Make sure that a re-parse is required
1410 iParser.iMode = EDelimitedDataNotParsed;
1414 Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
1416 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1417 and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required
1418 to ensure that the parser is valid.
1420 @pre The delimiter must have been set.
1421 @post The data will have been reduced to exclude the last segment.
1423 EXPORT_C void CDelimitedDataBase16::PopBackL()
1425 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1427 // Parse the string in reverse direction - sets last segment as current
1428 iParser.ParseReverse(*iDataBuf);
1430 // Remove the current segment
1433 // Make sure that a re-parse is required
1434 iParser.iMode = EDelimitedDataNotParsed;
1439 Adds a new segment to the front of the data. The new segment can be made up of several segments and have
1440 delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at
1441 the front of the new segment. The data must re-parsed to ensure that the parser is valid.
1443 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and
1444 a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure
1445 that the parser is valid.
1447 @param aSegment A descriptor with the new segment to be inserted.
1448 @pre The delimiter must have been set.
1449 @post The data will have been extended to include the new segment.
1451 EXPORT_C void CDelimitedDataBase16::PushFrontL(const TDesC16& aSegment)
1453 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1455 // Parse the string in forward direction - sets first segment as current
1456 iParser.Parse(*iDataBuf);
1458 // Insert the segment
1459 DoInsertL(aSegment);
1461 // Make sure that a re-parse is required
1462 iParser.iMode = EDelimitedDataNotParsed;
1466 Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
1468 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been
1469 parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse
1470 is required to ensure that the parser is valid.
1472 @pre The delimiter must have been set.
1473 @post The data will have been reduced to exclude the last segment.
1475 EXPORT_C void CDelimitedDataBase16::PopFrontL()
1477 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1479 // Parse the string in forward direction - sets first segment as current
1480 iParser.Parse(*iDataBuf);
1482 // Remove the current segment
1485 // Make sure that a re-parse is required
1486 iParser.iMode = EDelimitedDataNotParsed;
1491 Removes the front delimiter (if exists) from the data.
1493 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1494 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1495 been set. A re-parse is required to ensure that the parser is valid.
1497 @pre The delimiter must have been set.
1498 @post The data might have been reduced to exclude the front delimiter.
1500 EXPORT_C void CDelimitedDataBase16::TrimFrontDelimiterL()
1502 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1504 // Search for delimiter
1505 if( iParser.FrontDelimiter() )
1507 // Remove front delimiter and update member data
1508 SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
1510 // Make sure that a re-parse is required
1511 iParser.iMode = EDelimitedDataNotParsed;
1515 Adds a delimiter to the front of the data (if it doesn't exist).
1517 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1518 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1519 A re-parse is required to ensure that the parser is valid.
1521 @pre The delimiter must have been set.
1522 @post The data might have been extended to include a front delimiter.
1524 EXPORT_C void CDelimitedDataBase16::AddFrontDelimiterL()
1526 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1528 if( !iParser.FrontDelimiter() )
1530 // Create a new buffer of correct size
1531 HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
1532 TPtr16 str = buf->Des();
1534 // Append a delimiter, then append the current string
1535 str.Append(iParser.iDelimiter);
1536 str.Append(iParser.iDataDes);
1538 // Set buffer to this new string
1541 // Make sure that a re-parse is required
1542 iParser.iMode = EDelimitedDataNotParsed;
1546 Removes the back delimiter (if exists) from the data.
1548 @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1549 not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1550 been set. A re-parse is required to ensure that the parser is valid.
1552 @pre The delimiter must have been set.
1553 @post The data might have been reduced to exclude the front delimiter.
1555 EXPORT_C void CDelimitedDataBase16::TrimBackDelimiterL()
1557 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1559 // Search for delimiter
1560 if( iParser.BackDelimiter() )
1562 // Remove back delimiter and update member data
1563 SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
1565 // Make sure that a re-parse is required
1566 iParser.iMode = EDelimitedDataNotParsed;
1570 Adds a delimiter to the back of the data (if it doesn't exist).
1572 @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1573 been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1574 A re-parse is required to ensure that the parser is valid.
1576 @pre The delimiter must have been set.
1577 @post The data might have been extended to include a front delimiter.
1579 EXPORT_C void CDelimitedDataBase16::AddBackDelimiterL()
1581 __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1583 if( !iParser.BackDelimiter() )
1585 // Create a new buffer of correct size
1586 HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
1587 TPtr16 str = buf->Des();
1589 // Append the current string, then append a delimiter
1590 str.Append(iParser.iDataDes);
1591 str.Append(iParser.iDelimiter);
1593 // Set buffer to this new string
1596 // Make sure that a re-parse is required
1597 iParser.iMode = EDelimitedDataNotParsed;
1601 This parses the data into segments from left to right.
1603 @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1606 @pre The delimiter must have been set.
1607 @post The current segment is the leftmost segment and the direction of
1608 parsing is set from left to right (EDelimitedDataFroward).
1610 EXPORT_C void CDelimitedDataBase16::Parse()
1612 // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1613 iParser.Parse(*iDataBuf);
1617 This parses the string into segments from right to left.
1620 @pre The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
1621 the delimiter has not been initialized.
1622 @post The current segment is the leftmost segment and the direction of parsing is right to left.
1624 EXPORT_C void CDelimitedDataBase16::ParseReverse()
1626 // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1627 iParser.ParseReverse(*iDataBuf);
1631 Retrieves a const reference to the delimited data parser.
1634 @return A const reference to the delimited data parser.
1636 EXPORT_C const TDelimitedParserBase16& CDelimitedDataBase16::Parser() const
1642 Sets the delimiting character.
1645 @param aDelimiter The delimiting character.
1646 @post The delimiting character is updated.
1648 EXPORT_C void CDelimitedDataBase16::SetDelimiter(TChar aDelimiter)
1650 iParser.SetDelimiter(aDelimiter);
1654 Constructor. First phase of two-phase construction method. Does non-allocating construction.
1658 EXPORT_C CDelimitedDataBase16::CDelimitedDataBase16()
1663 Second phase of two-phase construction method. Does any allocations required to fully construct
1667 @param aData A descriptor with the initial string.
1668 @pre First phase of construction is complete.
1669 @post The object is fully constructed.
1671 EXPORT_C void CDelimitedDataBase16::ConstructL(const TDesC16& aData)
1673 // Create copy of string and set descriptor in the parser
1678 Inserts the new segment in a position before the current segment. The new segment can be made up of
1679 several segments and have delimiters at either extreme. The insert functionality will ensure that
1680 there is always a delimiter at the front of the new segment. The parser will be left in a state where
1681 its current segment is the same one as before the insertion.
1684 @param aSegment The descriptor with the segment to be inserted.
1685 @pre The string must have been parsed.
1686 @post The string will have been extended to include the new segment. The current segment will
1687 remain as the one before the insertion.
1689 void CDelimitedDataBase16::DoInsertL(const TDesC16& aSegment)
1691 TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1692 TPtrC16 prefix = iParser.iDataDes.Left(prevPos);
1694 TInt suffixLength = iParser.iDataDes.Length() - prevPos;
1695 TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
1696 if( suffixLength && suffix[0] == iParser.iDelimiter )
1698 // Remove front delimiter on suffix
1699 suffix.Set(suffix.Right(--suffixLength));
1702 // Check for delimiters...
1703 TPtrC16 segment = aSegment;
1704 TInt segmentLength = segment.Length();
1705 // Check the last character in segment
1706 TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
1707 if( segmentBackDelimiter )
1709 // Remove back delimiter from the segment
1710 segment.Set(segment.Left(--segmentLength));
1712 // Check the first character in segment...
1713 if( segmentLength && segment[0] == iParser.iDelimiter )
1715 // Remove front delimiter from the segment
1716 segment.Set(segment.Right(--segmentLength));
1719 // Check if a back delimiter is needed - NOTE always add a front delimiter
1721 TBool needBackDelimiter = EFalse;
1722 if( suffix.Length() || segmentBackDelimiter )
1725 needBackDelimiter = ETrue;
1727 // Create space for new string
1728 HBufC16* buf = HBufC16::NewL(prevPos + segmentLength + suffixLength + extra);
1729 TPtr16 str = buf->Des();
1731 // Form the new string
1733 str.Append(iParser.iDelimiter);
1734 str.Append(segment);
1735 if( needBackDelimiter )
1736 str.Append(iParser.iDelimiter);
1739 // Update string data
1742 // Check to see if the internal parser object (iParser) has been parsed
1743 // (can tell if it has if the data pointer in iCurrentSegment is not NULL)
1744 // If so update iCurrentSegment to ensure that iParser remains valid
1745 if( iParser.iCurrentSegment.Ptr() )
1747 // Ensure parser is in correct position and current segment is correct
1748 iParser.iNextSegmentPos = prevPos;
1749 if( iParser.iMode == EDelimitedDataForward )
1751 // Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
1752 iParser.iNextSegmentPos += segmentLength + 1;
1754 // Get the next segment
1755 iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
1760 Removes the current segment. After removing the segment, the parser's new current segment will be the
1761 next segment. If the last segment is the one that is removed then the parser will be set to the end of
1765 @pre The data must have been parsed.
1766 @post The data will have been reduced to exclude the removed data. The current segment
1767 is set to what was the next segment. If the removed segment was the last segment, the parser is
1768 at the end of the data.
1770 void CDelimitedDataBase16::DoRemoveL()
1772 // Check if there is anything to remove
1773 if( iParser.iDataDes.Length() == 0 )
1777 // Find the previous delimiter
1778 TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1780 // Set up the start and end position of current segment
1781 TInt endPos = iParser.iNextSegmentPos;
1782 TInt startPos = iParser.iNextSegmentPos;
1783 if( prev < iParser.iNextSegmentPos )
1788 // Ok, get the prefix and suffix parts
1789 TPtrC16 prefix = iParser.iDataDes.Left(startPos);
1790 TInt suffixLength = iParser.iDataDes.Length() - endPos;
1791 TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
1794 HBufC16* buf = HBufC16::NewL(startPos + suffixLength);
1795 TPtr16 str = buf->Des();
1797 // Form the new string
1801 // Update string data
1804 // Ensure parser is in correct position
1805 iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
1809 Updates internal data buffer with the new data. Creates a copy of the new data.
1812 @param aData A descriptor with the new string.
1813 @post The internal data buffer now contains a copy of the new data and the
1814 parser is set to the new data.
1816 void CDelimitedDataBase16::SetDataL(const TDesC16& aData)
1818 // Cleanup old data and set new
1819 HBufC16* buf = aData.AllocL();
1824 Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. The
1825 parser is set to the new data.
1828 @param aDataBuf A pointer to a decriptor buffer with the new data.
1829 @post The internal data buffer now points to the new buffer and the parser
1830 is set to the data in the new buffer..
1832 void CDelimitedDataBase16::SetData(HBufC16* aDataBuf)
1835 iDataBuf = aDataBuf;
1836 iParser.iDataDes.Set(*iDataBuf);
1841 // Implementation of LOCAL functions
1846 Finds the position of the next delimiter in the data.
1849 @param aData A descriptor with the delimited data.
1850 @param aStartPos The position from where to start the search for the delimiter.
1851 @param aDelimiter The delimiting character.
1852 @param aMode The parsing mode.
1853 @return The position of delimiter after the specified start position, or
1854 an error value of KErrNotFound if no more delimiters are found.
1858 template<class TDesCType>
1859 TInt NextDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
1861 if( aStartPos == KErrNotFound )
1863 // Have got to the end - initialise the iterator
1864 return InitialDelimiterPosition(aData, aMode);
1866 TInt next = KErrNotFound;
1869 case EDelimitedDataForward:
1871 // Search parsed string for next delimiter
1872 next = LeftDelimiterPosition(aData, aStartPos, aDelimiter);
1874 case EDelimitedDataReverse:
1876 // Search parsed string for next delimiter
1877 next = RightDelimiterPosition(aData, aStartPos, aDelimiter);
1881 User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1889 Finds the position of the previous delimiter in the data from the given start position.
1892 @param aData A descriptor with the delimited data.
1893 @param aStartPos The position from where to start the search for the delimiter.
1894 @param aDelimiter The delimiting character.
1895 @param aMode The parsing mode.
1896 @return The position of delimiter before the specified start position, or
1897 an error value of KErrNotFound if no more delimiters are found.
1901 template<class TDesCType>
1902 TInt PrevDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
1904 // Switch modes, then find the next delimiter, switch back
1905 TDelimitedDataParseMode mode = aMode == EDelimitedDataForward ? EDelimitedDataReverse : EDelimitedDataForward;
1906 return NextDelimiterPosition(aData, aStartPos, aDelimiter, mode);
1910 Finds the position of the delimiter to the right of the given start position.
1913 @param aData A descriptor with the delimited data.
1914 @param aStartPos The position from where to start the search for the delimiter.
1915 @param aDelimiter The delimiting character.
1916 @return The position of delimiter to the right of the specified start position, or
1917 an error value of KErrNotFound if no more delimiters are found.
1921 template<class TDesCType>
1922 TInt RightDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
1924 // Find position of right-most delimiter in the descriptor data to left of aStartPos
1925 if( aStartPos == 0 )
1928 return KErrNotFound;
1930 TInt rightDelimiterPos = aData.Left(aStartPos).LocateReverse(aDelimiter);
1932 // See if a delimiter was found
1933 if( rightDelimiterPos == KErrNotFound )
1935 // No - start of string delimits
1936 rightDelimiterPos = 0;
1938 return rightDelimiterPos;
1942 Finds the position of the delimiter to the left of the given start position.
1945 @param aData A descriptor with the delimited data.
1946 @param aStartPos The position from where to start the search for the delimiter.
1947 @param aDelimiter The delimiting character.
1948 @return The position of delimiter to the left of the specified start position, or
1949 an error value of KErrNotFound if no more delimiters are found.
1953 template<class TDesCType>
1954 TInt LeftDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
1956 // Find position of left-most delimiter in the descriptor data to right of aStartPos
1957 const TInt length = aData.Length();
1958 TInt rightLength = length - aStartPos;
1959 if( rightLength == 0 )
1962 return KErrNotFound;
1964 // Ok there is some string to search - remove delimiter
1966 TInt leftDelimiterPos = aData.Right(rightLength).Locate(aDelimiter);
1968 // See if a delimiter was found
1969 if( leftDelimiterPos == KErrNotFound )
1971 // No - end of string delimits
1972 leftDelimiterPos = length;
1976 // Offset the delimiter found - include delimiter that was removed
1977 leftDelimiterPos += aStartPos + 1;
1979 return leftDelimiterPos;
1983 Retrieves the initial position for searching delimited data for a given parsing mode.
1986 @param aData A descriptor with the delimited data.
1987 @param aMode The parsing mode.
1988 @return The initial position for parsing the data.
1992 template<class TDesCType>
1993 TInt InitialDelimiterPosition(const TDesCType& aData, TDelimitedDataParseMode aMode)
1995 // Initialises iNextSegmentPos
1997 TInt initPos = KErrNotFound;
2000 case EDelimitedDataForward:
2002 // Search parsed string for next delimiter
2005 case EDelimitedDataReverse:
2007 // Search parsed string for next delimiter
2008 initPos = aData.Length();
2012 User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);