| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svtools.hxx" |
| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ |
| |
| #include <stdio.h> |
| #include <svtools/svparser.hxx> |
| #include <tools/stream.hxx> |
| #include <tools/debug.hxx> |
| #define _SVSTDARR_USHORTS |
| #include <svl/svstdarr.hxx> |
| #include <rtl/textcvt.h> |
| #include <rtl/tencinfo.h> |
| |
| #define SVPAR_CSM_ |
| |
| #define SVPAR_CSM_ANSI 0x0001U |
| #define SVPAR_CSM_UTF8 0x0002U |
| #define SVPAR_CSM_UCS2B 0x0004U |
| #define SVPAR_CSM_UCS2L 0x0008U |
| #define SVPAR_CSM_SWITCH 0x8000U |
| |
| // Struktur, um sich die akt. Daten zumerken |
| struct SvParser_Impl |
| { |
| String aToken; // gescanntes Token |
| sal_uLong nFilePos; // akt. Position im Stream |
| sal_uLong nlLineNr; // akt. Zeilen Nummer |
| sal_uLong nlLinePos; // akt. Spalten Nummer |
| long nTokenValue; // zusaetzlicher Wert (RTF) |
| sal_Bool bTokenHasValue; // indicates whether nTokenValue is valid |
| int nToken; // akt. Token |
| sal_Unicode nNextCh; // akt. Zeichen |
| |
| int nSaveToken; // das Token vom Continue |
| |
| rtl_TextToUnicodeConverter hConv; |
| rtl_TextToUnicodeContext hContext; |
| |
| #ifdef DBG_UTIL |
| SvFileStream aOut; |
| #endif |
| |
| SvParser_Impl() : |
| nSaveToken(0), hConv( 0 ), hContext( (rtl_TextToUnicodeContext)1 ) |
| { |
| } |
| |
| }; |
| |
| |
| |
| // Konstruktor |
| SvParser::SvParser( SvStream& rIn, sal_uInt8 nStackSize ) |
| : rInput( rIn ) |
| , nlLineNr( 1 ) |
| , nlLinePos( 1 ) |
| , pImplData( 0 ) |
| , nTokenValue( 0 ) |
| , bTokenHasValue( false ) |
| , eState( SVPAR_NOTSTARTED ) |
| , eSrcEnc( RTL_TEXTENCODING_DONTKNOW ) |
| , bDownloadingFile( sal_False ) |
| , nTokenStackSize( nStackSize ) |
| , nTokenStackPos( 0 ) |
| { |
| bUCS2BSrcEnc = bSwitchToUCS2 = sal_False; |
| eState = SVPAR_NOTSTARTED; |
| if( nTokenStackSize < 3 ) |
| nTokenStackSize = 3; |
| pTokenStack = new TokenStackType[ nTokenStackSize ]; |
| pTokenStackPos = pTokenStack; |
| |
| #ifdef DBG_UTIL |
| |
| // wenn die Datei schon existiert, dann Anhaengen: |
| if( !pImplData ) |
| pImplData = new SvParser_Impl; |
| pImplData->aOut.Open( String::CreateFromAscii( "\\parser.dmp" ), |
| STREAM_STD_WRITE | STREAM_NOCREATE ); |
| if( pImplData->aOut.GetError() || !pImplData->aOut.IsOpen() ) |
| pImplData->aOut.Close(); |
| else |
| { |
| pImplData->aOut.Seek( STREAM_SEEK_TO_END ); |
| pImplData->aOut << "\x0c\n\n >>>>>>>>>>>>>>> Dump Start <<<<<<<<<<<<<<<\n"; |
| } |
| #endif |
| } |
| |
| SvParser::~SvParser() |
| { |
| #ifdef DBG_UTIL |
| if( pImplData->aOut.IsOpen() ) |
| pImplData->aOut << "\n\n >>>>>>>>>>>>>>> Dump Ende <<<<<<<<<<<<<<<\n"; |
| pImplData->aOut.Close(); |
| #endif |
| |
| if( pImplData && pImplData->hConv ) |
| { |
| rtl_destroyTextToUnicodeContext( pImplData->hConv, |
| pImplData->hContext ); |
| rtl_destroyTextToUnicodeConverter( pImplData->hConv ); |
| } |
| |
| delete pImplData; |
| |
| delete [] pTokenStack; |
| } |
| |
| void SvParser::ClearTxtConvContext() |
| { |
| if( pImplData && pImplData->hConv ) |
| rtl_resetTextToUnicodeContext( pImplData->hConv, pImplData->hContext ); |
| } |
| |
| void SvParser::SetSrcEncoding( rtl_TextEncoding eEnc ) |
| { |
| |
| if( eEnc != eSrcEnc ) |
| { |
| if( pImplData && pImplData->hConv ) |
| { |
| rtl_destroyTextToUnicodeContext( pImplData->hConv, |
| pImplData->hContext ); |
| rtl_destroyTextToUnicodeConverter( pImplData->hConv ); |
| pImplData->hConv = 0; |
| pImplData->hContext = (rtl_TextToUnicodeContext )1; |
| } |
| |
| if( rtl_isOctetTextEncoding(eEnc) || |
| RTL_TEXTENCODING_UCS2 == eEnc ) |
| { |
| eSrcEnc = eEnc; |
| if( !pImplData ) |
| pImplData = new SvParser_Impl; |
| pImplData->hConv = rtl_createTextToUnicodeConverter( eSrcEnc ); |
| DBG_ASSERT( pImplData->hConv, |
| "SvParser::SetSrcEncoding: no converter for source encoding" ); |
| if( !pImplData->hConv ) |
| eSrcEnc = RTL_TEXTENCODING_DONTKNOW; |
| else |
| pImplData->hContext = |
| rtl_createTextToUnicodeContext( pImplData->hConv ); |
| } |
| else |
| { |
| DBG_ASSERT( !this, |
| "SvParser::SetSrcEncoding: invalid source encoding" ); |
| eSrcEnc = RTL_TEXTENCODING_DONTKNOW; |
| } |
| } |
| } |
| |
| void SvParser::RereadLookahead() |
| { |
| rInput.Seek(nNextChPos); |
| nNextCh = GetNextChar(); |
| } |
| |
| sal_Unicode SvParser::GetNextChar() |
| { |
| sal_Unicode c = 0U; |
| |
| // When reading muliple bytes, we don't have to care about the file |
| // position when we run inti the pending state. The file position is |
| // maintained by SaveState/RestoreState. |
| sal_Bool bErr; |
| if( bSwitchToUCS2 && 0 == rInput.Tell() ) |
| { |
| sal_uChar c1, c2; |
| sal_Bool bSeekBack = sal_True; |
| |
| rInput >> c1; |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( !bErr ) |
| { |
| if( 0xff == c1 || 0xfe == c1 ) |
| { |
| rInput >> c2; |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( !bErr ) |
| { |
| if( 0xfe == c1 && 0xff == c2 ) |
| { |
| eSrcEnc = RTL_TEXTENCODING_UCS2; |
| bUCS2BSrcEnc = sal_True; |
| bSeekBack = sal_False; |
| } |
| else if( 0xff == c1 && 0xfe == c2 ) |
| { |
| eSrcEnc = RTL_TEXTENCODING_UCS2; |
| bUCS2BSrcEnc = sal_False; |
| bSeekBack = sal_False; |
| } |
| } |
| } |
| } |
| if( bSeekBack ) |
| rInput.Seek( 0 ); |
| |
| bSwitchToUCS2 = sal_False; |
| } |
| |
| nNextChPos = rInput.Tell(); |
| |
| if( RTL_TEXTENCODING_UCS2 == eSrcEnc ) |
| { |
| sal_Unicode cUC = USHRT_MAX; |
| sal_uChar c1, c2; |
| |
| rInput >> c1 >> c2; |
| if( 2 == rInput.Tell() && |
| !(rInput.IsEof() || rInput.GetError()) && |
| ( (bUCS2BSrcEnc && 0xfe == c1 && 0xff == c2) || |
| (!bUCS2BSrcEnc && 0xff == c1 && 0xfe == c2) ) ) |
| rInput >> c1 >> c2; |
| |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( !bErr ) |
| { |
| if( bUCS2BSrcEnc ) |
| cUC = (sal_Unicode(c1) << 8) | c2; |
| else |
| cUC = (sal_Unicode(c2) << 8) | c1; |
| } |
| |
| if( !bErr ) |
| { |
| c = cUC; |
| } |
| } |
| else |
| { |
| sal_Size nChars = 0; |
| do |
| { |
| sal_Char c1; // signed, that's the text converter expects |
| rInput >> c1; |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( !bErr ) |
| { |
| if ( |
| RTL_TEXTENCODING_DONTKNOW == eSrcEnc || |
| RTL_TEXTENCODING_SYMBOL == eSrcEnc |
| ) |
| { |
| // no convserion shall take place |
| c = (sal_Unicode)c1; |
| nChars = 1; |
| } |
| else |
| { |
| DBG_ASSERT( pImplData && pImplData->hConv, |
| "no text converter!" ); |
| |
| sal_Unicode cUC; |
| sal_uInt32 nInfo = 0; |
| sal_Size nCvtBytes; |
| nChars = rtl_convertTextToUnicode( |
| pImplData->hConv, pImplData->hContext, |
| &c1, 1, &cUC, 1, |
| RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR, |
| &nInfo, &nCvtBytes); |
| if( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 ) |
| { |
| // The conversion wasn't successfull because we haven't |
| // read enough characters. |
| if( pImplData->hContext != (rtl_TextToUnicodeContext)1 ) |
| { |
| while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 ) |
| { |
| rInput >> c1; |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( bErr ) |
| break; |
| |
| nChars = rtl_convertTextToUnicode( |
| pImplData->hConv, pImplData->hContext, |
| &c1, 1, &cUC, 1, |
| RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR, |
| &nInfo, &nCvtBytes); |
| } |
| if( !bErr ) |
| { |
| if( 1 == nChars && 0 == nInfo ) |
| { |
| c = cUC; |
| } |
| else if( 0 != nChars || 0 != nInfo ) |
| { |
| DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0, |
| "source buffer is to small" ); |
| DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0, |
| "there is a conversion error" ); |
| DBG_ASSERT( 0 == nChars, |
| "there is a converted character, but an error" ); |
| // There are still errors, but nothing we can |
| // do |
| c = (sal_Unicode)'?'; |
| nChars = 1; |
| } |
| } |
| } |
| else |
| { |
| sal_Char sBuffer[10]; |
| sBuffer[0] = c1; |
| sal_uInt16 nLen = 1; |
| while( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) != 0 && |
| nLen < 10 ) |
| { |
| rInput >> c1; |
| bErr = rInput.IsEof() || rInput.GetError(); |
| if( bErr ) |
| break; |
| |
| sBuffer[nLen++] = c1; |
| nChars = rtl_convertTextToUnicode( |
| pImplData->hConv, 0, sBuffer, nLen, &cUC, 1, |
| RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR| |
| RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR, |
| &nInfo, &nCvtBytes); |
| } |
| if( !bErr ) |
| { |
| if( 1 == nChars && 0 == nInfo ) |
| { |
| DBG_ASSERT( nCvtBytes == nLen, |
| "no all bytes have been converted!" ); |
| c = cUC; |
| } |
| else |
| { |
| DBG_ASSERT( (nInfo&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL) == 0, |
| "source buffer is to small" ); |
| DBG_ASSERT( (nInfo&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL)) == 0, |
| "there is a conversion error" ); |
| DBG_ASSERT( 0 == nChars, |
| "there is a converted character, but an error" ); |
| |
| // There are still errors, so we use the first |
| // character and restart after that. |
| c = (sal_Unicode)sBuffer[0]; |
| rInput.SeekRel( -(nLen-1) ); |
| nChars = 1; |
| } |
| } |
| } |
| } |
| else if( 1 == nChars && 0 == nInfo ) |
| { |
| // The conversion was successfull |
| DBG_ASSERT( nCvtBytes == 1, |
| "no all bytes have been converted!" ); |
| c = cUC; |
| } |
| else if( 0 != nChars || 0 != nInfo ) |
| { |
| DBG_ASSERT( 0 == nChars, |
| "there is a converted character, but an error" ); |
| DBG_ASSERT( 0 != nInfo, |
| "there is no converted character and no error" ); |
| // #73398#: If the character could not be converted, |
| // because a conversion is not available, do no conversion at all. |
| c = (sal_Unicode)c1; |
| nChars = 1; |
| |
| } |
| } |
| } |
| } |
| while( 0 == nChars && !bErr ); |
| } |
| if( bErr ) |
| { |
| if( ERRCODE_IO_PENDING == rInput.GetError() ) |
| { |
| eState = SVPAR_PENDING; |
| return c; |
| } |
| else |
| return sal_Unicode(EOF); |
| } |
| |
| #ifdef DBG_UTIL |
| if( pImplData->aOut.IsOpen() ) |
| pImplData->aOut << ByteString::ConvertFromUnicode( c, |
| RTL_TEXTENCODING_MS_1251 ); |
| #endif |
| |
| if( c == '\n' ) |
| { |
| IncLineNr(); |
| SetLinePos( 1L ); |
| } |
| else |
| IncLinePos(); |
| return c; |
| } |
| |
| int SvParser::GetNextToken() |
| { |
| int nRet = 0; |
| |
| if( !nTokenStackPos ) |
| { |
| aToken.Erase(); // Token-Buffer loeschen |
| nTokenValue = -1; // Kennzeichen fuer kein Value gelesen |
| bTokenHasValue = false; |
| |
| nRet = _GetNextToken(); |
| if( SVPAR_PENDING == eState ) |
| return nRet; |
| } |
| |
| ++pTokenStackPos; |
| if( pTokenStackPos == pTokenStack + nTokenStackSize ) |
| pTokenStackPos = pTokenStack; |
| |
| // vom Stack holen ?? |
| if( nTokenStackPos ) |
| { |
| --nTokenStackPos; |
| nTokenValue = pTokenStackPos->nTokenValue; |
| bTokenHasValue = pTokenStackPos->bTokenHasValue; |
| aToken = pTokenStackPos->sToken; |
| nRet = pTokenStackPos->nTokenId; |
| } |
| // nein, dann das aktuelle auf den Stack |
| else if( SVPAR_WORKING == eState ) |
| { |
| pTokenStackPos->sToken = aToken; |
| pTokenStackPos->nTokenValue = nTokenValue; |
| pTokenStackPos->bTokenHasValue = bTokenHasValue; |
| pTokenStackPos->nTokenId = nRet; |
| } |
| else if( SVPAR_ACCEPTED != eState && SVPAR_PENDING != eState ) |
| eState = SVPAR_ERROR; // irgend ein Fehler |
| |
| return nRet; |
| } |
| |
| int SvParser::SkipToken( short nCnt ) // n Tokens zurueck "skippen" |
| { |
| pTokenStackPos = GetStackPtr( nCnt ); |
| short nTmp = nTokenStackPos - nCnt; |
| if( nTmp < 0 ) |
| nTmp = 0; |
| else if( nTmp > nTokenStackSize ) |
| nTmp = nTokenStackSize; |
| nTokenStackPos = sal_uInt8(nTmp); |
| |
| // und die Werte zurueck |
| aToken = pTokenStackPos->sToken; |
| nTokenValue = pTokenStackPos->nTokenValue; |
| bTokenHasValue = pTokenStackPos->bTokenHasValue; |
| |
| return pTokenStackPos->nTokenId; |
| } |
| |
| SvParser::TokenStackType* SvParser::GetStackPtr( short nCnt ) |
| { |
| sal_uInt8 nAktPos = sal_uInt8(pTokenStackPos - pTokenStack ); |
| if( nCnt > 0 ) |
| { |
| if( nCnt >= nTokenStackSize ) |
| nCnt = (nTokenStackSize-1); |
| if( nAktPos + nCnt < nTokenStackSize ) |
| nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt); |
| else |
| nAktPos = sal::static_int_cast< sal_uInt8 >( |
| nAktPos + (nCnt - nTokenStackSize)); |
| } |
| else if( nCnt < 0 ) |
| { |
| if( -nCnt >= nTokenStackSize ) |
| nCnt = -nTokenStackSize+1; |
| if( -nCnt <= nAktPos ) |
| nAktPos = sal::static_int_cast< sal_uInt8 >(nAktPos + nCnt); |
| else |
| nAktPos = sal::static_int_cast< sal_uInt8 >( |
| nAktPos + (nCnt + nTokenStackSize)); |
| } |
| return pTokenStack + nAktPos; |
| } |
| |
| // wird fuer jedes Token gerufen, das in CallParser erkannt wird |
| void SvParser::NextToken( int ) |
| { |
| } |
| |
| |
| // fuers asynchrone lesen aus dem SvStream |
| |
| int SvParser::GetSaveToken() const |
| { |
| return pImplData ? pImplData->nSaveToken : 0; |
| } |
| |
| void SvParser::SaveState( int nToken ) |
| { |
| // aktuellen Status merken |
| if( !pImplData ) |
| { |
| pImplData = new SvParser_Impl; |
| pImplData->nSaveToken = 0; |
| } |
| |
| pImplData->nFilePos = rInput.Tell(); |
| pImplData->nToken = nToken; |
| |
| pImplData->aToken = aToken; |
| pImplData->nlLineNr = nlLineNr; |
| pImplData->nlLinePos = nlLinePos; |
| pImplData->nTokenValue= nTokenValue; |
| pImplData->bTokenHasValue = bTokenHasValue; |
| pImplData->nNextCh = nNextCh; |
| } |
| |
| void SvParser::RestoreState() |
| { |
| // alten Status wieder zurueck setzen |
| if( pImplData ) |
| { |
| if( ERRCODE_IO_PENDING == rInput.GetError() ) |
| rInput.ResetError(); |
| aToken = pImplData->aToken; |
| nlLineNr = pImplData->nlLineNr; |
| nlLinePos = pImplData->nlLinePos; |
| nTokenValue= pImplData->nTokenValue; |
| bTokenHasValue=pImplData->bTokenHasValue; |
| nNextCh = pImplData->nNextCh; |
| |
| pImplData->nSaveToken = pImplData->nToken; |
| |
| rInput.Seek( pImplData->nFilePos ); |
| } |
| } |
| |
| void SvParser::Continue( int ) |
| { |
| } |
| |
| void SvParser::BuildWhichTbl( SvUShorts &rWhichMap, |
| sal_uInt16 *pWhichIds, |
| sal_uInt16 nWhichIds ) |
| { |
| sal_uInt16 aNewRange[2]; |
| |
| for( sal_uInt16 nCnt = 0; nCnt < nWhichIds; ++nCnt, ++pWhichIds ) |
| if( *pWhichIds ) |
| { |
| aNewRange[0] = aNewRange[1] = *pWhichIds; |
| sal_Bool bIns = sal_True; |
| |
| // Position suchen |
| for ( sal_uInt16 nOfs = 0; rWhichMap[nOfs]; nOfs += 2 ) |
| { |
| if( *pWhichIds < rWhichMap[nOfs] - 1 ) |
| { |
| // neuen Range davor |
| rWhichMap.Insert( aNewRange, 2, nOfs ); |
| bIns = sal_False; |
| break; |
| } |
| else if( *pWhichIds == rWhichMap[nOfs] - 1 ) |
| { |
| // diesen Range nach unten erweitern |
| rWhichMap[nOfs] = *pWhichIds; |
| bIns = sal_False; |
| break; |
| } |
| else if( *pWhichIds == rWhichMap[nOfs+1] + 1 ) |
| { |
| if( rWhichMap[nOfs+2] != 0 && rWhichMap[nOfs+2] == *pWhichIds + 1 ) |
| { |
| // mit dem naechsten Bereich mergen |
| rWhichMap[nOfs+1] = rWhichMap[nOfs+3]; |
| rWhichMap.Remove( nOfs+2, 2 ); |
| } |
| else |
| // diesen Range nach oben erweitern |
| rWhichMap[nOfs+1] = *pWhichIds; |
| bIns = sal_False; |
| break; |
| } |
| } |
| |
| // einen Range hinten anhaengen |
| if( bIns ) |
| rWhichMap.Insert( aNewRange, 2, rWhichMap.Count()-1 ); |
| } |
| } |
| |
| |
| IMPL_STATIC_LINK( SvParser, NewDataRead, void*, EMPTYARG ) |
| { |
| switch( pThis->eState ) |
| { |
| case SVPAR_PENDING: |
| // Wenn gerade ein File geladen wird duerfen wir nicht weiterlaufen, |
| // sondern muessen den Aufruf ignorieren. |
| if( pThis->IsDownloadingFile() ) |
| break; |
| |
| pThis->eState = SVPAR_WORKING; |
| pThis->RestoreState(); |
| |
| pThis->Continue( pThis->pImplData->nToken ); |
| |
| if( ERRCODE_IO_PENDING == pThis->rInput.GetError() ) |
| pThis->rInput.ResetError(); |
| |
| if( SVPAR_PENDING != pThis->eState ) |
| pThis->ReleaseRef(); // ansonsten sind wir fertig! |
| break; |
| |
| case SVPAR_WAITFORDATA: |
| pThis->eState = SVPAR_WORKING; |
| break; |
| |
| case SVPAR_NOTSTARTED: |
| case SVPAR_WORKING: |
| break; |
| |
| default: |
| pThis->ReleaseRef(); // ansonsten sind wir fertig! |
| break; |
| } |
| |
| return 0; |
| } |
| |
| /*======================================================================== |
| * |
| * SvKeyValueIterator. |
| * |
| *======================================================================*/ |
| SV_DECL_PTRARR_DEL(SvKeyValueList_Impl, SvKeyValue*, 0, 4) |
| SV_IMPL_PTRARR(SvKeyValueList_Impl, SvKeyValue*); |
| |
| /* |
| * SvKeyValueIterator. |
| */ |
| SvKeyValueIterator::SvKeyValueIterator (void) |
| : m_pList (new SvKeyValueList_Impl), |
| m_nPos (0) |
| { |
| } |
| |
| /* |
| * ~SvKeyValueIterator. |
| */ |
| SvKeyValueIterator::~SvKeyValueIterator (void) |
| { |
| delete m_pList; |
| } |
| |
| /* |
| * GetFirst. |
| */ |
| sal_Bool SvKeyValueIterator::GetFirst (SvKeyValue &rKeyVal) |
| { |
| m_nPos = m_pList->Count(); |
| return GetNext (rKeyVal); |
| } |
| |
| /* |
| * GetNext. |
| */ |
| sal_Bool SvKeyValueIterator::GetNext (SvKeyValue &rKeyVal) |
| { |
| if (m_nPos > 0) |
| { |
| rKeyVal = *m_pList->GetObject(--m_nPos); |
| return sal_True; |
| } |
| else |
| { |
| // Nothing to do. |
| return sal_False; |
| } |
| } |
| |
| /* |
| * Append. |
| */ |
| void SvKeyValueIterator::Append (const SvKeyValue &rKeyVal) |
| { |
| SvKeyValue *pKeyVal = new SvKeyValue (rKeyVal); |
| m_pList->C40_INSERT(SvKeyValue, pKeyVal, m_pList->Count()); |
| } |
| |
| /* vi:set tabstop=4 shiftwidth=4 expandtab: */ |