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