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