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_sw.hxx" 26 27 #include <com/sun/star/embed/ElementModes.hpp> 28 #include <com/sun/star/embed/XTransactedObject.hpp> 29 #include <tools/urlobj.hxx> 30 #include <sot/stg.hxx> 31 #include <sfx2/docfile.hxx> 32 #include <unotools/localfilehelper.hxx> 33 #include <unotools/ucbstreamhelper.hxx> 34 35 #include <comphelper/storagehelper.hxx> 36 #include <doc.hxx> 37 #include <IDocumentUndoRedo.hxx> 38 #include <docsh.hxx> 39 #include <pam.hxx> 40 #include <swblocks.hxx> 41 #include <ndtxt.hxx> 42 #include <shellio.hxx> 43 #include <poolfmt.hxx> 44 #include <SwXMLTextBlocks.hxx> 45 #include <errhdl.hxx> 46 #include <SwXMLBlockImport.hxx> 47 #include <SwXMLBlockExport.hxx> 48 #include <swerror.h> 49 50 #define STREAM_STGREAD ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) 51 #define STREAM_STGWRITE ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) 52 53 using namespace ::com::sun::star; 54 55 56 void SwXMLTextBlocks::InitBlockMode ( const uno::Reference < embed::XStorage >& rStorage ) 57 { 58 xBlkRoot = rStorage; 59 xRoot = 0; 60 } 61 62 void SwXMLTextBlocks::ResetBlockMode ( ) 63 { 64 xBlkRoot = 0; 65 xRoot = 0; 66 } 67 68 SwXMLTextBlocks::SwXMLTextBlocks( const String& rFile ) 69 : SwImpBlocks( rFile ), bAutocorrBlock( sal_False ), nFlags ( 0 ) 70 { 71 SwDocShell* pDocSh = new SwDocShell ( SFX_CREATE_MODE_INTERNAL ); 72 if( !pDocSh->DoInitNew( 0 ) ) 73 return; 74 bReadOnly = sal_True; 75 pDoc = pDocSh->GetDoc(); 76 xDocShellRef = pDocSh; 77 pDoc->SetOle2Link( Link() ); 78 pDoc->GetIDocumentUndoRedo().DoUndo(false); 79 pDoc->acquire(); 80 uno::Reference< embed::XStorage > refStg; 81 if( !aDateModified.GetDate() || !aTimeModified.GetTime() ) 82 Touch(); // falls neu angelegt -> neuen ZeitStempel besorgen 83 try 84 { 85 refStg = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READWRITE ); 86 bReadOnly = sal_False; 87 } 88 catch( const uno::Exception& ) 89 { 90 //couldn't open the file - maybe it's readonly 91 } 92 if( !refStg.is()) 93 { 94 try 95 { 96 refStg = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READ ); 97 } 98 catch( const uno::Exception& ) 99 { 100 DBG_ERROR("exception while creating AutoText storage"); 101 } 102 } 103 InitBlockMode ( refStg ); 104 ReadInfo(); 105 ResetBlockMode (); 106 bInfoChanged = sal_False; 107 } 108 109 SwXMLTextBlocks::SwXMLTextBlocks( const uno::Reference < embed::XStorage >& rStg, const String& rName ) 110 : SwImpBlocks( rName ) 111 , bAutocorrBlock( sal_True ) 112 , nFlags ( 0 ) 113 { 114 SwDocShell* pDocSh = new SwDocShell ( SFX_CREATE_MODE_INTERNAL ); 115 if( !pDocSh->DoInitNew( 0 ) ) 116 return; 117 bReadOnly = sal_False; 118 pDoc = pDocSh->GetDoc(); 119 xDocShellRef = pDocSh; 120 pDoc->SetOle2Link( Link() ); 121 pDoc->GetIDocumentUndoRedo().DoUndo(false); 122 pDoc->acquire(); 123 124 InitBlockMode ( rStg ); 125 ReadInfo(); 126 bInfoChanged = sal_False; 127 } 128 129 SwXMLTextBlocks::~SwXMLTextBlocks() 130 { 131 if ( bInfoChanged ) 132 WriteInfo(); 133 ResetBlockMode (); 134 if(xDocShellRef.Is()) 135 xDocShellRef->DoClose(); 136 xDocShellRef = 0; 137 if( pDoc && !pDoc->release() ) 138 delete pDoc; 139 } 140 141 void SwXMLTextBlocks::ClearDoc() 142 { 143 SwDocShell * pDocShell = pDoc->GetDocShell(); 144 pDocShell->InvalidateModel(); 145 pDocShell->ReactivateModel(); 146 147 pDoc->ClearDoc(); 148 pDocShell->ClearEmbeddedObjects(); 149 } 150 void SwXMLTextBlocks::AddName( const String& rShort, const String& rLong, sal_Bool bOnlyTxt ) 151 { 152 sal_uInt16 nIdx = GetIndex( rShort ); 153 SwBlockName* pNew = NULL; 154 if( nIdx != (sal_uInt16) -1 ) 155 aNames.DeleteAndDestroy( nIdx ); 156 157 GeneratePackageName( rShort, aPackageName ); 158 pNew = new SwBlockName( rShort, rLong, aPackageName ); 159 160 pNew->bIsOnlyTxtFlagInit = sal_True; 161 pNew->bIsOnlyTxt = bOnlyTxt; 162 aNames.C40_PTR_INSERT( SwBlockName, pNew ); 163 bInfoChanged = sal_True; 164 } 165 void SwXMLTextBlocks::AddName( const String& rShort, const String& rLong, 166 const String& rPackageName, sal_Bool bOnlyTxt ) 167 { 168 sal_uInt16 nIdx = GetIndex( rShort ); 169 if( nIdx != (sal_uInt16) -1 ) 170 aNames.DeleteAndDestroy( nIdx ); 171 SwBlockName* pNew = new SwBlockName( rShort, rLong, rPackageName ); 172 pNew->bIsOnlyTxtFlagInit = sal_True; 173 pNew->bIsOnlyTxt = bOnlyTxt; 174 aNames.C40_PTR_INSERT( SwBlockName, pNew ); 175 bInfoChanged = sal_True; 176 } 177 178 sal_uLong SwXMLTextBlocks::Delete( sal_uInt16 n ) 179 { 180 String aPckName (aNames[ n ]->aPackageName); 181 uno::Reference < container::XNameAccess > xAccess( xBlkRoot, uno::UNO_QUERY ); 182 if ( xAccess.is() && 183 xAccess->hasByName( aPckName ) && xBlkRoot->isStreamElement( aPckName ) ) 184 { 185 try 186 { 187 xBlkRoot->removeElement ( aPckName ); 188 uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY ); 189 if ( xTrans.is() ) 190 xTrans->commit(); 191 return 0; 192 } 193 catch ( uno::Exception) 194 { 195 return ERR_SWG_WRITE_ERROR; 196 } 197 } 198 return 0; 199 } 200 201 sal_uLong SwXMLTextBlocks::Rename( sal_uInt16 nIdx, const String& rNewShort, const String& ) 202 { 203 DBG_ASSERT( xBlkRoot.is(), "No storage set" ); 204 if(!xBlkRoot.is()) 205 return 0; 206 String aOldName (aNames[ nIdx ]->aPackageName); 207 aShort = rNewShort; 208 GeneratePackageName( aShort, aPackageName ); 209 if (IsOnlyTextBlock ( nIdx ) ) 210 { 211 String sExt( String::CreateFromAscii( ".xml" )); 212 String aOldStreamName( aOldName ); aOldStreamName += sExt; 213 String aNewStreamName( aPackageName ); aNewStreamName += sExt; 214 215 xRoot = xBlkRoot->openStorageElement( aOldName, embed::ElementModes::READWRITE ); 216 xRoot->renameElement ( aOldStreamName, aNewStreamName ); 217 uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY ); 218 if ( xTrans.is() ) 219 xTrans->commit(); 220 xRoot = 0; 221 } 222 223 if(aOldName != aPackageName) 224 { 225 try 226 { 227 xBlkRoot->renameElement ( aOldName, aPackageName ); 228 } 229 catch( const container::ElementExistException& rEx ) 230 { 231 (void)rEx; 232 } 233 } 234 uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY ); 235 if ( xTrans.is() ) 236 xTrans->commit(); 237 // No need to commit xBlkRoot here as SwTextBlocks::Rename calls 238 // WriteInfo which does the commit 239 return 0; 240 } 241 242 sal_uLong SwXMLTextBlocks::CopyBlock( SwImpBlocks& rDestImp, String& rShort, 243 const String& rLong) 244 { 245 sal_uLong nError = 0; 246 OpenFile(sal_True); 247 rDestImp.OpenFile(sal_False); 248 String aGroup( rShort ); 249 sal_Bool bTextOnly = IsOnlyTextBlock ( rShort ) ;//pImp->pBlkRoot->IsStream( aGroup ); 250 sal_uInt16 nIndex = GetIndex ( rShort ); 251 String sDestShortName( GetPackageName (nIndex) ); 252 sal_uInt16 nIdx = 0; 253 254 DBG_ASSERT( xBlkRoot.is(), "No storage set" ); 255 if(!xBlkRoot.is()) 256 return ERR_SWG_WRITE_ERROR; 257 258 uno::Reference < container::XNameAccess > xAccess( ((SwXMLTextBlocks&)rDestImp).xBlkRoot, uno::UNO_QUERY ); 259 while ( xAccess->hasByName( sDestShortName ) ) 260 { 261 ++nIdx; 262 //falls wirklich mal einer so verrueckt ist 263 if(USHRT_MAX == nIdx) 264 { 265 CloseFile(); 266 rDestImp.CloseFile(); 267 return ERR_SWG_WRITE_ERROR; 268 } 269 sDestShortName += String::CreateFromInt32( nIdx ); 270 } 271 272 try 273 { 274 uno::Reference < embed::XStorage > rSourceRoot = xBlkRoot->openStorageElement( aGroup, embed::ElementModes::READ ); 275 uno::Reference < embed::XStorage > rDestRoot = ((SwXMLTextBlocks&)rDestImp).xBlkRoot->openStorageElement( sDestShortName, embed::ElementModes::READWRITE ); 276 //if(!rSourceRoot.Is()) 277 // nError = ERR_SWG_READ_ERROR; 278 //else 279 //{ 280 rSourceRoot->copyToStorage( rDestRoot ); 281 } 282 catch ( uno::Exception& ) 283 { 284 nError = ERR_SWG_WRITE_ERROR; 285 } 286 287 /* I think this should work now that text only blocks are in sub-storages as well 288 else 289 { 290 SvStorageStreamRef rSourceStream = xBlkRoot->OpenStream( aGroup, STREAM_STGREAD ); 291 SvStorageStreamRef rDestStream = ((SwXMLTextBlocks&)rDestImp).xBlkRoot-> OpenStream( sDestShortName, STREAM_STGWRITE ); 292 if(!rDestStream.Is()) 293 nError = ERR_SWG_WRITE_ERROR; 294 else 295 { 296 if(!rSourceStream->CopyTo(&rDestStream)) 297 nError = ERR_SWG_WRITE_ERROR; 298 else 299 rDestStream->Commit(); 300 } 301 } 302 */ 303 if(!nError) 304 { 305 rShort = sDestShortName; 306 //((SwXMLTextBlocks&)rDestImp).xBlkRoot->Commit(); 307 ((SwXMLTextBlocks&)rDestImp).AddName( rShort, rLong, bTextOnly ); 308 ((SwXMLTextBlocks&)rDestImp).MakeBlockList(); 309 } 310 CloseFile(); 311 rDestImp.CloseFile(); 312 return nError; 313 } 314 315 316 sal_uLong SwXMLTextBlocks::StartPutBlock( const String& rShort, const String& rPackageName ) 317 { 318 DBG_ASSERT( xBlkRoot.is(), "No storage set" ); 319 if(!xBlkRoot.is()) 320 return 0; 321 GetIndex ( rShort ); 322 /* 323 if( xBlkRoot->IsContained( rPackageName ) ) 324 { 325 xBlkRoot->Remove( rPackageName ); 326 xBlkRoot->Commit(); 327 } 328 */ 329 try 330 { 331 xRoot = xBlkRoot->openStorageElement( rPackageName, embed::ElementModes::READWRITE ); 332 333 uno::Reference< beans::XPropertySet > xRootProps( xRoot, uno::UNO_QUERY_THROW ); 334 ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM("MediaType") ); 335 ::rtl::OUString aMime( SotExchange::GetFormatMimeType( SOT_FORMATSTR_ID_STARWRITER_8 ) ); 336 xRootProps->setPropertyValue( aPropName, uno::makeAny( aMime ) ); 337 } 338 catch (uno::Exception&) 339 { 340 } 341 return 0; 342 } 343 sal_uLong SwXMLTextBlocks::BeginPutDoc( const String& rShort, const String& rLong ) 344 { 345 // In der Basisklasse ablegen! 346 aShort = rShort; 347 aLong = rLong; 348 GeneratePackageName( rShort, aPackageName ); 349 SetIsTextOnly( rShort, sal_False); 350 return StartPutBlock (rShort, aPackageName); 351 } 352 353 sal_uLong SwXMLTextBlocks::PutBlock( SwPaM& , const String& ) 354 { 355 sal_uLong nRes = 0; 356 sal_uInt16 nCommitFlags = nFlags & (SWXML_CONVBLOCK|SWXML_NOROOTCOMMIT); 357 358 nFlags |= nCommitFlags; 359 360 WriterRef xWrt; 361 ::GetXMLWriter ( aEmptyStr, GetBaseURL(), xWrt); 362 SwWriter aWriter (xRoot, *pDoc ); 363 364 xWrt->bBlock = sal_True; 365 nRes = aWriter.Write ( xWrt ); 366 xWrt->bBlock = sal_False; 367 // Save OLE objects if there are some 368 SwDocShell *pDocSh = pDoc->GetDocShell(); 369 370 sal_Bool bHasChildren = pDocSh && pDocSh->GetEmbeddedObjectContainer().HasEmbeddedObjects(); 371 if( !nRes && bHasChildren ) 372 { 373 // we have to write to the temporary storage first, since the used below functions are optimized 374 // TODO/LATER: it is only a temporary solution, that should be changed soon, the used methods should be 375 // called without optimization 376 377 sal_Bool bOK = sal_False; 378 379 if ( xRoot.is() ) 380 { 381 SfxMedium* pTmpMedium = NULL; 382 try 383 { 384 uno::Reference< embed::XStorage > xTempStorage = 385 ::comphelper::OStorageHelper::GetTemporaryStorage(); 386 387 xRoot->copyToStorage( xTempStorage ); 388 389 // TODO/LATER: no progress bar?! 390 // TODO/MBA: strange construct 391 pTmpMedium = new SfxMedium( xTempStorage, GetBaseURL() ); 392 sal_Bool bTmpOK = pDocSh->SaveAsChildren( *pTmpMedium ); 393 if( bTmpOK ) 394 bTmpOK = pDocSh->SaveCompletedChildren( sal_False ); 395 396 xTempStorage->copyToStorage( xRoot ); 397 bOK = bTmpOK; 398 } 399 catch( uno::Exception& ) 400 { 401 } 402 403 if ( pTmpMedium ) 404 DELETEZ( pTmpMedium ); 405 } 406 407 if( !bOK ) 408 nRes = ERR_SWG_WRITE_ERROR; 409 } 410 411 try 412 { 413 uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY ); 414 if ( xTrans.is() ) 415 xTrans->commit(); 416 xRoot = 0; 417 if ( !nCommitFlags ) 418 { 419 uno::Reference < embed::XTransactedObject > xTmpTrans( xBlkRoot, uno::UNO_QUERY ); 420 if ( xTmpTrans.is() ) 421 xTmpTrans->commit(); 422 } 423 } 424 catch (uno::Exception&) 425 { 426 } 427 428 //TODO/LATER: error handling 429 /* 430 sal_uLong nErr = xBlkRoot->GetError(); 431 if( nErr == SVSTREAM_DISK_FULL ) 432 nRes = ERR_W4W_WRITE_FULL; 433 else if( nErr != SVSTREAM_OK ) 434 nRes = ERR_SWG_WRITE_ERROR; 435 nFlags |= nCommitFlags; 436 return nErr;*/ 437 return 0; 438 } 439 440 sal_uLong SwXMLTextBlocks::PutDoc() 441 { 442 SwPaM* pPaM = MakePaM(); 443 sal_uLong nErr = PutBlock(*pPaM, aLong); 444 delete pPaM; 445 return nErr; 446 } 447 448 sal_uLong SwXMLTextBlocks::GetText( sal_uInt16 nIdx, String& rText ) 449 { 450 return GetBlockText( aNames[ nIdx ]->aShort, rText ); 451 } 452 453 sal_uLong SwXMLTextBlocks::GetText( const String& rShort, String& rText ) 454 { 455 return GetBlockText( rShort, rText ); 456 } 457 458 459 sal_uLong SwXMLTextBlocks::MakeBlockList() 460 { 461 WriteInfo(); 462 return 0; 463 } 464 465 sal_Bool SwXMLTextBlocks::PutMuchEntries( sal_Bool bOn ) 466 { 467 sal_Bool bRet = sal_False; 468 if( bOn ) 469 { 470 if( bInPutMuchBlocks ) 471 { 472 ASSERT( !this, "verschachtelte Aufrufe sind nicht erlaubt" ); 473 } 474 else if( !IsFileChanged() ) 475 { 476 bRet = 0 == OpenFile( sal_False ); 477 if( bRet ) 478 { 479 nFlags |= SWXML_NOROOTCOMMIT; 480 bInPutMuchBlocks = sal_True; 481 } 482 } 483 } 484 else if( bInPutMuchBlocks ) 485 { 486 nFlags &= ~SWXML_NOROOTCOMMIT; 487 if( xBlkRoot.is() ) 488 { 489 try 490 { 491 uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY ); 492 if ( xTrans.is() ) 493 xTrans->commit(); 494 MakeBlockList(); 495 CloseFile(); 496 Touch(); 497 bInPutMuchBlocks = sal_False; 498 bRet = sal_True; 499 } 500 catch (uno::Exception&) 501 { 502 } 503 } 504 } 505 return bRet; 506 } 507 508 sal_uLong SwXMLTextBlocks::OpenFile( sal_Bool bRdOnly ) 509 { 510 if( bAutocorrBlock ) 511 return 0; 512 sal_uLong nRet = 0; 513 try 514 { 515 uno::Reference < embed::XStorage > refStg = comphelper::OStorageHelper::GetStorageFromURL( aFile, 516 bRdOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE ); 517 InitBlockMode ( refStg ); 518 } 519 catch ( uno::Exception& ) 520 { 521 //TODO/LATER: error handling 522 nRet = 1; 523 } 524 525 return nRet; 526 } 527 528 void SwXMLTextBlocks::CloseFile() 529 { 530 if ( !bAutocorrBlock ) 531 { 532 if (bInfoChanged) 533 WriteInfo(); 534 ResetBlockMode(); 535 } 536 } 537 538 void SwXMLTextBlocks::SetIsTextOnly( const String& rShort, sal_Bool bNewValue ) 539 { 540 sal_uInt16 nIdx = GetIndex ( rShort ); 541 if (nIdx != (sal_uInt16) -1 && nIdx != USHRT_MAX) 542 aNames[nIdx]->bIsOnlyTxt = bNewValue; 543 } 544 545 void SwXMLTextBlocks::SetIsTextOnly( sal_uInt16 nIdx, sal_Bool bNewValue ) 546 { 547 aNames[nIdx]->bIsOnlyTxt = bNewValue; 548 } 549 550 sal_Bool SwXMLTextBlocks::IsOnlyTextBlock( const String& rShort ) const 551 { 552 sal_uInt16 nIdx = GetIndex ( rShort ); 553 sal_Bool bRet = sal_False; 554 if (nIdx != (sal_uInt16) -1 && nIdx != USHRT_MAX) 555 { 556 bRet = aNames[nIdx]->bIsOnlyTxt; 557 } 558 return bRet; 559 } 560 sal_Bool SwXMLTextBlocks::IsOnlyTextBlock( sal_uInt16 nIdx ) const 561 { 562 return aNames[nIdx]->bIsOnlyTxt; 563 } 564 565 sal_Bool SwXMLTextBlocks::IsFileUCBStorage( const String & rFileName) 566 { 567 String aName( rFileName ); 568 INetURLObject aObj( aName ); 569 if ( aObj.GetProtocol() == INET_PROT_NOT_VALID ) 570 { 571 String aURL; 572 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL ); 573 aObj.SetURL( aURL ); 574 aName = aObj.GetMainURL( INetURLObject::NO_DECODE ); 575 } 576 577 SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READ ); 578 sal_Bool bRet = UCBStorage::IsStorageFile( pStm ); 579 delete pStm; 580 return bRet; 581 } 582 583 584 585 short SwXMLTextBlocks::GetFileType ( void ) const 586 { 587 return SWBLK_XML; 588 } 589 590 void SwXMLTextBlocks::GeneratePackageName ( const String& rShort, String& rPackageName ) 591 { 592 rPackageName = rShort; 593 xub_StrLen nPos = 0; 594 sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 }; 595 ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7); 596 rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US); 597 while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos ))) 598 { 599 rPackageName.SetChar( nPos, '_' ); 600 ++nPos; 601 } 602 } 603 604 sal_uLong SwXMLTextBlocks::PutText( const String& rShort, const String& rName, 605 const String& rText ) 606 { 607 sal_uLong nRes = 0; 608 aShort = rShort; 609 aLong = rName; 610 aCur = rText; 611 SetIsTextOnly( aShort, sal_True ); 612 GeneratePackageName( rShort, aPackageName ); 613 ClearDoc(); 614 nRes = PutBlockText( rShort, rName, rText, aPackageName ); 615 return nRes; 616 } 617 618 void SwXMLTextBlocks::MakeBlockText( const String& rText ) 619 { 620 SwTxtNode* pTxtNode = pDoc->GetNodes()[ pDoc->GetNodes().GetEndOfContent(). 621 GetIndex() - 1 ]->GetTxtNode(); 622 //JP 18.09.98: Bug 56706 - Standard sollte zumindest gesetzt sein! 623 if( pTxtNode->GetTxtColl() == pDoc->GetDfltTxtFmtColl() ) 624 pTxtNode->ChgFmtColl( pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); 625 626 xub_StrLen nPos = 0; 627 do 628 { 629 if ( nPos ) 630 { 631 pTxtNode = (SwTxtNode*)pTxtNode->AppendNode( SwPosition( *pTxtNode ) ); 632 } 633 SwIndex aIdx( pTxtNode ); 634 String sTemp(rText.GetToken( 0, '\015', nPos ) ); 635 pTxtNode->InsertText( sTemp, aIdx ); 636 } while ( STRING_NOTFOUND != nPos ); 637 } 638