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