1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26
27 #include <stdio.h>
28 #include <svtools/svparser.hxx>
29 #include <tools/stream.hxx>
30 #include <tools/debug.hxx>
31 #define _SVSTDARR_USHORTS
32 #include <svl/svstdarr.hxx>
33 #include <rtl/textcvt.h>
34 #include <rtl/tencinfo.h>
35
36 #define SVPAR_CSM_
37
38 #define SVPAR_CSM_ANSI 0x0001U
39 #define SVPAR_CSM_UTF8 0x0002U
40 #define SVPAR_CSM_UCS2B 0x0004U
41 #define SVPAR_CSM_UCS2L 0x0008U
42 #define SVPAR_CSM_SWITCH 0x8000U
43
44 // Struktur, um sich die akt. Daten zumerken
45 struct SvParser_Impl
46 {
47 String aToken; // gescanntes Token
48 sal_uLong nFilePos; // akt. Position im Stream
49 sal_uLong nlLineNr; // akt. Zeilen Nummer
50 sal_uLong nlLinePos; // akt. Spalten Nummer
51 long nTokenValue; // zusaetzlicher Wert (RTF)
52 sal_Bool bTokenHasValue; // indicates whether nTokenValue is valid
53 int nToken; // akt. Token
54 sal_Unicode nNextCh; // akt. Zeichen
55
56 int nSaveToken; // das Token vom Continue
57
58 rtl_TextToUnicodeConverter hConv;
59 rtl_TextToUnicodeContext hContext;
60
61 #ifdef DBG_UTIL
62 SvFileStream aOut;
63 #endif
64
SvParser_ImplSvParser_Impl65 SvParser_Impl() :
66 nSaveToken(0), hConv( 0 ), hContext( (rtl_TextToUnicodeContext)1 )
67 {
68 }
69
70 };
71
72
73
74 // Konstruktor
SvParser(SvStream & rIn,sal_uInt8 nStackSize)75 SvParser::SvParser( SvStream& rIn, sal_uInt8 nStackSize )
76 : rInput( rIn )
77 , nlLineNr( 1 )
78 , nlLinePos( 1 )
79 , pImplData( 0 )
80 , nTokenValue( 0 )
81 , bTokenHasValue( false )
82 , eState( SVPAR_NOTSTARTED )
83 , eSrcEnc( RTL_TEXTENCODING_DONTKNOW )
84 , bDownloadingFile( sal_False )
85 , nTokenStackSize( nStackSize )
86 , nTokenStackPos( 0 )
87 {
88 bUCS2BSrcEnc = bSwitchToUCS2 = sal_False;
89 eState = SVPAR_NOTSTARTED;
90 if( nTokenStackSize < 3 )
91 nTokenStackSize = 3;
92 pTokenStack = new TokenStackType[ nTokenStackSize ];
93 pTokenStackPos = pTokenStack;
94
95 #ifdef DBG_UTIL
96
97 // wenn die Datei schon existiert, dann Anhaengen:
98 if( !pImplData )
99 pImplData = new SvParser_Impl;
100 pImplData->aOut.Open( String::CreateFromAscii( "\\parser.dmp" ),
101 STREAM_STD_WRITE | STREAM_NOCREATE );
102 if( pImplData->aOut.GetError() || !pImplData->aOut.IsOpen() )
103 pImplData->aOut.Close();
104 else
105 {
106 pImplData->aOut.Seek( STREAM_SEEK_TO_END );
107 pImplData->aOut << "\x0c\n\n >>>>>>>>>>>>>>> Dump Start <<<<<<<<<<<<<<<\n";
108 }
109 #endif
110 }
111
~SvParser()112 SvParser::~SvParser()
113 {
114 #ifdef DBG_UTIL
115 if( pImplData->aOut.IsOpen() )
116 pImplData->aOut << "\n\n >>>>>>>>>>>>>>> Dump Ende <<<<<<<<<<<<<<<\n";
117 pImplData->aOut.Close();
118 #endif
119
120 if( pImplData && pImplData->hConv )
121 {
122 rtl_destroyTextToUnicodeContext( pImplData->hConv,
123 pImplData->hContext );
124 rtl_destroyTextToUnicodeConverter( pImplData->hConv );
125 }
126
127 delete pImplData;
128
129 delete [] pTokenStack;
130 }
131
ClearTxtConvContext()132 void SvParser::ClearTxtConvContext()
133 {
134 if( pImplData && pImplData->hConv )
135 rtl_resetTextToUnicodeContext( pImplData->hConv, pImplData->hContext );
136 }
137
SetSrcEncoding(rtl_TextEncoding eEnc)138 void SvParser::SetSrcEncoding( rtl_TextEncoding eEnc )
139 {
140
141 if( eEnc != eSrcEnc )
142 {
143 if( pImplData && pImplData->hConv )
144 {
145 rtl_destroyTextToUnicodeContext( pImplData->hConv,
146 pImplData->hContext );
147 rtl_destroyTextToUnicodeConverter( pImplData->hConv );
148 pImplData->hConv = 0;
149 pImplData->hContext = (rtl_TextToUnicodeContext )1;
150 }
151
152 if( rtl_isOctetTextEncoding(eEnc) ||
153 RTL_TEXTENCODING_UCS2 == eEnc )
154 {
155 eSrcEnc = eEnc;
156 if( !pImplData )
157 pImplData = new SvParser_Impl;
158 pImplData->hConv = rtl_createTextToUnicodeConverter( eSrcEnc );
159 DBG_ASSERT( pImplData->hConv,
160 "SvParser::SetSrcEncoding: no converter for source encoding" );
161 if( !pImplData->hConv )
162 eSrcEnc = RTL_TEXTENCODING_DONTKNOW;
163 else
164 pImplData->hContext =
165 rtl_createTextToUnicodeContext( pImplData->hConv );
166 }
167 else
168 {
169 DBG_ASSERT( sal_False,
170 "SvParser::SetSrcEncoding: invalid source encoding" );
171 eSrcEnc = RTL_TEXTENCODING_DONTKNOW;
172 }
173 }
174 }
175
RereadLookahead()176 void SvParser::RereadLookahead()
177 {
178 rInput.Seek(nNextChPos);
179 nNextCh = GetNextChar();
180 }
181
GetNextChar()182 sal_Unicode SvParser::GetNextChar()
183 {
184 sal_Unicode c = 0U;
185
186 // When reading multiple bytes, we don't have to care about the file
187 // position when we run inti the pending state. The file position is
188 // maintained by SaveState/RestoreState.
189 sal_Bool bErr;
190 if( bSwitchToUCS2 && 0 == rInput.Tell() )
191 {
192 sal_uChar c1, c2;
193 sal_Bool bSeekBack = sal_True;
194
195 rInput >> c1;
196 bErr = rInput.IsEof() || rInput.GetError();
197 if( !bErr )
198 {
199 if( 0xff == c1 || 0xfe == c1 )
200 {
201 rInput >> c2;
202 bErr = rInput.IsEof() || rInput.GetError();
203 if( !bErr )
204 {
205 if( 0xfe == c1 && 0xff == c2 )
206 {
207 eSrcEnc = RTL_TEXTENCODING_UCS2;
208 bUCS2BSrcEnc = sal_True;
209 bSeekBack = sal_False;
210 }
211 else if( 0xff == c1 && 0xfe == c2 )
212 {
213 eSrcEnc = RTL_TEXTENCODING_UCS2;
214 bUCS2BSrcEnc = sal_False;
215 bSeekBack = sal_False;
216 }
217 }
218 }
219 }
220 if( bSeekBack )
221 rInput.Seek( 0 );
222
223 bSwitchToUCS2 = sal_False;
224 }
225
226 nNextChPos = rInput.Tell();
227
228 if( RTL_TEXTENCODING_UCS2 == eSrcEnc )
229 {
230 sal_Unicode cUC = USHRT_MAX;
231 sal_uChar c1, c2;
232
233 rInput >> c1 >> c2;
234 if( 2 == rInput.Tell() &&
235 !(rInput.IsEof() || rInput.GetError()) &&
236 ( (bUCS2BSrcEnc && 0xfe == c1 && 0xff == c2) ||
237 (!bUCS2BSrcEnc && 0xff == c1 && 0xfe == c2) ) )
238 rInput >> c1 >> c2;
239
240 bErr = rInput.IsEof() || rInput.GetError();
241 if( !bErr )
242 {
243 if( bUCS2BSrcEnc )
244 cUC = (sal_Unicode(c1) << 8) | c2;
245 else
246 cUC = (sal_Unicode(c2) << 8) | c1;
247 }
248
249 if( !bErr )
250 {
251 c = cUC;
252 }
253 }
254 else
255 {
256 sal_Size nChars = 0;
257 do
258 {
259 sal_Char c1; // signed, that's the text converter expects
260 rInput >> c1;
261 bErr = rInput.IsEof() || rInput.GetError();
262 if( !bErr )
263 {
264 if (
265 RTL_TEXTENCODING_DONTKNOW == eSrcEnc ||
266 RTL_TEXTENCODING_SYMBOL == eSrcEnc
267 )
268 {
269 // no conversion shall take place
270 c = (sal_Unicode)c1;
271 nChars = 1;
272 }
273 else
274 {
275 DBG_ASSERT( pImplData && pImplData->hConv,
276 "no text converter!" );
277
278 sal_Unicode cUC;
279 sal_uInt32 nInfo = 0;
280 sal_Size nCvtBytes;
281 nChars = rtl_convertTextToUnicode(
282 pImplData->hConv, pImplData->hContext,
283 &c1, 1, &cUC, 1,
284 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
285 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
286 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
287 &nInfo, &nCvtBytes);
288 if( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 )
289 {
290 // The conversion wasn't successful because we haven't
291 // read enough characters.
292 if( pImplData->hContext != (rtl_TextToUnicodeContext)1 )
293 {
294 while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 )
295 {
296 rInput >> c1;
297 bErr = rInput.IsEof() || rInput.GetError();
298 if( bErr )
299 break;
300
301 nChars = rtl_convertTextToUnicode(
302 pImplData->hConv, pImplData->hContext,
303 &c1, 1, &cUC, 1,
304 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
305 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
306 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
307 &nInfo, &nCvtBytes);
308 }
309 if( !bErr )
310 {
311 if( 1 == nChars && 0 == nInfo )
312 {
313 c = cUC;
314 }
315 else if( 0 != nChars || 0 != nInfo )
316 {
317 DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0,
318 "source buffer is to small" );
319 DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0,
320 "there is a conversion error" );
321 DBG_ASSERT( 0 == nChars,
322 "there is a converted character, but an error" );
323 // There are still errors, but nothing we can
324 // do
325 c = (sal_Unicode)'?';
326 nChars = 1;
327 }
328 }
329 }
330 else
331 {
332 sal_Char sBuffer[10];
333 sBuffer[0] = c1;
334 sal_uInt16 nLen = 1;
335 while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 &&
336 nLen < 10 )
337 {
338 rInput >> c1;
339 bErr = rInput.IsEof() || rInput.GetError();
340 if( bErr )
341 break;
342
343 sBuffer[nLen++] = c1;
344 nChars = rtl_convertTextToUnicode(
345 pImplData->hConv, 0, sBuffer, nLen, &cUC, 1,
346 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR|
347 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR|
348 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
349 &nInfo, &nCvtBytes);
350 }
351 if( !bErr )
352 {
353 if( 1 == nChars && 0 == nInfo )
354 {
355 DBG_ASSERT( nCvtBytes == nLen,
356 "no all bytes have been converted!" );
357 c = cUC;
358 }
359 else
360 {
361 DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0,
362 "source buffer is to small" );
363 DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0,
364 "there is a conversion error" );
365 DBG_ASSERT( 0 == nChars,
366 "there is a converted character, but an error" );
367
368 // There are still errors, so we use the first
369 // character and restart after that.
370 c = (sal_Unicode)sBuffer[0];
371 rInput.SeekRel( -(nLen-1) );
372 nChars = 1;
373 }
374 }
375 }
376 }
377 else if( 1 == nChars && 0 == nInfo )
378 {
379 // The conversion was successful
380 DBG_ASSERT( nCvtBytes == 1,
381 "no all bytes have been converted!" );
382 c = cUC;
383 }
384 else if( 0 != nChars || 0 != nInfo )
385 {
386 DBG_ASSERT( 0 == nChars,
387 "there is a converted character, but an error" );
388 DBG_ASSERT( 0 != nInfo,
389 "there is no converted character and no error" );
390 // #73398#: If the character could not be converted,
391 // because a conversion is not available, do no conversion at all.
392 c = (sal_Unicode)c1;
393 nChars = 1;
394
395 }
396 }
397 }
398 }
399 while( 0 == nChars && !bErr );
400 }
401 if( bErr )
402 {
403 if( ERRCODE_IO_PENDING == rInput.GetError() )
404 {
405 eState = SVPAR_PENDING;
406 return c;
407 }
408 else
409 return sal_Unicode(EOF);
410 }
411
412 #ifdef DBG_UTIL
413 if( pImplData->aOut.IsOpen() )
414 pImplData->aOut << ByteString::ConvertFromUnicode( c,
415 RTL_TEXTENCODING_MS_1251 );
416 #endif
417
418 if( c == '\n' )
419 {
420 IncLineNr();
421 SetLinePos( 1L );
422 }
423 else
424 IncLinePos();
425 return c;
426 }
427
GetNextToken()428 int SvParser::GetNextToken()
429 {
430 int nRet = 0;
431
432 if( !nTokenStackPos )
433 {
434 aToken.Erase(); // Token-Buffer loeschen
435 nTokenValue = -1; // Kennzeichen fuer kein Value gelesen
436 bTokenHasValue = false;
437
438 nRet = _GetNextToken();
439 if( SVPAR_PENDING == eState )
440 return nRet;
441 }
442
443 ++pTokenStackPos;
444 if( pTokenStackPos == pTokenStack + nTokenStackSize )
445 pTokenStackPos = pTokenStack;
446
447 // vom Stack holen ??
448 if( nTokenStackPos )
449 {
450 --nTokenStackPos;
451 nTokenValue = pTokenStackPos->nTokenValue;
452 bTokenHasValue = pTokenStackPos->bTokenHasValue;
453 aToken = pTokenStackPos->sToken;
454 nRet = pTokenStackPos->nTokenId;
455 }
456 // nein, dann das aktuelle auf den Stack
457 else if( SVPAR_WORKING == eState )
458 {
459 pTokenStackPos->sToken = aToken;
460 pTokenStackPos->nTokenValue = nTokenValue;
461 pTokenStackPos->bTokenHasValue = bTokenHasValue;
462 pTokenStackPos->nTokenId = nRet;
463 }
464 else if( SVPAR_ACCEPTED != eState && SVPAR_PENDING != eState )
465 eState = SVPAR_ERROR; // irgend ein Fehler
466
467 return nRet;
468 }
469
SkipToken(short nCnt)470 int SvParser::SkipToken( short nCnt ) // n Tokens zurueck "skippen"
471 {
472 pTokenStackPos = GetStackPtr( nCnt );
473 short nTmp = nTokenStackPos - nCnt;
474 if( nTmp < 0 )
475 nTmp = 0;
476 else if( nTmp > nTokenStackSize )
477 nTmp = nTokenStackSize;
478 nTokenStackPos = sal_uInt8(nTmp);
479
480 // und die Werte zurueck
481 aToken = pTokenStackPos->sToken;
482 nTokenValue = pTokenStackPos->nTokenValue;
483 bTokenHasValue = pTokenStackPos->bTokenHasValue;
484
485 return pTokenStackPos->nTokenId;
486 }
487
GetStackPtr(short nCnt)488 SvParser::TokenStackType* SvParser::GetStackPtr( short nCnt )
489 {
490 sal_uInt8 nAktPos = sal_uInt8(pTokenStackPos - pTokenStack );
491 if( nCnt > 0 )
492 {
493 if( nCnt >= nTokenStackSize )
494 nCnt = (nTokenStackSize-1);
495 if( nAktPos + nCnt < nTokenStackSize )
496 nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt);
497 else
498 nAktPos = sal::static_int_cast< sal_uInt8 >(
499 nAktPos + (nCnt - nTokenStackSize));
500 }
501 else if( nCnt < 0 )
502 {
503 if( -nCnt >= nTokenStackSize )
504 nCnt = -nTokenStackSize+1;
505 if( -nCnt <= nAktPos )
506 nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt);
507 else
508 nAktPos = sal::static_int_cast< sal_uInt8 >(
509 nAktPos + (nCnt + nTokenStackSize));
510 }
511 return pTokenStack + nAktPos;
512 }
513
514 // wird fuer jedes Token gerufen, das in CallParser erkannt wird
NextToken(int)515 void SvParser::NextToken( int )
516 {
517 }
518
519
520 // fuers asynchrone lesen aus dem SvStream
521
GetSaveToken() const522 int SvParser::GetSaveToken() const
523 {
524 return pImplData ? pImplData->nSaveToken : 0;
525 }
526
SaveState(int nToken)527 void SvParser::SaveState( int nToken )
528 {
529 // aktuellen Status merken
530 if( !pImplData )
531 {
532 pImplData = new SvParser_Impl;
533 pImplData->nSaveToken = 0;
534 }
535
536 pImplData->nFilePos = rInput.Tell();
537 pImplData->nToken = nToken;
538
539 pImplData->aToken = aToken;
540 pImplData->nlLineNr = nlLineNr;
541 pImplData->nlLinePos = nlLinePos;
542 pImplData->nTokenValue= nTokenValue;
543 pImplData->bTokenHasValue = bTokenHasValue;
544 pImplData->nNextCh = nNextCh;
545 }
546
RestoreState()547 void SvParser::RestoreState()
548 {
549 // alten Status wieder zurueck setzen
550 if( pImplData )
551 {
552 if( ERRCODE_IO_PENDING == rInput.GetError() )
553 rInput.ResetError();
554 aToken = pImplData->aToken;
555 nlLineNr = pImplData->nlLineNr;
556 nlLinePos = pImplData->nlLinePos;
557 nTokenValue= pImplData->nTokenValue;
558 bTokenHasValue=pImplData->bTokenHasValue;
559 nNextCh = pImplData->nNextCh;
560
561 pImplData->nSaveToken = pImplData->nToken;
562
563 rInput.Seek( pImplData->nFilePos );
564 }
565 }
566
Continue(int)567 void SvParser::Continue( int )
568 {
569 }
570
BuildWhichTbl(SvUShorts & rWhichMap,sal_uInt16 * pWhichIds,sal_uInt16 nWhichIds)571 void SvParser::BuildWhichTbl( SvUShorts &rWhichMap,
572 sal_uInt16 *pWhichIds,
573 sal_uInt16 nWhichIds )
574 {
575 sal_uInt16 aNewRange[2];
576
577 for( sal_uInt16 nCnt = 0; nCnt < nWhichIds; ++nCnt, ++pWhichIds )
578 if( *pWhichIds )
579 {
580 aNewRange[0] = aNewRange[1] = *pWhichIds;
581 sal_Bool bIns = sal_True;
582
583 // Position suchen
584 for ( sal_uInt16 nOfs = 0; rWhichMap[nOfs]; nOfs += 2 )
585 {
586 if( *pWhichIds < rWhichMap[nOfs] - 1 )
587 {
588 // neuen Range davor
589 rWhichMap.Insert( aNewRange, 2, nOfs );
590 bIns = sal_False;
591 break;
592 }
593 else if( *pWhichIds == rWhichMap[nOfs] - 1 )
594 {
595 // diesen Range nach unten erweitern
596 rWhichMap[nOfs] = *pWhichIds;
597 bIns = sal_False;
598 break;
599 }
600 else if( *pWhichIds == rWhichMap[nOfs+1] + 1 )
601 {
602 if( rWhichMap[nOfs+2] != 0 && rWhichMap[nOfs+2] == *pWhichIds + 1 )
603 {
604 // mit dem naechsten Bereich mergen
605 rWhichMap[nOfs+1] = rWhichMap[nOfs+3];
606 rWhichMap.Remove( nOfs+2, 2 );
607 }
608 else
609 // diesen Range nach oben erweitern
610 rWhichMap[nOfs+1] = *pWhichIds;
611 bIns = sal_False;
612 break;
613 }
614 }
615
616 // einen Range hinten anhaengen
617 if( bIns )
618 rWhichMap.Insert( aNewRange, 2, rWhichMap.Count()-1 );
619 }
620 }
621
622
IMPL_STATIC_LINK(SvParser,NewDataRead,void *,EMPTYARG)623 IMPL_STATIC_LINK( SvParser, NewDataRead, void*, EMPTYARG )
624 {
625 switch( pThis->eState )
626 {
627 case SVPAR_PENDING:
628 // Wenn gerade ein File geladen wird duerfen wir nicht weiterlaufen,
629 // sondern muessen den Aufruf ignorieren.
630 if( pThis->IsDownloadingFile() )
631 break;
632
633 pThis->eState = SVPAR_WORKING;
634 pThis->RestoreState();
635
636 pThis->Continue( pThis->pImplData->nToken );
637
638 if( ERRCODE_IO_PENDING == pThis->rInput.GetError() )
639 pThis->rInput.ResetError();
640
641 if( SVPAR_PENDING != pThis->eState )
642 pThis->ReleaseRef(); // ansonsten sind wir fertig!
643 break;
644
645 case SVPAR_WAITFORDATA:
646 pThis->eState = SVPAR_WORKING;
647 break;
648
649 case SVPAR_NOTSTARTED:
650 case SVPAR_WORKING:
651 break;
652
653 default:
654 pThis->ReleaseRef(); // ansonsten sind wir fertig!
655 break;
656 }
657
658 return 0;
659 }
660
661 /*========================================================================
662 *
663 * SvKeyValueIterator.
664 *
665 *======================================================================*/
666 SV_DECL_PTRARR_DEL(SvKeyValueList_Impl, SvKeyValue*, 0, 4)
667 SV_IMPL_PTRARR(SvKeyValueList_Impl, SvKeyValue*);
668
669 /*
670 * SvKeyValueIterator.
671 */
SvKeyValueIterator(void)672 SvKeyValueIterator::SvKeyValueIterator (void)
673 : m_pList (new SvKeyValueList_Impl),
674 m_nPos (0)
675 {
676 }
677
678 /*
679 * ~SvKeyValueIterator.
680 */
~SvKeyValueIterator(void)681 SvKeyValueIterator::~SvKeyValueIterator (void)
682 {
683 delete m_pList;
684 }
685
686 /*
687 * GetFirst.
688 */
GetFirst(SvKeyValue & rKeyVal)689 sal_Bool SvKeyValueIterator::GetFirst (SvKeyValue &rKeyVal)
690 {
691 m_nPos = m_pList->Count();
692 return GetNext (rKeyVal);
693 }
694
695 /*
696 * GetNext.
697 */
GetNext(SvKeyValue & rKeyVal)698 sal_Bool SvKeyValueIterator::GetNext (SvKeyValue &rKeyVal)
699 {
700 if (m_nPos > 0)
701 {
702 rKeyVal = *m_pList->GetObject(--m_nPos);
703 return sal_True;
704 }
705 else
706 {
707 // Nothing to do.
708 return sal_False;
709 }
710 }
711
712 /*
713 * Append.
714 */
Append(const SvKeyValue & rKeyVal)715 void SvKeyValueIterator::Append (const SvKeyValue &rKeyVal)
716 {
717 SvKeyValue *pKeyVal = new SvKeyValue (rKeyVal);
718 m_pList->C40_INSERT(SvKeyValue, pKeyVal, m_pList->Count());
719 }
720
721 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
722