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