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