xref: /aoo42x/main/svtools/source/svrtf/svparser.cxx (revision 5900e8ec)
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 
66 	SvParser_Impl() :
67 		nSaveToken(0), hConv( 0 ), hContext( (rtl_TextToUnicodeContext)1 )
68 	{
69 	}
70 
71 };
72 
73 
74 
75 // Konstruktor
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 
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 
133 void SvParser::ClearTxtConvContext()
134 {
135 	if( pImplData && pImplData->hConv )
136 		rtl_resetTextToUnicodeContext( pImplData->hConv, pImplData->hContext );
137 }
138 
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 
177 void SvParser::RereadLookahead()
178 {
179     rInput.Seek(nNextChPos);
180     nNextCh = GetNextChar();
181 }
182 
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 
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 
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 
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
516 void SvParser::NextToken( int )
517 {
518 }
519 
520 
521 // fuers asynchrone lesen aus dem SvStream
522 
523 int SvParser::GetSaveToken() const
524 {
525 	return pImplData ? pImplData->nSaveToken : 0;
526 }
527 
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 
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 
568 void SvParser::Continue( int )
569 {
570 }
571 
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 
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  */
673 SvKeyValueIterator::SvKeyValueIterator (void)
674     : m_pList (new SvKeyValueList_Impl),
675       m_nPos  (0)
676 {
677 }
678 
679 /*
680  * ~SvKeyValueIterator.
681  */
682 SvKeyValueIterator::~SvKeyValueIterator (void)
683 {
684     delete m_pList;
685 }
686 
687 /*
688  * GetFirst.
689  */
690 sal_Bool SvKeyValueIterator::GetFirst (SvKeyValue &rKeyVal)
691 {
692     m_nPos = m_pList->Count();
693     return GetNext (rKeyVal);
694 }
695 
696 /*
697  * GetNext.
698  */
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  */
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