Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <stdio.h>
21 : #include <svtools/svparser.hxx>
22 : #include <tools/stream.hxx>
23 : #include <tools/debug.hxx>
24 : #include <rtl/textcvt.h>
25 : #include <rtl/tencinfo.h>
26 :
27 : // structure to store the actuel data
28 0 : struct SvParser_Impl
29 : {
30 : OUString aToken; // gescanntes Token
31 : sal_uLong nFilePos; // actual position in stream
32 : sal_uLong nlLineNr; // actual line number
33 : sal_uLong nlLinePos; // actual column number
34 : long nTokenValue; // extra value (RTF)
35 : sal_Bool bTokenHasValue; // indicates whether nTokenValue is valid
36 : int nToken; // actual Token
37 : sal_Unicode nNextCh; // actual character
38 : int nSaveToken; // the token from Continue
39 :
40 : rtl_TextToUnicodeConverter hConv;
41 : rtl_TextToUnicodeContext hContext;
42 :
43 0 : SvParser_Impl() :
44 0 : nTokenValue(0), nToken(0), nSaveToken(0), hConv( 0 ), hContext( (rtl_TextToUnicodeContext)1 )
45 : {
46 0 : }
47 :
48 : };
49 :
50 :
51 :
52 : // Construktor
53 0 : SvParser::SvParser( SvStream& rIn, sal_uInt8 nStackSize )
54 : : rInput( rIn )
55 : , nlLineNr( 1 )
56 : , nlLinePos( 1 )
57 : , pImplData( 0 )
58 : , nTokenValue( 0 )
59 : , bTokenHasValue( false )
60 : , eState( SVPAR_NOTSTARTED )
61 : , eSrcEnc( RTL_TEXTENCODING_DONTKNOW )
62 : , nNextChPos(0)
63 : , bDownloadingFile(false)
64 : , bUCS2BSrcEnc(false)
65 : , bSwitchToUCS2(false)
66 : , bRTF_InTextRead(false)
67 : , nTokenStackSize( nStackSize )
68 0 : , nTokenStackPos( 0 )
69 : {
70 0 : eState = SVPAR_NOTSTARTED;
71 0 : if( nTokenStackSize < 3 )
72 0 : nTokenStackSize = 3;
73 0 : pTokenStack = new TokenStackType[ nTokenStackSize ];
74 0 : pTokenStackPos = pTokenStack;
75 0 : }
76 :
77 0 : SvParser::~SvParser()
78 : {
79 0 : if( pImplData && pImplData->hConv )
80 : {
81 : rtl_destroyTextToUnicodeContext( pImplData->hConv,
82 0 : pImplData->hContext );
83 0 : rtl_destroyTextToUnicodeConverter( pImplData->hConv );
84 : }
85 :
86 0 : delete pImplData;
87 :
88 0 : delete [] pTokenStack;
89 0 : }
90 :
91 0 : void SvParser::ClearTxtConvContext()
92 : {
93 0 : if( pImplData && pImplData->hConv )
94 0 : rtl_resetTextToUnicodeContext( pImplData->hConv, pImplData->hContext );
95 0 : }
96 :
97 0 : void SvParser::SetSrcEncoding( rtl_TextEncoding eEnc )
98 : {
99 :
100 0 : if( eEnc != eSrcEnc )
101 : {
102 0 : if( pImplData && pImplData->hConv )
103 : {
104 : rtl_destroyTextToUnicodeContext( pImplData->hConv,
105 0 : pImplData->hContext );
106 0 : rtl_destroyTextToUnicodeConverter( pImplData->hConv );
107 0 : pImplData->hConv = 0;
108 0 : pImplData->hContext = (rtl_TextToUnicodeContext )1;
109 : }
110 :
111 0 : if( rtl_isOctetTextEncoding(eEnc) ||
112 : RTL_TEXTENCODING_UCS2 == eEnc )
113 : {
114 0 : eSrcEnc = eEnc;
115 0 : if( !pImplData )
116 0 : pImplData = new SvParser_Impl;
117 0 : pImplData->hConv = rtl_createTextToUnicodeConverter( eSrcEnc );
118 : DBG_ASSERT( pImplData->hConv,
119 : "SvParser::SetSrcEncoding: no converter for source encoding" );
120 0 : if( !pImplData->hConv )
121 0 : eSrcEnc = RTL_TEXTENCODING_DONTKNOW;
122 : else
123 : pImplData->hContext =
124 0 : rtl_createTextToUnicodeContext( pImplData->hConv );
125 : }
126 : else
127 : {
128 : DBG_ASSERT( !this,
129 : "SvParser::SetSrcEncoding: invalid source encoding" );
130 0 : eSrcEnc = RTL_TEXTENCODING_DONTKNOW;
131 : }
132 : }
133 0 : }
134 :
135 0 : void SvParser::RereadLookahead()
136 : {
137 0 : rInput.Seek(nNextChPos);
138 0 : nNextCh = GetNextChar();
139 0 : }
140 :
141 0 : sal_Unicode SvParser::GetNextChar()
142 : {
143 0 : sal_Unicode c = 0U;
144 :
145 : // When reading muliple bytes, we don't have to care about the file
146 : // position when we run inti the pending state. The file position is
147 : // maintained by SaveState/RestoreState.
148 : sal_Bool bErr;
149 0 : if( bSwitchToUCS2 && 0 == rInput.Tell() )
150 : {
151 : unsigned char c1, c2;
152 0 : sal_Bool bSeekBack = sal_True;
153 :
154 0 : rInput.ReadUChar( c1 );
155 0 : bErr = rInput.IsEof() || rInput.GetError();
156 0 : if( !bErr )
157 : {
158 0 : if( 0xff == c1 || 0xfe == c1 )
159 : {
160 0 : rInput.ReadUChar( c2 );
161 0 : bErr = rInput.IsEof() || rInput.GetError();
162 0 : if( !bErr )
163 : {
164 0 : if( 0xfe == c1 && 0xff == c2 )
165 : {
166 0 : eSrcEnc = RTL_TEXTENCODING_UCS2;
167 0 : bUCS2BSrcEnc = true;
168 0 : bSeekBack = false;
169 : }
170 0 : else if( 0xff == c1 && 0xfe == c2 )
171 : {
172 0 : eSrcEnc = RTL_TEXTENCODING_UCS2;
173 0 : bUCS2BSrcEnc = false;
174 0 : bSeekBack = false;
175 : }
176 : }
177 : }
178 : }
179 0 : if( bSeekBack )
180 0 : rInput.Seek( 0 );
181 :
182 0 : bSwitchToUCS2 = false;
183 : }
184 :
185 0 : nNextChPos = rInput.Tell();
186 :
187 0 : if( RTL_TEXTENCODING_UCS2 == eSrcEnc )
188 : {
189 0 : sal_Unicode cUC = USHRT_MAX;
190 : unsigned char c1, c2;
191 :
192 0 : rInput.ReadUChar( c1 ).ReadUChar( c2 );
193 0 : if( 2 == rInput.Tell() &&
194 0 : !(rInput.IsEof() || rInput.GetError()) &&
195 0 : ( (bUCS2BSrcEnc && 0xfe == c1 && 0xff == c2) ||
196 0 : (!bUCS2BSrcEnc && 0xff == c1 && 0xfe == c2) ) )
197 0 : rInput.ReadUChar( c1 ).ReadUChar( c2 );
198 :
199 0 : bErr = rInput.IsEof() || rInput.GetError();
200 0 : if( !bErr )
201 : {
202 0 : if( bUCS2BSrcEnc )
203 0 : cUC = (sal_Unicode(c1) << 8) | c2;
204 : else
205 0 : cUC = (sal_Unicode(c2) << 8) | c1;
206 : }
207 :
208 0 : if( !bErr )
209 : {
210 0 : c = cUC;
211 : }
212 : }
213 : else
214 : {
215 0 : sal_Size nChars = 0;
216 0 : do
217 : {
218 : sal_Char c1; // signed, that's the text converter expects
219 0 : rInput.ReadChar( c1 );
220 0 : bErr = rInput.IsEof() || rInput.GetError();
221 0 : if( !bErr )
222 : {
223 0 : if (
224 0 : RTL_TEXTENCODING_DONTKNOW == eSrcEnc ||
225 0 : RTL_TEXTENCODING_SYMBOL == eSrcEnc
226 : )
227 : {
228 : // no convserion shall take place
229 0 : c = (sal_Unicode)c1;
230 0 : nChars = 1;
231 : }
232 : else
233 : {
234 : DBG_ASSERT( pImplData && pImplData->hConv,
235 : "no text converter!" );
236 :
237 : sal_Unicode cUC;
238 0 : sal_uInt32 nInfo = 0;
239 : sal_Size nCvtBytes;
240 : nChars = rtl_convertTextToUnicode(
241 : pImplData->hConv, pImplData->hContext,
242 : &c1, 1, &cUC, 1,
243 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
244 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
245 : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
246 0 : &nInfo, &nCvtBytes);
247 0 : if( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 )
248 : {
249 : // The conversion wasn't successful because we haven't
250 : // read enough characters.
251 0 : if( pImplData->hContext != (rtl_TextToUnicodeContext)1 )
252 : {
253 0 : while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 )
254 : {
255 0 : rInput.ReadChar( c1 );
256 0 : bErr = rInput.IsEof() || rInput.GetError();
257 0 : if( bErr )
258 0 : break;
259 :
260 : nChars = rtl_convertTextToUnicode(
261 : pImplData->hConv, pImplData->hContext,
262 : &c1, 1, &cUC, 1,
263 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
264 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
265 : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
266 0 : &nInfo, &nCvtBytes);
267 : }
268 0 : if( !bErr )
269 : {
270 0 : if( 1 == nChars && 0 == nInfo )
271 : {
272 0 : c = cUC;
273 : }
274 0 : else if( 0 != nChars || 0 != nInfo )
275 : {
276 : DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0,
277 : "source buffer is to small" );
278 : DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0,
279 : "there is a conversion error" );
280 : DBG_ASSERT( 0 == nChars,
281 : "there is a converted character, but an error" );
282 : // There are still errors, but nothing we can
283 : // do
284 0 : c = (sal_Unicode)'?';
285 0 : nChars = 1;
286 : }
287 : }
288 : }
289 : else
290 : {
291 : sal_Char sBuffer[10];
292 0 : sBuffer[0] = c1;
293 0 : sal_uInt16 nLen = 1;
294 0 : while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 &&
295 : nLen < 10 )
296 : {
297 0 : rInput.ReadChar( c1 );
298 0 : bErr = rInput.IsEof() || rInput.GetError();
299 0 : if( bErr )
300 0 : break;
301 :
302 0 : sBuffer[nLen++] = c1;
303 : nChars = rtl_convertTextToUnicode(
304 : pImplData->hConv, 0, sBuffer, nLen, &cUC, 1,
305 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
306 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
307 : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
308 0 : &nInfo, &nCvtBytes);
309 : }
310 0 : if( !bErr )
311 : {
312 0 : if( 1 == nChars && 0 == nInfo )
313 : {
314 : DBG_ASSERT( nCvtBytes == nLen,
315 : "no all bytes have been converted!" );
316 0 : c = cUC;
317 : }
318 : else
319 : {
320 : DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0,
321 : "source buffer is to small" );
322 : DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0,
323 : "there is a conversion error" );
324 : DBG_ASSERT( 0 == nChars,
325 : "there is a converted character, but an error" );
326 :
327 : // There are still errors, so we use the first
328 : // character and restart after that.
329 0 : c = (sal_Unicode)sBuffer[0];
330 0 : rInput.SeekRel( -(nLen-1) );
331 0 : nChars = 1;
332 : }
333 : }
334 : }
335 : }
336 0 : else if( 1 == nChars && 0 == nInfo )
337 : {
338 : // The conversion was successful
339 : DBG_ASSERT( nCvtBytes == 1,
340 : "no all bytes have been converted!" );
341 0 : c = cUC;
342 : }
343 0 : else if( 0 != nChars || 0 != nInfo )
344 : {
345 : DBG_ASSERT( 0 == nChars,
346 : "there is a converted character, but an error" );
347 : DBG_ASSERT( 0 != nInfo,
348 : "there is no converted character and no error" );
349 : // #73398#: If the character could not be converted,
350 : // because a conversion is not available, do no conversion at all.
351 0 : c = (sal_Unicode)c1;
352 0 : nChars = 1;
353 :
354 : }
355 : }
356 : }
357 : }
358 0 : while( 0 == nChars && !bErr );
359 : }
360 0 : if( bErr )
361 : {
362 0 : if( ERRCODE_IO_PENDING == rInput.GetError() )
363 : {
364 0 : eState = SVPAR_PENDING;
365 0 : return c;
366 : }
367 : else
368 0 : return sal_Unicode(EOF);
369 : }
370 :
371 0 : if( c == '\n' )
372 : {
373 0 : IncLineNr();
374 0 : SetLinePos( 1L );
375 : }
376 : else
377 0 : IncLinePos();
378 0 : return c;
379 : }
380 :
381 0 : int SvParser::GetNextToken()
382 : {
383 0 : int nRet = 0;
384 :
385 0 : if( !nTokenStackPos )
386 : {
387 0 : aToken = ""; // empty token buffer
388 0 : nTokenValue = -1; // marker for no value read
389 0 : bTokenHasValue = false;
390 :
391 0 : nRet = _GetNextToken();
392 0 : if( SVPAR_PENDING == eState )
393 0 : return nRet;
394 : }
395 :
396 0 : ++pTokenStackPos;
397 0 : if( pTokenStackPos == pTokenStack + nTokenStackSize )
398 0 : pTokenStackPos = pTokenStack;
399 :
400 : // pop from stack ??
401 0 : if( nTokenStackPos )
402 : {
403 0 : --nTokenStackPos;
404 0 : nTokenValue = pTokenStackPos->nTokenValue;
405 0 : bTokenHasValue = pTokenStackPos->bTokenHasValue;
406 0 : aToken = pTokenStackPos->sToken;
407 0 : nRet = pTokenStackPos->nTokenId;
408 : }
409 : // no, now push actual value on stack
410 0 : else if( SVPAR_WORKING == eState )
411 : {
412 0 : pTokenStackPos->sToken = aToken;
413 0 : pTokenStackPos->nTokenValue = nTokenValue;
414 0 : pTokenStackPos->bTokenHasValue = bTokenHasValue;
415 0 : pTokenStackPos->nTokenId = nRet;
416 : }
417 0 : else if( SVPAR_ACCEPTED != eState && SVPAR_PENDING != eState )
418 0 : eState = SVPAR_ERROR; // an error occured
419 :
420 0 : return nRet;
421 : }
422 :
423 0 : int SvParser::SkipToken( short nCnt ) // "skip" n Tokens backward
424 : {
425 0 : pTokenStackPos = GetStackPtr( nCnt );
426 0 : short nTmp = nTokenStackPos - nCnt;
427 0 : if( nTmp < 0 )
428 0 : nTmp = 0;
429 0 : else if( nTmp > nTokenStackSize )
430 0 : nTmp = nTokenStackSize;
431 0 : nTokenStackPos = sal_uInt8(nTmp);
432 :
433 : // restore values
434 0 : aToken = pTokenStackPos->sToken;
435 0 : nTokenValue = pTokenStackPos->nTokenValue;
436 0 : bTokenHasValue = pTokenStackPos->bTokenHasValue;
437 :
438 0 : return pTokenStackPos->nTokenId;
439 : }
440 :
441 0 : SvParser::TokenStackType* SvParser::GetStackPtr( short nCnt )
442 : {
443 0 : sal_uInt8 nAktPos = sal_uInt8(pTokenStackPos - pTokenStack );
444 0 : if( nCnt > 0 )
445 : {
446 0 : if( nCnt >= nTokenStackSize )
447 0 : nCnt = (nTokenStackSize-1);
448 0 : if( nAktPos + nCnt < nTokenStackSize )
449 0 : nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt);
450 : else
451 : nAktPos = sal::static_int_cast< sal_uInt8 >(
452 0 : nAktPos + (nCnt - nTokenStackSize));
453 : }
454 0 : else if( nCnt < 0 )
455 : {
456 0 : if( -nCnt >= nTokenStackSize )
457 0 : nCnt = -nTokenStackSize+1;
458 0 : if( -nCnt <= nAktPos )
459 0 : nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt);
460 : else
461 : nAktPos = sal::static_int_cast< sal_uInt8 >(
462 0 : nAktPos + (nCnt + nTokenStackSize));
463 : }
464 0 : return pTokenStack + nAktPos;
465 : }
466 :
467 : // is called for each token which is recognised by CallParser
468 0 : void SvParser::NextToken( int )
469 : {
470 0 : }
471 :
472 :
473 : // to read asynchronous from SvStream
474 :
475 0 : int SvParser::GetSaveToken() const
476 : {
477 0 : return pImplData ? pImplData->nSaveToken : 0;
478 : }
479 :
480 0 : void SvParser::SaveState( int nToken )
481 : {
482 : // save actual status
483 0 : if( !pImplData )
484 : {
485 0 : pImplData = new SvParser_Impl;
486 0 : pImplData->nSaveToken = 0;
487 : }
488 :
489 0 : pImplData->nFilePos = rInput.Tell();
490 0 : pImplData->nToken = nToken;
491 :
492 0 : pImplData->aToken = aToken;
493 0 : pImplData->nlLineNr = nlLineNr;
494 0 : pImplData->nlLinePos = nlLinePos;
495 0 : pImplData->nTokenValue= nTokenValue;
496 0 : pImplData->bTokenHasValue = bTokenHasValue;
497 0 : pImplData->nNextCh = nNextCh;
498 0 : }
499 :
500 0 : void SvParser::RestoreState()
501 : {
502 : // restore old status
503 0 : if( pImplData )
504 : {
505 0 : if( ERRCODE_IO_PENDING == rInput.GetError() )
506 0 : rInput.ResetError();
507 0 : aToken = pImplData->aToken;
508 0 : nlLineNr = pImplData->nlLineNr;
509 0 : nlLinePos = pImplData->nlLinePos;
510 0 : nTokenValue= pImplData->nTokenValue;
511 0 : bTokenHasValue=pImplData->bTokenHasValue;
512 0 : nNextCh = pImplData->nNextCh;
513 :
514 0 : pImplData->nSaveToken = pImplData->nToken;
515 :
516 0 : rInput.Seek( pImplData->nFilePos );
517 : }
518 0 : }
519 :
520 0 : void SvParser::Continue( int )
521 : {
522 0 : }
523 :
524 0 : void SvParser::BuildWhichTbl( std::vector<sal_uInt16> &rWhichMap,
525 : sal_uInt16 *pWhichIds,
526 : sal_uInt16 nWhichIds )
527 : {
528 : sal_uInt16 aNewRange[2];
529 :
530 0 : for( sal_uInt16 nCnt = 0; nCnt < nWhichIds; ++nCnt, ++pWhichIds )
531 0 : if( *pWhichIds )
532 : {
533 0 : aNewRange[0] = aNewRange[1] = *pWhichIds;
534 0 : sal_Bool bIns = sal_True;
535 :
536 : // search position
537 0 : for ( sal_uInt16 nOfs = 0; rWhichMap[nOfs]; nOfs += 2 )
538 : {
539 0 : if( *pWhichIds < rWhichMap[nOfs] - 1 )
540 : {
541 : // new range before
542 0 : rWhichMap.insert( rWhichMap.begin() + nOfs, aNewRange, aNewRange + 2 );
543 0 : bIns = sal_False;
544 0 : break;
545 : }
546 0 : else if( *pWhichIds == rWhichMap[nOfs] - 1 )
547 : {
548 : // extend range downwards
549 0 : rWhichMap[nOfs] = *pWhichIds;
550 0 : bIns = sal_False;
551 0 : break;
552 : }
553 0 : else if( *pWhichIds == rWhichMap[nOfs+1] + 1 )
554 : {
555 0 : if( rWhichMap[nOfs+2] != 0 && rWhichMap[nOfs+2] == *pWhichIds + 1 )
556 : {
557 : // merge with next field
558 0 : rWhichMap[nOfs+1] = rWhichMap[nOfs+3];
559 0 : rWhichMap.erase( rWhichMap.begin() + nOfs + 2,
560 0 : rWhichMap.begin() + nOfs + 4 );
561 : }
562 : else
563 : // extend range upwards
564 0 : rWhichMap[nOfs+1] = *pWhichIds;
565 0 : bIns = sal_False;
566 0 : break;
567 : }
568 : }
569 :
570 : // append range
571 0 : if( bIns )
572 : {
573 0 : rWhichMap.insert( rWhichMap.begin() + rWhichMap.size() - 1,
574 0 : aNewRange, aNewRange + 2 );
575 : }
576 : }
577 0 : }
578 :
579 :
580 0 : IMPL_STATIC_LINK( SvParser, NewDataRead, void*, EMPTYARG )
581 : {
582 0 : switch( pThis->eState )
583 : {
584 : case SVPAR_PENDING:
585 : // if file is loaded we are not allowed to continue
586 : // instead should ignore the call.
587 0 : if( pThis->IsDownloadingFile() )
588 0 : break;
589 :
590 0 : pThis->eState = SVPAR_WORKING;
591 0 : pThis->RestoreState();
592 :
593 0 : pThis->Continue( pThis->pImplData->nToken );
594 :
595 0 : if( ERRCODE_IO_PENDING == pThis->rInput.GetError() )
596 0 : pThis->rInput.ResetError();
597 :
598 0 : if( SVPAR_PENDING != pThis->eState )
599 0 : pThis->ReleaseRef(); // ready otherwise!
600 0 : break;
601 :
602 : case SVPAR_WAITFORDATA:
603 0 : pThis->eState = SVPAR_WORKING;
604 0 : break;
605 :
606 : case SVPAR_NOTSTARTED:
607 : case SVPAR_WORKING:
608 0 : break;
609 :
610 : default:
611 0 : pThis->ReleaseRef(); // ready otherwise!
612 0 : break;
613 : }
614 :
615 0 : return 0;
616 : }
617 :
618 : /*========================================================================
619 : *
620 : * SvKeyValueIterator.
621 : *
622 : *======================================================================*/
623 :
624 : /*
625 : * SvKeyValueIterator.
626 : */
627 0 : SvKeyValueIterator::SvKeyValueIterator (void)
628 0 : : m_pList (new SvKeyValueList_Impl),
629 0 : m_nPos (0)
630 : {
631 0 : }
632 :
633 : /*
634 : * ~SvKeyValueIterator.
635 : */
636 0 : SvKeyValueIterator::~SvKeyValueIterator (void)
637 : {
638 0 : delete m_pList;
639 0 : }
640 :
641 : /*
642 : * GetFirst.
643 : */
644 0 : bool SvKeyValueIterator::GetFirst (SvKeyValue &rKeyVal)
645 : {
646 0 : m_nPos = m_pList->size();
647 0 : return GetNext (rKeyVal);
648 : }
649 :
650 : /*
651 : * GetNext.
652 : */
653 0 : bool SvKeyValueIterator::GetNext (SvKeyValue &rKeyVal)
654 : {
655 0 : if (m_nPos > 0)
656 : {
657 0 : rKeyVal = (*m_pList)[--m_nPos];
658 0 : return true;
659 : }
660 : else
661 : {
662 : // Nothing to do.
663 0 : return false;
664 : }
665 : }
666 :
667 : /*
668 : * Append.
669 : */
670 0 : void SvKeyValueIterator::Append (const SvKeyValue &rKeyVal)
671 : {
672 0 : m_pList->push_back(new SvKeyValue(rKeyVal));
673 0 : }
674 :
675 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|