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