1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericservices/httputils/DelimitedParser/DelimitedParser.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,2017 @@
1.4 +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <delimitedparser8.h>
1.20 +#include <delimitedparser16.h>
1.21 +#include "DelimitedParserInternal.h"
1.22 +#include <uriutilscommon.h>
1.23 +
1.24 +// Panic category
1.25 +//
1.26 +_LIT(KDelimitedParserPanicCategory,"DELIM-PARSER");
1.27 +
1.28 +//
1.29 +//
1.30 +// Implementation of TDelimitedParserBase8
1.31 +//
1.32 +//
1.33 +
1.34 +/**
1.35 + Constructor.
1.36 +
1.37 + @since 6.0
1.38 +*/
1.39 +EXPORT_C TDelimitedParserBase8::TDelimitedParserBase8()
1.40 +: iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
1.41 + {
1.42 + }
1.43 +
1.44 +/**
1.45 + Resets the internal pointer position to the start or end or the descriptor
1.46 + depending on whether the decriptor is parsing mode.
1.47 +
1.48 + @warning There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has
1.49 + not been correctly set.
1.50 + */
1.51 +EXPORT_C void TDelimitedParserBase8::Reset() const
1.52 + {
1.53 + iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
1.54 + }
1.55 +
1.56 +/**
1.57 + Retrieves the current segment and then parses the data to the next one.
1.58 +
1.59 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.60 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.61 + been set.
1.62 + @since 6.0
1.63 + @param aSegment This is an output argument that is set to the current segment.
1.64 + @return A error value of KErrNotFound if there is no current segment. The
1.65 + value KErrNone if there is a current segment.
1.66 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.67 + @post The current segment is updated to the next one.
1.68 +*/
1.69 +EXPORT_C TInt TDelimitedParserBase8::GetNext(TPtrC8& aSegment) const
1.70 + {
1.71 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.72 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.73 +
1.74 + // Check that there is a segment
1.75 + if( iNextSegmentPos == KErrNotFound )
1.76 + {
1.77 + // There is no segment
1.78 + return KErrNotFound;
1.79 + }
1.80 + // There is one - set aSegment
1.81 + aSegment.Set(iCurrentSegment);
1.82 + // Parse the next segment
1.83 + iNextSegmentPos = FindNextSegment(iNextSegmentPos);
1.84 + return KErrNone;
1.85 + }
1.86 +
1.87 +/**
1.88 + Parses to the next segment.
1.89 +
1.90 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.91 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.92 + been set.
1.93 + @since 6.0
1.94 + @return A error value of KErrNotFound if there is no current segment. The
1.95 + value KErrNone if there is a current segment.
1.96 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.97 + @post The current segment is updated to the next one.
1.98 + */
1.99 +EXPORT_C TInt TDelimitedParserBase8::Inc() const
1.100 + {
1.101 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.102 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.103 +
1.104 + // Check that there is a segment
1.105 + if( iNextSegmentPos == KErrNotFound )
1.106 + {
1.107 + // There is no segment
1.108 + return KErrNotFound;
1.109 + }
1.110 + // Parse the next segment
1.111 + iNextSegmentPos = FindNextSegment(iNextSegmentPos);
1.112 + return KErrNone;
1.113 + }
1.114 +
1.115 +/**
1.116 + Parses back to the previous segment.
1.117 +
1.118 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.119 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.120 + been set.
1.121 + @since 6.0
1.122 + @return A error value of KErrNotFound if the current segment is the initial
1.123 + segment. The value KErrNone if the data has been parsed to the previous segment.
1.124 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.125 + @post If the parse was successful then the current segment is updated
1.126 + to the previous one. Otherwise there is no change.
1.127 +*/
1.128 +EXPORT_C TInt TDelimitedParserBase8::Dec() const
1.129 + {
1.130 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.131 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.132 +
1.133 + // Find position of previous delimiter
1.134 + TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1.135 +
1.136 + // Get the previous segment
1.137 + if( FindPrevSegment(prev) == KErrNotFound )
1.138 + {
1.139 + // There is no previous segment - set to start of data
1.140 + return KErrNotFound;
1.141 + }
1.142 + // Update next segment position
1.143 + iNextSegmentPos = prev;
1.144 + return KErrNone;
1.145 + }
1.146 +
1.147 +/**
1.148 + Retrieves the current segment.
1.149 +
1.150 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.151 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.152 + been set.
1.153 + @since 6.0
1.154 + @param aSegment This is an output argument that is set to the current segment.
1.155 + @return A error value of KErrNotFound if there is no current segment. The
1.156 + value KErrNone if there is a current segment.
1.157 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.158 +*/
1.159 +EXPORT_C TInt TDelimitedParserBase8::Peek(TPtrC8& aSegment) const
1.160 + {
1.161 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.162 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.163 +
1.164 + // Check that there is a segment
1.165 + if( iNextSegmentPos == KErrNotFound )
1.166 + {
1.167 + // There is no segment
1.168 + return KErrNotFound;
1.169 + }
1.170 + // There is one - set aSegment
1.171 + aSegment.Set(iCurrentSegment);
1.172 + return KErrNone;
1.173 + }
1.174 +
1.175 +/**
1.176 + Indicates whether the end of the data has been reached and there are no more segments
1.177 + to parse.
1.178 +
1.179 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.180 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.181 + been set.
1.182 + @since 6.0
1.183 + @return A boolean value of ETrue if the end of the data has been reached,
1.184 + or EFalse if there are more segements to parse.
1.185 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.186 +*/
1.187 +EXPORT_C TBool TDelimitedParserBase8::Eos() const
1.188 + {
1.189 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.190 +
1.191 + TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
1.192 + return eos;
1.193 + }
1.194 +
1.195 +/**
1.196 + Checks for a delimiter at the front (left) of the data.
1.197 +
1.198 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.199 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.200 + @since 6.0
1.201 + @return A boolean of value ETrue if there is a front delimiter, or EFalse
1.202 + if there is no front delimiter.
1.203 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.204 +*/
1.205 +EXPORT_C TBool TDelimitedParserBase8::FrontDelimiter() const
1.206 + {
1.207 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.208 +
1.209 + return (iDataDes.Locate(iDelimiter) == 0);
1.210 + }
1.211 +
1.212 +/**
1.213 + Checks for a delimiter at the back (right) of the data.
1.214 +
1.215 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.216 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.217 + been set.
1.218 + @since 6.0
1.219 + @return A boolean of value ETrue if there is a back delimiter, or EFalse
1.220 + if there is no back delimiter.
1.221 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.222 +*/
1.223 +EXPORT_C TBool TDelimitedParserBase8::BackDelimiter() const
1.224 + {
1.225 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.226 +
1.227 + TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
1.228 + if( delimiterPos == KErrNotFound )
1.229 + return EFalse;
1.230 + return (delimiterPos == iDataDes.Length() - 1);
1.231 + }
1.232 +
1.233 +/**
1.234 + Retrieves the descriptor reference with the data
1.235 +
1.236 + @since 6.0
1.237 + @return A const descriptor reference with the data.
1.238 +*/
1.239 +EXPORT_C const TDesC8& TDelimitedParserBase8::Des() const
1.240 + {
1.241 + return iDataDes;
1.242 + }
1.243 +
1.244 +/**
1.245 + Gives the remainder of the data from (and including) the current segment. Any other segments
1.246 + that have parsed through are not included.
1.247 +
1.248 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.249 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.250 + been set.
1.251 + @since 6.0
1.252 + @param aRemainder This is an output argument that is set to the remaining data.
1.253 + @return An error value of KErrNotFound if there is no remaining data, or
1.254 + value of KErrNone if there is remaining data.
1.255 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.256 + */
1.257 +EXPORT_C TInt TDelimitedParserBase8::Remainder(TPtrC8& aRemainder) const
1.258 + {
1.259 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.260 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.261 +
1.262 + // Check to see if there is a segment left
1.263 + if( iNextSegmentPos == KErrNotFound )
1.264 + {
1.265 + // There is no segment
1.266 + return KErrNotFound;
1.267 + }
1.268 + // Find the previous delimiter -> the start of the current segment
1.269 + TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1.270 +
1.271 + // Need to see which direction the parsing is going to set the remainder
1.272 + switch(iMode)
1.273 + {
1.274 + case EDelimitedDataForward:
1.275 + {
1.276 + aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
1.277 + } break;
1.278 + case EDelimitedDataReverse:
1.279 + {
1.280 + aRemainder.Set(iDataDes.Left(prev));
1.281 + } break;
1.282 + default:
1.283 + // Bad mode!
1.284 + User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1.285 + break;
1.286 + }
1.287 + return KErrNone;
1.288 + }
1.289 +
1.290 +/**
1.291 + This parses the data into segments from left to right.
1.292 +
1.293 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.294 + has not been set.
1.295 + @since 6.0
1.296 + @param aData A descriptor containing the data.
1.297 + @pre The delimiter must have been set.
1.298 + @post The current segment is the leftmost segment and the direction of
1.299 + parsing is set from left to right (EDelimitedDataFroward).
1.300 + */
1.301 +EXPORT_C void TDelimitedParserBase8::Parse(const TDesC8& aData)
1.302 + {
1.303 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.304 +
1.305 + // Initialise data for EForward direction
1.306 + iMode = EDelimitedDataForward;
1.307 + DoParse(aData);
1.308 + }
1.309 +
1.310 +/**
1.311 + This parses the data into segments from lright to left.
1.312 +
1.313 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.314 + has not been set.
1.315 + @since 6.0
1.316 + @param aData A descriptor containing the data.
1.317 + @pre The delimiter must have been set.
1.318 + @post The current segment is the leftmost segment and the direction of
1.319 + parsing is set from right to left (EDelimitedDataReverse).
1.320 + */
1.321 +EXPORT_C void TDelimitedParserBase8::ParseReverse(const TDesC8& aData)
1.322 + {
1.323 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.324 +
1.325 + // Initialise data for EReverse direction
1.326 + iMode = EDelimitedDataReverse;
1.327 + DoParse(aData);
1.328 + }
1.329 +
1.330 +/**
1.331 + Sets the delimiting character.
1.332 +
1.333 + @since 6.0
1.334 + @param aDelimiter The delimiting character.
1.335 + @post The delimiting character is set.
1.336 +*/
1.337 +EXPORT_C void TDelimitedParserBase8::SetDelimiter(TChar aDelimiter)
1.338 + {
1.339 + iDelimiter = aDelimiter;
1.340 + }
1.341 +
1.342 +/**
1.343 + Initialises the parsing of the data.
1.344 +
1.345 + @since 6.0
1.346 + @param aData A descriptor reference with the data.
1.347 + @pre The delimiting character has been set.
1.348 + @post The data descriptor is set to the input argument. The current
1.349 + segment refers to the initial segment of the data.
1.350 +*/
1.351 +void TDelimitedParserBase8::DoParse(const TDesC8& aData)
1.352 + {
1.353 + // Reset the segment information, then set the new Data - set pointer to NULL and length to zero
1.354 + iCurrentSegment.Set(NULL,0);
1.355 + iDataDes.Set(aData);
1.356 +
1.357 + // Check that there is a string!
1.358 + if( iDataDes.Length() == 0 )
1.359 + {
1.360 + // No string - ensure functionality blocked for this descriptor
1.361 + iNextSegmentPos = KErrNotFound;
1.362 + return;
1.363 + }
1.364 + // Find the segment - search from initial start position
1.365 + iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
1.366 + }
1.367 +
1.368 +/**
1.369 + Finds the next segment from the given start position.
1.370 +
1.371 + @since 6.0
1.372 + @param aStartPos The position from where to start the search for the
1.373 + next segment.
1.374 + @return The position of delimiter after the specified start position, or
1.375 + an error value of KErrNotFound if no more delimiters are found.
1.376 +*/
1.377 +TInt TDelimitedParserBase8::FindNextSegment(TInt aStartPos) const
1.378 + {
1.379 + // Find position of next delimiter
1.380 + TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1.381 +
1.382 + if( next != KErrNotFound )
1.383 + {
1.384 + TInt startPos = next < aStartPos ? next : aStartPos;
1.385 + TInt endPos = next < aStartPos ? aStartPos : next;
1.386 + if( iDataDes[startPos] == iDelimiter )
1.387 + {
1.388 + // Move past delimiter
1.389 + ++startPos;
1.390 + }
1.391 + TInt length = endPos - startPos;
1.392 + iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1.393 + }
1.394 + return next;
1.395 + }
1.396 +
1.397 +/**
1.398 + Finds the previous segment from the given start position.
1.399 +
1.400 + @since 6.0
1.401 + @param aStartPos The position from where to start the search for the
1.402 + previous segment.
1.403 + @return The position of delimiter before the specified start position, or
1.404 + an error value of KErrNotFound if no more delimiters are found.
1.405 +*/
1.406 +TInt TDelimitedParserBase8::FindPrevSegment(TInt aStartPos) const
1.407 + {
1.408 + // Find position of previous delimiter
1.409 + TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1.410 +
1.411 + if( prev != KErrNotFound )
1.412 + {
1.413 + TInt startPos = prev < aStartPos ? prev : aStartPos;
1.414 + TInt endPos = prev < aStartPos ? aStartPos : prev;
1.415 + if( iDataDes[startPos] == iDelimiter )
1.416 + {
1.417 + // Move past delimiter
1.418 + ++startPos;
1.419 + }
1.420 + TInt length = endPos - startPos;
1.421 + iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1.422 + }
1.423 + return prev;
1.424 + }
1.425 +
1.426 +//
1.427 +//
1.428 +// Implementation of CDelimitedDataBase8
1.429 +//
1.430 +//
1.431 +
1.432 +/**
1.433 + Destructor.
1.434 +
1.435 + @since 6.0
1.436 +*/
1.437 +EXPORT_C CDelimitedDataBase8::~CDelimitedDataBase8()
1.438 + {
1.439 + delete iDataBuf;
1.440 + }
1.441 +
1.442 +/**
1.443 + Inserts the new segment in a position before the current parsed segment. The new
1.444 + segment can be made up of several segments and have delimiters at either extreme.
1.445 + The insert functionality will ensure that there is always a delimiter at the front
1.446 + of the new segment. The parser is left in a state where its current segment is the
1.447 + same one as before the insertion.
1.448 +
1.449 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been
1.450 + parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.451 + @since 6.0
1.452 + @param aSegment A descriptor with the new segment to be inserted.
1.453 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.454 + @post The data will have been extended to include the new segment. The
1.455 + current segment will remain as the one before the insertion.
1.456 +*/
1.457 +EXPORT_C void CDelimitedDataBase8::InsertCurrentL(const TDesC8& aSegment)
1.458 + {
1.459 + __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.460 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.461 +
1.462 + DoInsertL(aSegment);
1.463 + }
1.464 +
1.465 +/**
1.466 + Removes the current segment. After removing the segment, the parser's new current segment
1.467 + will be the next segment. If the last segment is the one that is removed then the parser
1.468 + will be set to the end of the data.
1.469 +
1.470 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.471 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.472 + been set.
1.473 + @since 6.0
1.474 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.475 + @post The data will have been reduced to exclude the removed segment.
1.476 + The current segment will be set to what was the next segment. If the removed segment was
1.477 + the last segment, the parser is at the end of the data.
1.478 +*/
1.479 +EXPORT_C void CDelimitedDataBase8::RemoveCurrentL()
1.480 + {
1.481 + __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.482 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.483 +
1.484 + DoRemoveL();
1.485 + }
1.486 +
1.487 +/**
1.488 + Adds a new segment to the end of the data. The new segment can be made up of several segments
1.489 + and have delimiters at either extreme. The insert functionality will ensure that there is
1.490 + always a delimiter at the front of the new segment. The data must re-parsed to ensure that the
1.491 + parser is valid.
1.492 +
1.493 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.494 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.495 + been set. A re-parse is required to ensure that the parser is valid.
1.496 + @since 6.0
1.497 + @param aSegment A descriptor with the new segment to be inserted.
1.498 + @pre The delimiter must have been set.
1.499 + @post The data will have been extended to include the new segment.
1.500 +*/
1.501 +EXPORT_C void CDelimitedDataBase8::PushBackL(const TDesC8& aSegment)
1.502 + {
1.503 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.504 +
1.505 + // Parse the string in reverse direction - sets last segment as current
1.506 + iParser.ParseReverse(*iDataBuf);
1.507 +
1.508 + // Insert the segment
1.509 + DoInsertL(aSegment);
1.510 +
1.511 + // Make sure that a re-parse is required
1.512 + iParser.iMode = EDelimitedDataNotParsed;
1.513 + }
1.514 +
1.515 +/**
1.516 + Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
1.517 +
1.518 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.519 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.520 + been set. A re-parse is required to ensure that the parser is valid.
1.521 + @since 6.0
1.522 + @pre The delimiter must have been set.
1.523 + @post The data will have been reduced to exclude the last segment.
1.524 +*/
1.525 +EXPORT_C void CDelimitedDataBase8::PopBackL()
1.526 + {
1.527 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.528 +
1.529 + // Parse the string in reverse direction - sets last segment as current
1.530 + iParser.ParseReverse(*iDataBuf);
1.531 +
1.532 + // Remove the current segment
1.533 + DoRemoveL();
1.534 +
1.535 + // Make sure that a re-parse is required
1.536 + iParser.iMode = EDelimitedDataNotParsed;
1.537 + }
1.538 +
1.539 +/**
1.540 + Adds a new segment to the front of the data. The new segment can be made up of several segments
1.541 + and have delimiters at either extreme. The insert functionality will ensure that there is always
1.542 + a delimiter at the front of the new segment. The data must re-parsed to ensure that the parser
1.543 + is valid.
1.544 +
1.545 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.546 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.547 + been set. A re-parse is required to ensure that the parser is valid.
1.548 + @since 6.0
1.549 + @param aSegment A descriptor with the new segment to be inserted.
1.550 + @pre The delimiter must have been set.
1.551 + @post The data will have been extended to include the new segment.
1.552 +*/
1.553 +EXPORT_C void CDelimitedDataBase8::PushFrontL(const TDesC8& aSegment)
1.554 + {
1.555 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.556 +
1.557 + // Parse the string in forward direction - sets first segment as current
1.558 + iParser.Parse(*iDataBuf);
1.559 +
1.560 + // Insert the segment
1.561 + DoInsertL(aSegment);
1.562 +
1.563 + // Make sure that a re-parse is required
1.564 + iParser.iMode = EDelimitedDataNotParsed;
1.565 + }
1.566 +
1.567 +/**
1.568 + Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
1.569 +
1.570 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.571 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.572 + been set. A re-parse is required to ensure that the parser is valid.
1.573 + @since 6.0
1.574 + @pre The delimiter must have been set.
1.575 + @post The data will have been reduced to exclude the last segment.
1.576 +*/
1.577 +EXPORT_C void CDelimitedDataBase8::PopFrontL()
1.578 + {
1.579 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.580 +
1.581 + // Parse the string in forward direction - sets first segment as current
1.582 + iParser.Parse(*iDataBuf);
1.583 +
1.584 + // Remove the current segment
1.585 + DoRemoveL();
1.586 +
1.587 + // Make sure that a re-parse is required
1.588 + iParser.iMode = EDelimitedDataNotParsed;
1.589 + }
1.590 +
1.591 +/**
1.592 + Removes the front delimiter (if exists) from the data.
1.593 +
1.594 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.595 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.596 + been set. A re-parse is required to ensure that the parser is valid.
1.597 + @since 6.0
1.598 + @pre The delimiter must have been set.
1.599 + @post The data might have been reduced to exclude the front delimiter.
1.600 +*/
1.601 +EXPORT_C void CDelimitedDataBase8::TrimFrontDelimiterL()
1.602 + {
1.603 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.604 +
1.605 + // Search for delimiter
1.606 + if( iParser.FrontDelimiter() )
1.607 + {
1.608 + // Remove front delimiter and update member data
1.609 + SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
1.610 + }
1.611 + // Make sure that a re-parse is required
1.612 + iParser.iMode = EDelimitedDataNotParsed;
1.613 + }
1.614 +
1.615 +/**
1.616 + Adds a delimiter to the front of the data (if it doesn't exist).
1.617 +
1.618 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.619 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.620 + been set. A re-parse is required to ensure that the parser is valid.
1.621 + @since 6.0
1.622 + @pre The delimiter must have been set.
1.623 + @post The data might have been extended to include a front delimiter.
1.624 +*/
1.625 +EXPORT_C void CDelimitedDataBase8::AddFrontDelimiterL()
1.626 + {
1.627 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.628 +
1.629 + if( !iParser.FrontDelimiter() )
1.630 + {
1.631 + // Create a new buffer of correct size
1.632 + HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
1.633 + TPtr8 str = buf->Des();
1.634 +
1.635 + // Append a delimiter, then append the current string
1.636 + str.Append(iParser.iDelimiter);
1.637 + str.Append(iParser.iDataDes);
1.638 +
1.639 + // Set buffer to this new string
1.640 + SetData(buf);
1.641 + }
1.642 + // Make sure that a re-parse is required
1.643 + iParser.iMode = EDelimitedDataNotParsed;
1.644 + }
1.645 +
1.646 +/**
1.647 + Removes the back delimiter (if exists) from the data.
1.648 +
1.649 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.650 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.651 + been set. A re-parse is required to ensure that the parser is valid.
1.652 + @since 6.0
1.653 + @pre The delimiter must have been set.
1.654 + @post The data might have been reduced to exclude the front delimiter.
1.655 +*/
1.656 +EXPORT_C void CDelimitedDataBase8::TrimBackDelimiterL()
1.657 + {
1.658 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.659 +
1.660 + // Search for delimiter
1.661 + if( iParser.BackDelimiter() )
1.662 + {
1.663 + // Remove back delimiter and update member data
1.664 + SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
1.665 + }
1.666 + // Make sure that a re-parse is required
1.667 + iParser.iMode = EDelimitedDataNotParsed;
1.668 + }
1.669 +
1.670 +/**
1.671 + Adds a delimiter to the back of the data (if it doesn't exist).
1.672 +
1.673 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.674 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.675 + been set. A re-parse is required to ensure that the parser is valid.
1.676 + @since 6.0
1.677 + @pre The delimiter must have been set.
1.678 + @post The data might have been extended to include a front delimiter.
1.679 +*/
1.680 +EXPORT_C void CDelimitedDataBase8::AddBackDelimiterL()
1.681 + {
1.682 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.683 +
1.684 + if( !iParser.BackDelimiter() )
1.685 + {
1.686 + // Create a new buffer of correct size
1.687 + HBufC8* buf = HBufC8::NewL(iParser.iDataDes.Length() + 1);
1.688 + TPtr8 str = buf->Des();
1.689 +
1.690 + // Append the current string, then append a delimiter
1.691 + str.Append(iParser.iDataDes);
1.692 + str.Append(iParser.iDelimiter);
1.693 +
1.694 + // Set buffer to this new string
1.695 + SetData(buf);
1.696 + }
1.697 + // Make sure that a re-parse is required
1.698 + iParser.iMode = EDelimitedDataNotParsed;
1.699 + }
1.700 +
1.701 +/**
1.702 + This parses the data into segments from left to right.
1.703 +
1.704 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.705 + has not been set.
1.706 + @since 6.0
1.707 + @pre The delimiter must have been set.
1.708 + @post The current segment is the leftmost segment and the direction of
1.709 + parsing is set from left to right (EDelimitedDataFroward).
1.710 +*/
1.711 +EXPORT_C void CDelimitedDataBase8::Parse()
1.712 + {
1.713 + // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1.714 + iParser.Parse(*iDataBuf);
1.715 + }
1.716 +
1.717 +/**
1.718 + This parses the string into segments from right to left.
1.719 +
1.720 + @since 6.0
1.721 + @pre The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
1.722 + the delimiter has not been initialized.
1.723 + @post The current segment is the leftmost segment and the direction of parsing is right to left.
1.724 +*/
1.725 +EXPORT_C void CDelimitedDataBase8::ParseReverse()
1.726 + {
1.727 + // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1.728 + iParser.ParseReverse(*iDataBuf);
1.729 + }
1.730 +
1.731 +/**
1.732 + Retrieves a const reference to the delimited data parser.
1.733 +
1.734 + @since 6.0
1.735 + @return A const reference to the delimited data parser.
1.736 +*/
1.737 +EXPORT_C const TDelimitedParserBase8& CDelimitedDataBase8::Parser() const
1.738 + {
1.739 + return iParser;
1.740 + }
1.741 +
1.742 +/**
1.743 + Sets the delimiting character.
1.744 +
1.745 + @since 6.0
1.746 + @param aDelimiter The delimiting character.
1.747 + @post The delimiting character is updated.
1.748 +*/
1.749 +EXPORT_C void CDelimitedDataBase8::SetDelimiter(TChar aDelimiter)
1.750 + {
1.751 + iParser.SetDelimiter(aDelimiter);
1.752 + }
1.753 +
1.754 +/**
1.755 + Constructor. First phase of two-phase construction method. Does non-allocating construction.
1.756 +
1.757 + @since 6.0
1.758 +*/
1.759 +EXPORT_C CDelimitedDataBase8::CDelimitedDataBase8()
1.760 + {
1.761 + }
1.762 +
1.763 +/**
1.764 + Second phase of two-phase construction method. Does any allocations required to fully construct
1.765 + the object.
1.766 +
1.767 + @since 6.0
1.768 + @param aData A descriptor with the initial string.
1.769 + @pre First phase of construction is complete.
1.770 + @post The object is fully constructed.
1.771 +*/
1.772 +EXPORT_C void CDelimitedDataBase8::ConstructL(const TDesC8& aData)
1.773 + {
1.774 + // Create copy of string and set descriptor in the parser
1.775 + SetDataL(aData);
1.776 + }
1.777 +
1.778 +/**
1.779 + Inserts the new segment in a position before the current segment. The new segment can be made up
1.780 + of several segments and have delimiters at either extreme. The insert functionality will ensure
1.781 + that there is always a delimiter at the front of the new segment. The parser will be left in a
1.782 + state where its current segment is the same one as before the insertion.
1.783 +
1.784 + @since 6.0
1.785 + @param aSegment The descriptor with the segment to be inserted.
1.786 + @pre The string must have been parsed.
1.787 + @post The string will have been extended to include the new segment. The current segment will
1.788 + remain as the one before the insertion.
1.789 +*/
1.790 +void CDelimitedDataBase8::DoInsertL(const TDesC8& aSegment)
1.791 + {
1.792 + // Get previous delimiter to split the current string into prefix and suffix to the new segment
1.793 + TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1.794 + TPtrC8 prefix = iParser.iDataDes.Left(prevPos);
1.795 +
1.796 + TInt suffixLength = iParser.iDataDes.Length() - prevPos;
1.797 + TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
1.798 + if( suffixLength && suffix[0] == iParser.iDelimiter )
1.799 + {
1.800 + // Remove front delimiter on suffix
1.801 + suffix.Set(suffix.Right(--suffixLength));
1.802 + }
1.803 +
1.804 + // Check for delimiters
1.805 + TPtrC8 segment = aSegment;
1.806 + TInt segmentLength = segment.Length();
1.807 + TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
1.808 + if( segmentBackDelimiter )
1.809 + {
1.810 + // Remove back delimiter from the segment
1.811 + segment.Set(segment.Left(--segmentLength));
1.812 + }
1.813 + if( segmentLength && segment[0] == iParser.iDelimiter )
1.814 + {
1.815 + // Remove front delimiter from the segment
1.816 + segment.Set(segment.Right(--segmentLength));
1.817 + }
1.818 +
1.819 + // Check if a back delimiter is needed - NOTE always add a front delimiter
1.820 + TInt extra = 1;
1.821 + TBool needBackDelimiter = EFalse;
1.822 + if( suffix.Length() || segmentBackDelimiter )
1.823 + {
1.824 + ++extra;
1.825 + needBackDelimiter = ETrue;
1.826 + }
1.827 + // Create space for new string
1.828 + HBufC8* buf = HBufC8::NewL(prevPos + segmentLength + suffixLength + extra);
1.829 + TPtr8 str = buf->Des();
1.830 +
1.831 + // Form the new string
1.832 + str.Append(prefix);
1.833 + str.Append(iParser.iDelimiter);
1.834 + str.Append(segment);
1.835 + if( needBackDelimiter )
1.836 + str.Append(iParser.iDelimiter);
1.837 + str.Append(suffix);
1.838 +
1.839 + // Update string data
1.840 + SetData(buf);
1.841 +
1.842 + // Check to see if the internal parser object (iParser) has been parsed
1.843 + // (can tell if it has if the data pointer in iCurrentSegment is not NULL)
1.844 + // If so update iCurrentSegment to ensure that iParser remains valid
1.845 + if( iParser.iCurrentSegment.Ptr() )
1.846 + {
1.847 + // Ensure parser is in correct position and current segment is correct
1.848 + iParser.iNextSegmentPos = prevPos;
1.849 + if( iParser.iMode == EDelimitedDataForward )
1.850 + {
1.851 + // Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
1.852 + iParser.iNextSegmentPos += segmentLength + 1;
1.853 + }
1.854 + // Get the next segment
1.855 + iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
1.856 + }
1.857 + }
1.858 +
1.859 +/**
1.860 + Removes the current segment. After removing the segment, the parser's new current segment will be
1.861 + the next segment. If the last segment is the one that is removed then the parser will be set to the
1.862 + end of the data.
1.863 +
1.864 + @since 6.0
1.865 + @pre The data must have been parsed.
1.866 + @post The data will have been reduced to exclude the removed data. The
1.867 + current segment is set to what was the next segment. If the removed segment was
1.868 + the last segment, the parser is at the end of the data.
1.869 +*/
1.870 +void CDelimitedDataBase8::DoRemoveL()
1.871 + {
1.872 + // Check if there is anything to remove
1.873 + if( iParser.iDataDes.Length() == 0 )
1.874 + {
1.875 + return;
1.876 + }
1.877 + // Find the previous delimiter
1.878 + TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1.879 +
1.880 + // Set up the start and end position of current segment
1.881 + TInt endPos = iParser.iNextSegmentPos;
1.882 + TInt startPos = iParser.iNextSegmentPos;
1.883 + if( prev < iParser.iNextSegmentPos )
1.884 + startPos = prev;
1.885 + else
1.886 + endPos = prev;
1.887 +
1.888 + // Ok, get the prefix and suffix parts
1.889 + TPtrC8 prefix = iParser.iDataDes.Left(startPos);
1.890 + TInt suffixLength = iParser.iDataDes.Length() - endPos;
1.891 + TPtrC8 suffix = iParser.iDataDes.Right(suffixLength);
1.892 +
1.893 + // Create the space
1.894 + HBufC8* buf = HBufC8::NewL(startPos + suffixLength);
1.895 + TPtr8 str = buf->Des();
1.896 +
1.897 + // Form the new string
1.898 + str.Append(prefix);
1.899 + str.Append(suffix);
1.900 +
1.901 + // Update string data
1.902 + SetData(buf);
1.903 +
1.904 + // Ensure parser is in correct position
1.905 + iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
1.906 + }
1.907 +
1.908 +/**
1.909 + Updates internal data buffer with the new data. Creates a copy of the new data.
1.910 +
1.911 + @since 6.0
1.912 + @param aData A descriptor with the new string.
1.913 + @post The internal data buffer now contains a copy of the new data and the
1.914 + parser is set to the new data.
1.915 +*/
1.916 +void CDelimitedDataBase8::SetDataL(const TDesC8& aData)
1.917 + {
1.918 + // Cleanup old data and set new
1.919 + HBufC8* buf = aData.AllocL();
1.920 + SetData(buf);
1.921 + }
1.922 +
1.923 +/**
1.924 + Sets internal data buffer and parser. Cleans up the old data and uses the data buffer.
1.925 + The parser is set to the new data.
1.926 +
1.927 + @since 6.0
1.928 + @param aDataBuf A pointer to a decriptor buffer with the new data.
1.929 + @post The internal data buffer now points to the new buffer and the parser
1.930 + is set to the data in the new buffer..
1.931 +*/
1.932 +void CDelimitedDataBase8::SetData(HBufC8* aDataBuf)
1.933 + {
1.934 + delete iDataBuf;
1.935 + iDataBuf = aDataBuf;
1.936 + iParser.iDataDes.Set(*iDataBuf);
1.937 + }
1.938 +
1.939 +//
1.940 +//
1.941 +// Implementation of TDelimitedParserBase16
1.942 +//
1.943 +//
1.944 +/**
1.945 + Constructor.
1.946 +
1.947 + @since 6.0
1.948 + */
1.949 +EXPORT_C TDelimitedParserBase16::TDelimitedParserBase16()
1.950 +: iDataDes(0,0), iCurrentSegment(0,0), iNextSegmentPos(-1), iMode(EDelimitedDataNotParsed), iDelimiter(0)
1.951 + {
1.952 + }
1.953 +
1.954 +/**
1.955 + Resets the internal pointer position to the start or end or the descriptor depending
1.956 + on whether the decriptor is parsing mode.
1.957 +
1.958 + @warning There will be a KUriUtilsErrBadDelimitedParserMode panic if the data mode has
1.959 + not been correctly set.
1.960 + */
1.961 +EXPORT_C void TDelimitedParserBase16::Reset() const
1.962 + {
1.963 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.964 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.965 +
1.966 + iNextSegmentPos = InitialDelimiterPosition(iDataDes, iMode);
1.967 + }
1.968 +/**
1.969 + Retrieves the current segment and then parses the data to the next one.
1.970 +
1.971 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.972 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.973 + @since 6.0
1.974 + @param aSegment This is an output argument that is set to the current segment.
1.975 + @return A error value of KErrNotFound if there is no current segment. The
1.976 + value KErrNone if there is a current segment.
1.977 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.978 + @post The current segment is updated to the next one.
1.979 + */
1.980 +EXPORT_C TInt TDelimitedParserBase16::GetNext(TPtrC16& aSegment) const
1.981 + {
1.982 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.983 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.984 +
1.985 + // Check that there is a segment
1.986 + if( iNextSegmentPos == KErrNotFound )
1.987 + {
1.988 + // There is no segment
1.989 + return KErrNotFound;
1.990 + }
1.991 + // There is one - set aSegment
1.992 + aSegment.Set(iCurrentSegment);
1.993 + // Parse the next segment
1.994 + iNextSegmentPos = FindNextSegment(iNextSegmentPos);
1.995 + return KErrNone;
1.996 + }
1.997 +
1.998 +/**
1.999 + Parses to the next segment.
1.1000 +
1.1001 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1002 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1003 + @since 6.0
1.1004 + @return A error value of KErrNotFound if there is no current segment. The
1.1005 + value KErrNone if there is a current segment.
1.1006 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1007 + @post The current segment is updated to the next one.
1.1008 + */
1.1009 +EXPORT_C TInt TDelimitedParserBase16::Inc() const
1.1010 + {
1.1011 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1012 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1013 +
1.1014 + // Check that there is a segment
1.1015 + if( iNextSegmentPos == KErrNotFound )
1.1016 + {
1.1017 + // There is no segment
1.1018 + return KErrNotFound;
1.1019 + }
1.1020 + // Parse the next segment
1.1021 + iNextSegmentPos = FindNextSegment(iNextSegmentPos);
1.1022 + return KErrNone;
1.1023 + }
1.1024 +
1.1025 +/**
1.1026 + Parses back to the previous segment.
1.1027 +
1.1028 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1029 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1030 + @since 6.0
1.1031 + @return A error value of KErrNotFound if the current segment is the initial
1.1032 + segment. The value KErrNone if the data has been parsed to the previous segment.
1.1033 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1034 + @post If the parse was successful then the current segment is updated
1.1035 + to the previous one. Otherwise there is no change.
1.1036 + */
1.1037 +EXPORT_C TInt TDelimitedParserBase16::Dec() const
1.1038 + {
1.1039 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1040 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1041 +
1.1042 + // Find position of previous delimiter
1.1043 + TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1.1044 +
1.1045 + // Get the previous segment
1.1046 + if( FindPrevSegment(prev) == KErrNotFound )
1.1047 + {
1.1048 + // There is no previous segment - set to start of data
1.1049 + return KErrNotFound;
1.1050 + }
1.1051 + // Update next segment position
1.1052 + iNextSegmentPos = prev;
1.1053 + return KErrNone;
1.1054 + }
1.1055 +
1.1056 +/**
1.1057 + Retrieves the current segment.
1.1058 +
1.1059 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1060 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1061 + @since 6.0
1.1062 + @param aSegment This is an output argument that is set to the current segment.
1.1063 + @return A error value of KErrNotFound if there is no current segment. The
1.1064 + value KErrNone if there is a current segment.
1.1065 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1066 + */
1.1067 +EXPORT_C TInt TDelimitedParserBase16::Peek(TPtrC16& aSegment) const
1.1068 + {
1.1069 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1070 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1071 +
1.1072 + // Check that there is a segment
1.1073 + if( iNextSegmentPos == KErrNotFound )
1.1074 + {
1.1075 + // There is no segment
1.1076 + return KErrNotFound;
1.1077 + }
1.1078 + // There is one - set aSegment
1.1079 + aSegment.Set(iCurrentSegment);
1.1080 + return KErrNone;
1.1081 + }
1.1082 +
1.1083 +/**
1.1084 + Indicates whether the end of the data has been reached and there are no more segments to parse.
1.1085 +
1.1086 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1087 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1088 + @since 6.0
1.1089 + @return A boolean value of ETrue if the end of the data has been reached,
1.1090 + or EFalse if there are more segements to parse.
1.1091 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1092 + */
1.1093 +EXPORT_C TBool TDelimitedParserBase16::Eos() const
1.1094 + {
1.1095 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1096 +
1.1097 + TBool eos = iNextSegmentPos == KErrNotFound ? ETrue : EFalse;
1.1098 + return eos;
1.1099 + }
1.1100 +
1.1101 +/**
1.1102 + Checks for a delimiter at the front (left) of the data.
1.1103 +
1.1104 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1105 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1106 + @since 6.0
1.1107 + @return A boolean of value ETrue if there is a front delimiter, or EFalse
1.1108 + if there is no front delimiter.
1.1109 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1110 + */
1.1111 +EXPORT_C TBool TDelimitedParserBase16::FrontDelimiter() const
1.1112 + {
1.1113 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1114 +
1.1115 + return (iDataDes.Locate(iDelimiter) == 0);
1.1116 + }
1.1117 +
1.1118 +/**
1.1119 + Checks for a delimiter at the back (right) of the data.
1.1120 +
1.1121 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1122 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1123 + @since 6.0
1.1124 + @return A boolean of value ETrue if there is a back delimiter, or EFalse
1.1125 + if there is no back delimiter.
1.1126 + @pre The string must have been initially parsed by Parse() or ParseReverse().
1.1127 + */
1.1128 +EXPORT_C TBool TDelimitedParserBase16::BackDelimiter() const
1.1129 + {
1.1130 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1131 +
1.1132 + TInt delimiterPos = iDataDes.LocateReverse(iDelimiter);
1.1133 + if( delimiterPos == KErrNotFound )
1.1134 + return EFalse;
1.1135 + return (delimiterPos == iDataDes.Length() - 1);
1.1136 + }
1.1137 +
1.1138 +/**
1.1139 + Retrieves the descriptor reference with the data
1.1140 +
1.1141 + @since 6.0
1.1142 + @return A const descriptor reference with the data.
1.1143 + */
1.1144 +EXPORT_C const TDesC16& TDelimitedParserBase16::Des() const
1.1145 + {
1.1146 + return iDataDes;
1.1147 + }
1.1148 +
1.1149 +/**
1.1150 + Gives the remainder of the data from (and including) the current segment. Any other segments that
1.1151 + have parsed through are not included.
1.1152 +
1.1153 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1.1154 + and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1155 + @since 6.0
1.1156 + @param aRemainder This is an output argument that is set to the remaining data.
1.1157 + @return An error value of KErrNotFound if there is no remaining data, or value of KErrNone
1.1158 + if there is remaining data.
1.1159 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.1160 + */
1.1161 +EXPORT_C TInt TDelimitedParserBase16::Remainder(TPtrC16& aRemainder) const
1.1162 + {
1.1163 + __ASSERT_ALWAYS(iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1164 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1165 +
1.1166 + // Check to see if there is a segment left
1.1167 + if( iNextSegmentPos == KErrNotFound )
1.1168 + {
1.1169 + // There is no segment
1.1170 + return KErrNotFound;
1.1171 + }
1.1172 + // Find the previous delimiter -> the start of the current segment
1.1173 + TInt prev = PrevDelimiterPosition(iDataDes, iNextSegmentPos, iDelimiter, iMode);
1.1174 +
1.1175 + // Need to see which direction the parsing is going to set the remainder
1.1176 + switch(iMode)
1.1177 + {
1.1178 + case EDelimitedDataForward:
1.1179 + {
1.1180 + aRemainder.Set(iDataDes.Right(iDataDes.Length() - prev));
1.1181 + } break;
1.1182 + case EDelimitedDataReverse:
1.1183 + {
1.1184 + aRemainder.Set(iDataDes.Left(prev));
1.1185 + } break;
1.1186 + default:
1.1187 + // Bad mode!
1.1188 + User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1.1189 + break;
1.1190 + }
1.1191 + return KErrNone;
1.1192 + }
1.1193 +
1.1194 +/**
1.1195 + This parses the data into segments from left to right.
1.1196 +
1.1197 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.1198 + has not been set.
1.1199 + @since 6.0
1.1200 + @param aData A descriptor containing the data.
1.1201 + @pre The delimiter must have been set.
1.1202 + @post The current segment is the leftmost segment and the direction of
1.1203 + parsing is set from left to right (EDelimitedDataFroward).
1.1204 + */
1.1205 +EXPORT_C void TDelimitedParserBase16::Parse(const TDesC16& aData)
1.1206 + {
1.1207 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1208 +
1.1209 + // Initialise data for EForward direction
1.1210 + iMode = EDelimitedDataForward;
1.1211 + DoParse(aData);
1.1212 + }
1.1213 +
1.1214 +/**
1.1215 + This parses the data into segments from lright to left.
1.1216 +
1.1217 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.1218 + has not been set.
1.1219 + @since 6.0
1.1220 + @param aData A descriptor containing the data.
1.1221 + @pre The delimiter must have been set.
1.1222 + @post The current segment is the leftmost segment and the direction of
1.1223 + parsing is set from right to left (EDelimitedDataReverse).
1.1224 + */
1.1225 +EXPORT_C void TDelimitedParserBase16::ParseReverse(const TDesC16& aData)
1.1226 + {
1.1227 + __ASSERT_ALWAYS(iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1228 +
1.1229 + // Initialise data for EReverse direction
1.1230 + iMode = EDelimitedDataReverse;
1.1231 + DoParse(aData);
1.1232 + }
1.1233 +
1.1234 +/**
1.1235 + Sets the delimiting character.
1.1236 +
1.1237 + @since 6.0
1.1238 + @param aDelimiter The delimiting character.
1.1239 + @post The delimiting character is set.
1.1240 +*/
1.1241 +EXPORT_C void TDelimitedParserBase16::SetDelimiter(TChar aDelimiter)
1.1242 + {
1.1243 + iDelimiter = aDelimiter;
1.1244 + }
1.1245 +
1.1246 +/**
1.1247 + Initialises the parsing of the data.
1.1248 +
1.1249 + @since 6.0
1.1250 + @param aData A descriptor reference with the data.
1.1251 + @pre The delimiting character has been set.
1.1252 + @post The data descriptor is set to the input argument. The current segment
1.1253 + refers to the initial segment of the data.
1.1254 + */
1.1255 +void TDelimitedParserBase16::DoParse(const TDesC16& aData)
1.1256 + {
1.1257 + // Reset the segment information, then set the new Data - set pointer to NULL and length to zero
1.1258 + iCurrentSegment.Set(NULL,0);
1.1259 + iDataDes.Set(aData);
1.1260 +
1.1261 + // Check that there is a string!
1.1262 + if( iDataDes.Length() == 0 )
1.1263 + {
1.1264 + // No string - ensure functionality blocked for this descriptor
1.1265 + iNextSegmentPos = KErrNotFound;
1.1266 + return;
1.1267 + }
1.1268 + // Find the segment - search from initial start position
1.1269 + iNextSegmentPos = FindNextSegment(InitialDelimiterPosition(iDataDes, iMode));
1.1270 + }
1.1271 +
1.1272 +/**
1.1273 + Finds the next segment from the given start position.
1.1274 +
1.1275 + @since 6.0
1.1276 + @param aStartPos The position from where to start the search for the
1.1277 + next segment.
1.1278 + @return The position of delimiter after the specified start position, or
1.1279 + an error value of KErrNotFound if no more delimiters are found.
1.1280 + */
1.1281 +TInt TDelimitedParserBase16::FindNextSegment(TInt aStartPos) const
1.1282 + {
1.1283 + // Find position of next delimiter
1.1284 + TInt next = NextDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1.1285 +
1.1286 + if( next != KErrNotFound )
1.1287 + {
1.1288 + TInt startPos = next < aStartPos ? next : aStartPos;
1.1289 + TInt endPos = next < aStartPos ? aStartPos : next;
1.1290 + if( iDataDes[startPos] == iDelimiter )
1.1291 + {
1.1292 + // Move past delimiter
1.1293 + ++startPos;
1.1294 + }
1.1295 + TInt length = endPos - startPos;
1.1296 + iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1.1297 + }
1.1298 + return next;
1.1299 + }
1.1300 +
1.1301 +/**
1.1302 + Finds the previous segment from the given start position.
1.1303 +
1.1304 + @since 6.0
1.1305 + @param aStartPos The position from where to start the search for the
1.1306 + previous segment.
1.1307 + @return The position of delimiter before the specified start position, or
1.1308 + an error value of KErrNotFound if no more delimiters are found.
1.1309 +*/
1.1310 +TInt TDelimitedParserBase16::FindPrevSegment(TInt aStartPos) const
1.1311 + {
1.1312 + // Find position of previous delimiter
1.1313 + TInt prev = PrevDelimiterPosition(iDataDes, aStartPos, iDelimiter, iMode);
1.1314 +
1.1315 + if( prev != KErrNotFound )
1.1316 + {
1.1317 + TInt startPos = prev < aStartPos ? prev : aStartPos;
1.1318 + TInt endPos = prev < aStartPos ? aStartPos : prev;
1.1319 + if( iDataDes[startPos] == iDelimiter )
1.1320 + {
1.1321 + // Move past delimiter
1.1322 + ++startPos;
1.1323 + }
1.1324 + TInt length = endPos - startPos;
1.1325 + iCurrentSegment.Set(iDataDes.Mid(startPos, length));
1.1326 + }
1.1327 + return prev;
1.1328 + }
1.1329 +
1.1330 +//
1.1331 +//
1.1332 +// Implementation of CDelimitedDataBase16
1.1333 +//
1.1334 +//
1.1335 +
1.1336 +/**
1.1337 + Destructor.
1.1338 +
1.1339 + @since 6.0
1.1340 + */
1.1341 +EXPORT_C CDelimitedDataBase16::~CDelimitedDataBase16()
1.1342 + {
1.1343 + delete iDataBuf;
1.1344 + }
1.1345 +
1.1346 +/**
1.1347 + Inserts the new segment in a position before the current parsed segment. The new segment can be
1.1348 + made up of several segments and have delimiters at either extreme. The insert functionality will
1.1349 + ensure that there is always a delimiter at the front of the new segment. The parser is left in a
1.1350 + state where its current segment is the same one as before the insertion.
1.1351 +
1.1352 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1.1353 + and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1354 + @since 6.0
1.1355 + @param aSegment A descriptor with the new segment to be inserted.
1.1356 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.1357 + @post The data will have been extended to include the new segment. The current segment
1.1358 + will remain as the one before the insertion.
1.1359 + */
1.1360 +EXPORT_C void CDelimitedDataBase16::InsertCurrentL(const TDesC16& aSegment)
1.1361 + {
1.1362 + __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1363 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1364 +
1.1365 + DoInsertL(aSegment);
1.1366 + }
1.1367 +
1.1368 +/**
1.1369 + Removes the current segment. After removing the segment, the parser's new current segment will be the
1.1370 + next segment. If the last segment is the one that is removed then the parser will be set to the end of
1.1371 + the data.
1.1372 +
1.1373 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and
1.1374 + a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1375 + @since 6.0
1.1376 + @pre The data must have been initially parsed by Parse() or ParseReverse().
1.1377 + @post The data will have been reduced to exclude the removed segment. The current segment will
1.1378 + be set to what was the next segment. If the removed segment was the last segment, the parser is at the end
1.1379 + of the data.
1.1380 + */
1.1381 +EXPORT_C void CDelimitedDataBase16::RemoveCurrentL()
1.1382 + {
1.1383 + __ASSERT_ALWAYS(iParser.iMode != EDelimitedDataNotParsed, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNotParsed));
1.1384 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1385 +
1.1386 + DoRemoveL();
1.1387 + }
1.1388 +
1.1389 +/**
1.1390 + Adds a new segment to the end of the data. The new segment can be made up of several segments and have
1.1391 + delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at
1.1392 + the front of the new segment. The data must re-parsed to ensure that the parser is valid.
1.1393 +
1.1394 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and a
1.1395 + KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure
1.1396 + that the parser is valid.
1.1397 + @since 6.0
1.1398 + @param aSegment A descriptor with the new segment to be inserted.
1.1399 + @pre The delimiter must have been set.
1.1400 + @post The data will have been extended to include the new segment.
1.1401 + */
1.1402 +EXPORT_C void CDelimitedDataBase16::PushBackL(const TDesC16& aSegment)
1.1403 + {
1.1404 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1405 +
1.1406 + // Parse the string in reverse direction - sets last segment as current
1.1407 + iParser.ParseReverse(*iDataBuf);
1.1408 +
1.1409 + // Insert the segment
1.1410 + DoInsertL(aSegment);
1.1411 +
1.1412 + // Make sure that a re-parse is required
1.1413 + iParser.iMode = EDelimitedDataNotParsed;
1.1414 + }
1.1415 +
1.1416 +/**
1.1417 + Removes the last segment from the data. The data must be re-parsed to ensure that the parser is valid.
1.1418 +
1.1419 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed,
1.1420 + and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required
1.1421 + to ensure that the parser is valid.
1.1422 + @since 6.0
1.1423 + @pre The delimiter must have been set.
1.1424 + @post The data will have been reduced to exclude the last segment.
1.1425 + */
1.1426 +EXPORT_C void CDelimitedDataBase16::PopBackL()
1.1427 + {
1.1428 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1429 +
1.1430 + // Parse the string in reverse direction - sets last segment as current
1.1431 + iParser.ParseReverse(*iDataBuf);
1.1432 +
1.1433 + // Remove the current segment
1.1434 + DoRemoveL();
1.1435 +
1.1436 + // Make sure that a re-parse is required
1.1437 + iParser.iMode = EDelimitedDataNotParsed;
1.1438 + }
1.1439 +
1.1440 +
1.1441 +/**
1.1442 + Adds a new segment to the front of the data. The new segment can be made up of several segments and have
1.1443 + delimiters at either extreme. The insert functionality will ensure that there is always a delimiter at
1.1444 + the front of the new segment. The data must re-parsed to ensure that the parser is valid.
1.1445 +
1.1446 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been parsed, and
1.1447 + a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse is required to ensure
1.1448 + that the parser is valid.
1.1449 + @since 6.0
1.1450 + @param aSegment A descriptor with the new segment to be inserted.
1.1451 + @pre The delimiter must have been set.
1.1452 + @post The data will have been extended to include the new segment.
1.1453 + */
1.1454 +EXPORT_C void CDelimitedDataBase16::PushFrontL(const TDesC16& aSegment)
1.1455 + {
1.1456 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1457 +
1.1458 + // Parse the string in forward direction - sets first segment as current
1.1459 + iParser.Parse(*iDataBuf);
1.1460 +
1.1461 + // Insert the segment
1.1462 + DoInsertL(aSegment);
1.1463 +
1.1464 + // Make sure that a re-parse is required
1.1465 + iParser.iMode = EDelimitedDataNotParsed;
1.1466 + }
1.1467 +
1.1468 +/**
1.1469 + Removes the first segment from the data. The data must be re-parsed to ensure that the parser is valid.
1.1470 +
1.1471 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not been
1.1472 + parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set. A re-parse
1.1473 + is required to ensure that the parser is valid.
1.1474 + @since 6.0
1.1475 + @pre The delimiter must have been set.
1.1476 + @post The data will have been reduced to exclude the last segment.
1.1477 + */
1.1478 +EXPORT_C void CDelimitedDataBase16::PopFrontL()
1.1479 + {
1.1480 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1481 +
1.1482 + // Parse the string in forward direction - sets first segment as current
1.1483 + iParser.Parse(*iDataBuf);
1.1484 +
1.1485 + // Remove the current segment
1.1486 + DoRemoveL();
1.1487 +
1.1488 + // Make sure that a re-parse is required
1.1489 + iParser.iMode = EDelimitedDataNotParsed;
1.1490 + }
1.1491 +
1.1492 +
1.1493 +/**
1.1494 + Removes the front delimiter (if exists) from the data.
1.1495 +
1.1496 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.1497 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.1498 + been set. A re-parse is required to ensure that the parser is valid.
1.1499 + @since 6.0
1.1500 + @pre The delimiter must have been set.
1.1501 + @post The data might have been reduced to exclude the front delimiter.
1.1502 + */
1.1503 +EXPORT_C void CDelimitedDataBase16::TrimFrontDelimiterL()
1.1504 + {
1.1505 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1506 +
1.1507 + // Search for delimiter
1.1508 + if( iParser.FrontDelimiter() )
1.1509 + {
1.1510 + // Remove front delimiter and update member data
1.1511 + SetDataL(iParser.iDataDes.Right(iParser.iDataDes.Length() - 1));
1.1512 + }
1.1513 + // Make sure that a re-parse is required
1.1514 + iParser.iMode = EDelimitedDataNotParsed;
1.1515 + }
1.1516 +
1.1517 +/**
1.1518 + Adds a delimiter to the front of the data (if it doesn't exist).
1.1519 +
1.1520 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1521 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1522 + A re-parse is required to ensure that the parser is valid.
1.1523 + @since 6.0
1.1524 + @pre The delimiter must have been set.
1.1525 + @post The data might have been extended to include a front delimiter.
1.1526 + */
1.1527 +EXPORT_C void CDelimitedDataBase16::AddFrontDelimiterL()
1.1528 + {
1.1529 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1530 +
1.1531 + if( !iParser.FrontDelimiter() )
1.1532 + {
1.1533 + // Create a new buffer of correct size
1.1534 + HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
1.1535 + TPtr16 str = buf->Des();
1.1536 +
1.1537 + // Append a delimiter, then append the current string
1.1538 + str.Append(iParser.iDelimiter);
1.1539 + str.Append(iParser.iDataDes);
1.1540 +
1.1541 + // Set buffer to this new string
1.1542 + SetData(buf);
1.1543 + }
1.1544 + // Make sure that a re-parse is required
1.1545 + iParser.iMode = EDelimitedDataNotParsed;
1.1546 + }
1.1547 +
1.1548 +/**
1.1549 + Removes the back delimiter (if exists) from the data.
1.1550 +
1.1551 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has
1.1552 + not been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not
1.1553 + been set. A re-parse is required to ensure that the parser is valid.
1.1554 + @since 6.0
1.1555 + @pre The delimiter must have been set.
1.1556 + @post The data might have been reduced to exclude the front delimiter.
1.1557 + */
1.1558 +EXPORT_C void CDelimitedDataBase16::TrimBackDelimiterL()
1.1559 + {
1.1560 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1561 +
1.1562 + // Search for delimiter
1.1563 + if( iParser.BackDelimiter() )
1.1564 + {
1.1565 + // Remove back delimiter and update member data
1.1566 + SetDataL(iParser.iDataDes.Left(iParser.iDataDes.Length() - 1));
1.1567 + }
1.1568 + // Make sure that a re-parse is required
1.1569 + iParser.iMode = EDelimitedDataNotParsed;
1.1570 + }
1.1571 +
1.1572 +/**
1.1573 + Adds a delimiter to the back of the data (if it doesn't exist).
1.1574 +
1.1575 + @warning There will be a KDelimitedParserErrNotParsed panic if the data has not
1.1576 + been parsed, and a KDelimitedParserErrNoDelimiter panic if the delimiter has not been set.
1.1577 + A re-parse is required to ensure that the parser is valid.
1.1578 + @since 6.0
1.1579 + @pre The delimiter must have been set.
1.1580 + @post The data might have been extended to include a front delimiter.
1.1581 + */
1.1582 +EXPORT_C void CDelimitedDataBase16::AddBackDelimiterL()
1.1583 + {
1.1584 + __ASSERT_ALWAYS(iParser.iDelimiter != 0, User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrNoDelimiter));
1.1585 +
1.1586 + if( !iParser.BackDelimiter() )
1.1587 + {
1.1588 + // Create a new buffer of correct size
1.1589 + HBufC16* buf = HBufC16::NewL(iParser.iDataDes.Length() + 1);
1.1590 + TPtr16 str = buf->Des();
1.1591 +
1.1592 + // Append the current string, then append a delimiter
1.1593 + str.Append(iParser.iDataDes);
1.1594 + str.Append(iParser.iDelimiter);
1.1595 +
1.1596 + // Set buffer to this new string
1.1597 + SetData(buf);
1.1598 + }
1.1599 + // Make sure that a re-parse is required
1.1600 + iParser.iMode = EDelimitedDataNotParsed;
1.1601 + }
1.1602 +
1.1603 +/**
1.1604 + This parses the data into segments from left to right.
1.1605 +
1.1606 + @warning There will be a KDelimitedParserErrNoDelimiter panic if the delimiter
1.1607 + has not been set.
1.1608 + @since 6.0
1.1609 + @pre The delimiter must have been set.
1.1610 + @post The current segment is the leftmost segment and the direction of
1.1611 + parsing is set from left to right (EDelimitedDataFroward).
1.1612 + */
1.1613 +EXPORT_C void CDelimitedDataBase16::Parse()
1.1614 + {
1.1615 + // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1.1616 + iParser.Parse(*iDataBuf);
1.1617 + }
1.1618 +
1.1619 +/**
1.1620 + This parses the string into segments from right to left.
1.1621 +
1.1622 + @since 6.0
1.1623 + @pre The delimiter must have been set. Will get a KDelimitedParserErrNoDelimiter panic if
1.1624 + the delimiter has not been initialized.
1.1625 + @post The current segment is the leftmost segment and the direction of parsing is right to left.
1.1626 + */
1.1627 +EXPORT_C void CDelimitedDataBase16::ParseReverse()
1.1628 + {
1.1629 + // This call will panic with KUriUtilsErrNoDelimiter if the delimiter is not set
1.1630 + iParser.ParseReverse(*iDataBuf);
1.1631 + }
1.1632 +
1.1633 +/**
1.1634 + Retrieves a const reference to the delimited data parser.
1.1635 +
1.1636 + @since 6.0
1.1637 + @return A const reference to the delimited data parser.
1.1638 + */
1.1639 +EXPORT_C const TDelimitedParserBase16& CDelimitedDataBase16::Parser() const
1.1640 + {
1.1641 + return iParser;
1.1642 + }
1.1643 +
1.1644 +/**
1.1645 + Sets the delimiting character.
1.1646 +
1.1647 + @since 6.0
1.1648 + @param aDelimiter The delimiting character.
1.1649 + @post The delimiting character is updated.
1.1650 + */
1.1651 +EXPORT_C void CDelimitedDataBase16::SetDelimiter(TChar aDelimiter)
1.1652 + {
1.1653 + iParser.SetDelimiter(aDelimiter);
1.1654 + }
1.1655 +
1.1656 +/**
1.1657 + Constructor. First phase of two-phase construction method. Does non-allocating construction.
1.1658 +
1.1659 + @since 6.0
1.1660 + */
1.1661 +EXPORT_C CDelimitedDataBase16::CDelimitedDataBase16()
1.1662 + {
1.1663 + }
1.1664 +
1.1665 +/**
1.1666 + Second phase of two-phase construction method. Does any allocations required to fully construct
1.1667 + the object.
1.1668 +
1.1669 + @since 6.0
1.1670 + @param aData A descriptor with the initial string.
1.1671 + @pre First phase of construction is complete.
1.1672 + @post The object is fully constructed.
1.1673 + */
1.1674 +EXPORT_C void CDelimitedDataBase16::ConstructL(const TDesC16& aData)
1.1675 + {
1.1676 + // Create copy of string and set descriptor in the parser
1.1677 + SetDataL(aData);
1.1678 + }
1.1679 +
1.1680 +/**
1.1681 + Inserts the new segment in a position before the current segment. The new segment can be made up of
1.1682 + several segments and have delimiters at either extreme. The insert functionality will ensure that
1.1683 + there is always a delimiter at the front of the new segment. The parser will be left in a state where
1.1684 + its current segment is the same one as before the insertion.
1.1685 +
1.1686 + @since 6.0
1.1687 + @param aSegment The descriptor with the segment to be inserted.
1.1688 + @pre The string must have been parsed.
1.1689 + @post The string will have been extended to include the new segment. The current segment will
1.1690 + remain as the one before the insertion.
1.1691 + */
1.1692 +void CDelimitedDataBase16::DoInsertL(const TDesC16& aSegment)
1.1693 + {
1.1694 + TInt prevPos = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1.1695 + TPtrC16 prefix = iParser.iDataDes.Left(prevPos);
1.1696 +
1.1697 + TInt suffixLength = iParser.iDataDes.Length() - prevPos;
1.1698 + TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
1.1699 + if( suffixLength && suffix[0] == iParser.iDelimiter )
1.1700 + {
1.1701 + // Remove front delimiter on suffix
1.1702 + suffix.Set(suffix.Right(--suffixLength));
1.1703 + }
1.1704 +
1.1705 + // Check for delimiters...
1.1706 + TPtrC16 segment = aSegment;
1.1707 + TInt segmentLength = segment.Length();
1.1708 + // Check the last character in segment
1.1709 + TBool segmentBackDelimiter = (segmentLength && segment[segmentLength - 1] == iParser.iDelimiter);
1.1710 + if( segmentBackDelimiter )
1.1711 + {
1.1712 + // Remove back delimiter from the segment
1.1713 + segment.Set(segment.Left(--segmentLength));
1.1714 + }
1.1715 + // Check the first character in segment...
1.1716 + if( segmentLength && segment[0] == iParser.iDelimiter )
1.1717 + {
1.1718 + // Remove front delimiter from the segment
1.1719 + segment.Set(segment.Right(--segmentLength));
1.1720 + }
1.1721 +
1.1722 + // Check if a back delimiter is needed - NOTE always add a front delimiter
1.1723 + TInt extra = 1;
1.1724 + TBool needBackDelimiter = EFalse;
1.1725 + if( suffix.Length() || segmentBackDelimiter )
1.1726 + {
1.1727 + ++extra;
1.1728 + needBackDelimiter = ETrue;
1.1729 + }
1.1730 + // Create space for new string
1.1731 + HBufC16* buf = HBufC16::NewL(prevPos + segmentLength + suffixLength + extra);
1.1732 + TPtr16 str = buf->Des();
1.1733 +
1.1734 + // Form the new string
1.1735 + str.Append(prefix);
1.1736 + str.Append(iParser.iDelimiter);
1.1737 + str.Append(segment);
1.1738 + if( needBackDelimiter )
1.1739 + str.Append(iParser.iDelimiter);
1.1740 + str.Append(suffix);
1.1741 +
1.1742 + // Update string data
1.1743 + SetData(buf);
1.1744 +
1.1745 + // Check to see if the internal parser object (iParser) has been parsed
1.1746 + // (can tell if it has if the data pointer in iCurrentSegment is not NULL)
1.1747 + // If so update iCurrentSegment to ensure that iParser remains valid
1.1748 + if( iParser.iCurrentSegment.Ptr() )
1.1749 + {
1.1750 + // Ensure parser is in correct position and current segment is correct
1.1751 + iParser.iNextSegmentPos = prevPos;
1.1752 + if( iParser.iMode == EDelimitedDataForward )
1.1753 + {
1.1754 + // Move iterator to delimiter before iCurrentSegment - length of segment + a delimiter
1.1755 + iParser.iNextSegmentPos += segmentLength + 1;
1.1756 + }
1.1757 + // Get the next segment
1.1758 + iParser.iNextSegmentPos = iParser.FindNextSegment(iParser.iNextSegmentPos);
1.1759 + }
1.1760 + }
1.1761 +
1.1762 +/**
1.1763 + Removes the current segment. After removing the segment, the parser's new current segment will be the
1.1764 + next segment. If the last segment is the one that is removed then the parser will be set to the end of
1.1765 + the data.
1.1766 +
1.1767 + @since 6.0
1.1768 + @pre The data must have been parsed.
1.1769 + @post The data will have been reduced to exclude the removed data. The current segment
1.1770 + is set to what was the next segment. If the removed segment was the last segment, the parser is
1.1771 + at the end of the data.
1.1772 + */
1.1773 +void CDelimitedDataBase16::DoRemoveL()
1.1774 + {
1.1775 + // Check if there is anything to remove
1.1776 + if( iParser.iDataDes.Length() == 0 )
1.1777 + {
1.1778 + return;
1.1779 + }
1.1780 + // Find the previous delimiter
1.1781 + TInt prev = PrevDelimiterPosition(iParser.iDataDes, iParser.iNextSegmentPos, iParser.iDelimiter, iParser.iMode);
1.1782 +
1.1783 + // Set up the start and end position of current segment
1.1784 + TInt endPos = iParser.iNextSegmentPos;
1.1785 + TInt startPos = iParser.iNextSegmentPos;
1.1786 + if( prev < iParser.iNextSegmentPos )
1.1787 + startPos = prev;
1.1788 + else
1.1789 + endPos = prev;
1.1790 +
1.1791 + // Ok, get the prefix and suffix parts
1.1792 + TPtrC16 prefix = iParser.iDataDes.Left(startPos);
1.1793 + TInt suffixLength = iParser.iDataDes.Length() - endPos;
1.1794 + TPtrC16 suffix = iParser.iDataDes.Right(suffixLength);
1.1795 +
1.1796 + // Create the space
1.1797 + HBufC16* buf = HBufC16::NewL(startPos + suffixLength);
1.1798 + TPtr16 str = buf->Des();
1.1799 +
1.1800 + // Form the new string
1.1801 + str.Append(prefix);
1.1802 + str.Append(suffix);
1.1803 +
1.1804 + // Update string data
1.1805 + SetData(buf);
1.1806 +
1.1807 + // Ensure parser is in correct position
1.1808 + iParser.iNextSegmentPos = iParser.FindNextSegment(startPos);
1.1809 + }
1.1810 +
1.1811 +/**
1.1812 + Updates internal data buffer with the new data. Creates a copy of the new data.
1.1813 +
1.1814 + @since 6.0
1.1815 + @param aData A descriptor with the new string.
1.1816 + @post The internal data buffer now contains a copy of the new data and the
1.1817 + parser is set to the new data.
1.1818 + */
1.1819 +void CDelimitedDataBase16::SetDataL(const TDesC16& aData)
1.1820 + {
1.1821 + // Cleanup old data and set new
1.1822 + HBufC16* buf = aData.AllocL();
1.1823 + SetData(buf);
1.1824 + }
1.1825 +
1.1826 +/**
1.1827 + Sets internal data buffer and parser. Cleans up the old data and uses the data buffer. The
1.1828 + parser is set to the new data.
1.1829 +
1.1830 + @since 6.0
1.1831 + @param aDataBuf A pointer to a decriptor buffer with the new data.
1.1832 + @post The internal data buffer now points to the new buffer and the parser
1.1833 + is set to the data in the new buffer..
1.1834 + */
1.1835 +void CDelimitedDataBase16::SetData(HBufC16* aDataBuf)
1.1836 + {
1.1837 + delete iDataBuf;
1.1838 + iDataBuf = aDataBuf;
1.1839 + iParser.iDataDes.Set(*iDataBuf);
1.1840 + }
1.1841 +
1.1842 +//
1.1843 +//
1.1844 +// Implementation of LOCAL functions
1.1845 +//
1.1846 +//
1.1847 +
1.1848 +/**
1.1849 + Finds the position of the next delimiter in the data.
1.1850 +
1.1851 + @since 6.0
1.1852 + @param aData A descriptor with the delimited data.
1.1853 + @param aStartPos The position from where to start the search for the delimiter.
1.1854 + @param aDelimiter The delimiting character.
1.1855 + @param aMode The parsing mode.
1.1856 + @return The position of delimiter after the specified start position, or
1.1857 + an error value of KErrNotFound if no more delimiters are found.
1.1858 + @pre None
1.1859 + @post Unspecified
1.1860 + */
1.1861 +template<class TDesCType>
1.1862 +TInt NextDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
1.1863 + {
1.1864 + if( aStartPos == KErrNotFound )
1.1865 + {
1.1866 + // Have got to the end - initialise the iterator
1.1867 + return InitialDelimiterPosition(aData, aMode);
1.1868 + }
1.1869 + TInt next = KErrNotFound;
1.1870 + switch( aMode )
1.1871 + {
1.1872 + case EDelimitedDataForward:
1.1873 + {
1.1874 + // Search parsed string for next delimiter
1.1875 + next = LeftDelimiterPosition(aData, aStartPos, aDelimiter);
1.1876 + } break;
1.1877 + case EDelimitedDataReverse:
1.1878 + {
1.1879 + // Search parsed string for next delimiter
1.1880 + next = RightDelimiterPosition(aData, aStartPos, aDelimiter);
1.1881 + } break;
1.1882 + default:
1.1883 + // Bad mode!
1.1884 + User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1.1885 + break;
1.1886 + }
1.1887 + return next;
1.1888 + }
1.1889 +
1.1890 +
1.1891 +/**
1.1892 + Finds the position of the previous delimiter in the data from the given start position.
1.1893 +
1.1894 + @since 6.0
1.1895 + @param aData A descriptor with the delimited data.
1.1896 + @param aStartPos The position from where to start the search for the delimiter.
1.1897 + @param aDelimiter The delimiting character.
1.1898 + @param aMode The parsing mode.
1.1899 + @return The position of delimiter before the specified start position, or
1.1900 + an error value of KErrNotFound if no more delimiters are found.
1.1901 + @pre None
1.1902 + @post Unspecified
1.1903 + */
1.1904 +template<class TDesCType>
1.1905 +TInt PrevDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter, TDelimitedDataParseMode aMode)
1.1906 + {
1.1907 + // Switch modes, then find the next delimiter, switch back
1.1908 + TDelimitedDataParseMode mode = aMode == EDelimitedDataForward ? EDelimitedDataReverse : EDelimitedDataForward;
1.1909 + return NextDelimiterPosition(aData, aStartPos, aDelimiter, mode);
1.1910 + }
1.1911 +
1.1912 +/**
1.1913 + Finds the position of the delimiter to the right of the given start position.
1.1914 +
1.1915 + @since 6.0
1.1916 + @param aData A descriptor with the delimited data.
1.1917 + @param aStartPos The position from where to start the search for the delimiter.
1.1918 + @param aDelimiter The delimiting character.
1.1919 + @return The position of delimiter to the right of the specified start position, or
1.1920 + an error value of KErrNotFound if no more delimiters are found.
1.1921 + @pre None
1.1922 + @post Unspecified
1.1923 + */
1.1924 +template<class TDesCType>
1.1925 +TInt RightDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
1.1926 + {
1.1927 + // Find position of right-most delimiter in the descriptor data to left of aStartPos
1.1928 + if( aStartPos == 0 )
1.1929 + {
1.1930 + // There is no data
1.1931 + return KErrNotFound;
1.1932 + }
1.1933 + TInt rightDelimiterPos = aData.Left(aStartPos).LocateReverse(aDelimiter);
1.1934 +
1.1935 + // See if a delimiter was found
1.1936 + if( rightDelimiterPos == KErrNotFound )
1.1937 + {
1.1938 + // No - start of string delimits
1.1939 + rightDelimiterPos = 0;
1.1940 + }
1.1941 + return rightDelimiterPos;
1.1942 + }
1.1943 +
1.1944 +/**
1.1945 + Finds the position of the delimiter to the left of the given start position.
1.1946 +
1.1947 + @since 6.0
1.1948 + @param aData A descriptor with the delimited data.
1.1949 + @param aStartPos The position from where to start the search for the delimiter.
1.1950 + @param aDelimiter The delimiting character.
1.1951 + @return The position of delimiter to the left of the specified start position, or
1.1952 + an error value of KErrNotFound if no more delimiters are found.
1.1953 + @pre None
1.1954 + @post Unspecified
1.1955 + */
1.1956 +template<class TDesCType>
1.1957 +TInt LeftDelimiterPosition(const TDesCType& aData, TInt aStartPos, TInt aDelimiter)
1.1958 + {
1.1959 + // Find position of left-most delimiter in the descriptor data to right of aStartPos
1.1960 + const TInt length = aData.Length();
1.1961 + TInt rightLength = length - aStartPos;
1.1962 + if( rightLength == 0 )
1.1963 + {
1.1964 + // There is no data
1.1965 + return KErrNotFound;
1.1966 + }
1.1967 + // Ok there is some string to search - remove delimiter
1.1968 + --rightLength;
1.1969 + TInt leftDelimiterPos = aData.Right(rightLength).Locate(aDelimiter);
1.1970 +
1.1971 + // See if a delimiter was found
1.1972 + if( leftDelimiterPos == KErrNotFound )
1.1973 + {
1.1974 + // No - end of string delimits
1.1975 + leftDelimiterPos = length;
1.1976 + }
1.1977 + else
1.1978 + {
1.1979 + // Offset the delimiter found - include delimiter that was removed
1.1980 + leftDelimiterPos += aStartPos + 1;
1.1981 + }
1.1982 + return leftDelimiterPos;
1.1983 + }
1.1984 +
1.1985 +/**
1.1986 + Retrieves the initial position for searching delimited data for a given parsing mode.
1.1987 +
1.1988 + @since 6.0
1.1989 + @param aData A descriptor with the delimited data.
1.1990 + @param aMode The parsing mode.
1.1991 + @return The initial position for parsing the data.
1.1992 + @pre None
1.1993 + @post Unspecified
1.1994 + */
1.1995 +template<class TDesCType>
1.1996 +TInt InitialDelimiterPosition(const TDesCType& aData, TDelimitedDataParseMode aMode)
1.1997 +//
1.1998 +// Initialises iNextSegmentPos
1.1999 + {
1.2000 + TInt initPos = KErrNotFound;
1.2001 + switch( aMode )
1.2002 + {
1.2003 + case EDelimitedDataForward:
1.2004 + {
1.2005 + // Search parsed string for next delimiter
1.2006 + initPos = 0;
1.2007 + } break;
1.2008 + case EDelimitedDataReverse:
1.2009 + {
1.2010 + // Search parsed string for next delimiter
1.2011 + initPos = aData.Length();
1.2012 + } break;
1.2013 + default:
1.2014 + // Bad mode!
1.2015 + User::Panic(KDelimitedParserPanicCategory, KUriUtilsErrBadDelimitedParserMode);
1.2016 + break;
1.2017 + }
1.2018 + return initPos;
1.2019 + }
1.2020 +