xref: /aoo41x/main/svtools/source/svrtf/svparser.cxx (revision cdf0e10c)
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