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_sc.hxx" 26 27 // System - Includes ----------------------------------------------------- 28 29 class StarBASIC; 30 31 32 33 #ifndef PCH 34 #include "sc.hrc" 35 #define GLOBALOVERFLOW 36 #endif 37 38 // INCLUDE --------------------------------------------------------------- 39 40 #include <stdio.h> 41 #include <ctype.h> 42 #include <stdlib.h> 43 #include <osl/endian.h> 44 #include <i18npool/mslangid.hxx> 45 #include <tools/list.hxx> 46 #include <tools/string.hxx> 47 #include <rtl/math.hxx> 48 #include <svtools/htmlout.hxx> 49 #include <svl/zforlist.hxx> 50 #define _SVSTDARR_ULONGS 51 #include <svl/svstdarr.hxx> 52 #include <sot/formats.hxx> 53 #include <sfx2/mieclip.hxx> 54 #include <unotools/charclass.hxx> 55 #include <unotools/collatorwrapper.hxx> 56 #include <unotools/calendarwrapper.hxx> 57 #include <com/sun/star/i18n/CalendarFieldIndex.hpp> 58 #include <unotools/transliterationwrapper.hxx> 59 60 #include "global.hxx" 61 #include "scerrors.hxx" 62 #include "docsh.hxx" 63 #include "undoblk.hxx" 64 #include "rangenam.hxx" 65 #include "viewdata.hxx" 66 #include "tabvwsh.hxx" 67 #include "filter.hxx" 68 #include "asciiopt.hxx" 69 #include "cell.hxx" 70 #include "docoptio.hxx" 71 #include "progress.hxx" 72 #include "scitems.hxx" 73 #include "editable.hxx" 74 #include "compiler.hxx" 75 #include "warnbox.hxx" 76 77 #include "impex.hxx" 78 79 // ause 80 #include "editutil.hxx" 81 82 #include "globstr.hrc" 83 #include <vcl/msgbox.hxx> 84 #include <vcl/svapp.hxx> 85 #include <osl/module.hxx> 86 87 //======================================================================== 88 89 namespace 90 { 91 const String SYLK_LF = String::CreateFromAscii("\x1b :"); 92 const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;"); 93 const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\""); 94 } 95 96 enum SylkVersion 97 { 98 SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons. 99 SYLK_OOO32, // Correct strings, plus multiline content. 100 SYLK_OWN, // Place our new versions, if any, before this value. 101 SYLK_OTHER // Assume that aliens wrote correct strings. 102 }; 103 104 105 // Gesamtdokument ohne Undo 106 107 108 ScImportExport::ScImportExport( ScDocument* p ) 109 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), 110 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), 111 bFormulas( sal_False ), bIncludeFiltered( sal_True ), 112 bAll( sal_True ), bSingle( sal_True ), bUndo( sal_False ), 113 bOverflow( sal_False ), mbApi( true ), mExportTextOptions() 114 { 115 pUndoDoc = NULL; 116 pExtOptions = NULL; 117 } 118 119 // Insert am Punkt ohne Bereichschecks 120 121 122 ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt ) 123 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), 124 aRange( rPt ), 125 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), 126 bFormulas( sal_False ), bIncludeFiltered( sal_True ), 127 bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ), 128 bOverflow( sal_False ), mbApi( true ), mExportTextOptions() 129 { 130 pUndoDoc = NULL; 131 pExtOptions = NULL; 132 } 133 134 135 // ctor with a range is only used for export 136 //! ctor with a string (and bSingle=sal_True) is also used for DdeSetData 137 138 ScImportExport::ScImportExport( ScDocument* p, const ScRange& r ) 139 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), 140 aRange( r ), 141 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), 142 bFormulas( sal_False ), bIncludeFiltered( sal_True ), 143 bAll( sal_False ), bSingle( sal_False ), bUndo( sal_Bool( pDocSh != NULL ) ), 144 bOverflow( sal_False ), mbApi( true ), mExportTextOptions() 145 { 146 pUndoDoc = NULL; 147 pExtOptions = NULL; 148 // Zur Zeit nur in einer Tabelle! 149 aRange.aEnd.SetTab( aRange.aStart.Tab() ); 150 } 151 152 // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler) 153 // Falls eine View existiert, wird die TabNo der View entnommen! 154 155 156 ScImportExport::ScImportExport( ScDocument* p, const String& rPos ) 157 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), 158 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), 159 bFormulas( sal_False ), bIncludeFiltered( sal_True ), 160 bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ), 161 bOverflow( sal_False ), mbApi( true ), mExportTextOptions() 162 { 163 pUndoDoc = NULL; 164 pExtOptions = NULL; 165 166 SCTAB nTab = ScDocShell::GetCurTab(); 167 aRange.aStart.SetTab( nTab ); 168 String aPos( rPos ); 169 // Benannter Bereich? 170 ScRangeName* pRange = pDoc->GetRangeName(); 171 if( pRange ) 172 { 173 sal_uInt16 nPos; 174 if( pRange->SearchName( aPos, nPos ) ) 175 { 176 ScRangeData* pData = (*pRange)[ nPos ]; 177 if( pData->HasType( RT_REFAREA ) 178 || pData->HasType( RT_ABSAREA ) 179 || pData->HasType( RT_ABSPOS ) ) 180 pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten 181 } 182 } 183 formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); 184 // Bereich? 185 if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID ) 186 bSingle = sal_False; 187 // Zelle? 188 else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID ) 189 aRange.aEnd = aRange.aStart; 190 else 191 bAll = sal_True; 192 } 193 194 195 ScImportExport::~ScImportExport() 196 { 197 delete pUndoDoc; 198 delete pExtOptions; 199 } 200 201 202 void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt ) 203 { 204 if ( pExtOptions ) 205 *pExtOptions = rOpt; 206 else 207 pExtOptions = new ScAsciiOptions( rOpt ); 208 209 // "normale" Optionen uebernehmen 210 211 cSep = rOpt.GetFieldSeps().GetChar(0); 212 cStr = rOpt.GetTextSep(); 213 } 214 215 216 sal_Bool ScImportExport::IsFormatSupported( sal_uLong nFormat ) 217 { 218 return sal_Bool( nFormat == FORMAT_STRING 219 || nFormat == SOT_FORMATSTR_ID_SYLK 220 || nFormat == SOT_FORMATSTR_ID_LINK 221 || nFormat == SOT_FORMATSTR_ID_HTML 222 || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE 223 || nFormat == SOT_FORMATSTR_ID_DIF ); 224 } 225 226 227 ////////////////////////////////////////////////////////////////////////////// 228 229 // Vorbereitung fuer Undo: Undo-Dokument erzeugen 230 231 232 sal_Bool ScImportExport::StartPaste() 233 { 234 if ( !bAll ) 235 { 236 ScEditableTester aTester( pDoc, aRange ); 237 if ( !aTester.IsEditable() ) 238 { 239 InfoBox aInfoBox(Application::GetDefDialogParent(), 240 ScGlobal::GetRscString( aTester.GetMessageId() ) ); 241 aInfoBox.Execute(); 242 return sal_False; 243 } 244 } 245 if( bUndo && pDocSh && pDoc->IsUndoEnabled()) 246 { 247 pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); 248 pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() ); 249 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, sal_False, pUndoDoc ); 250 } 251 return sal_True; 252 } 253 254 // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint 255 256 257 void ScImportExport::EndPaste() 258 { 259 sal_Bool bHeight = pDocSh && pDocSh->AdjustRowHeight( 260 aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() ); 261 262 if( pUndoDoc && pDoc->IsUndoEnabled() ) 263 { 264 ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); 265 pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() ); 266 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, sal_False, pRedoDoc ); 267 ScMarkData aDestMark; 268 aDestMark.SelectOneTable( aRange.aStart.Tab() ); 269 pDocSh->GetUndoManager()->AddUndoAction( 270 new ScUndoPaste( pDocSh, 271 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), 272 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), aDestMark, 273 pUndoDoc, pRedoDoc, IDF_ALL, NULL,NULL,NULL,NULL ) ); 274 } 275 pUndoDoc = NULL; 276 if( pDocSh ) 277 { 278 if (!bHeight) 279 pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber 280 pDocSh->SetDocumentModified(); 281 } 282 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); 283 if ( pViewSh ) 284 pViewSh->UpdateInputHandler(); 285 286 } 287 288 ///////////////////////////////////////////////////////////////////////////// 289 290 291 #if 0 292 sal_Bool ScImportExport::ImportData( SvData& rData ) 293 { 294 sal_uLong nFmt = rData.GetFormat(); 295 if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE ) 296 { 297 MSE40HTMLClipFormatObj aMSE40ClpObj; 298 if ( aMSE40ClpObj.GetData( rData ) ) 299 { 300 SvStream* pStream = aMSE40ClpObj.GetStream(); 301 return ImportStream( *pStream, nFmt ); 302 } 303 return sal_False; 304 } 305 else 306 { 307 void* pMem; 308 sal_uLong nSize = rData.GetMinMemorySize(); 309 rData.GetData( &pMem, TRANSFER_REFERENCE ); 310 if( nFmt == FORMAT_STRING 311 || nFmt == FORMAT_RTF 312 || nFmt == SOT_FORMATSTR_ID_SYLK 313 || nFmt == SOT_FORMATSTR_ID_HTML 314 || nFmt == SOT_FORMATSTR_ID_DIF ) 315 { 316 //! String? Unicode?? 317 318 // Stringende ermitteln! 319 sal_Char* pBegin = (sal_Char*) pMem; 320 sal_Char* pEnd = (sal_Char*) pMem + nSize; 321 322 nSize = 0; 323 while( pBegin != pEnd && *pBegin != '\0' ) 324 pBegin++, nSize++; 325 // #72909# MT says only STRING has to be zero-terminated 326 DBG_ASSERT( pBegin != pEnd || nFmt != FORMAT_STRING, "non zero-terminated String" ) 327 } 328 SvMemoryStream aStrm( pMem, nSize, STREAM_READ ); 329 return ImportStream( aStrm, nFmt ); 330 } 331 } 332 333 #endif 334 335 sal_Bool ScImportExport::ImportData( const String& /* rMimeType */, 336 const ::com::sun::star::uno::Any & /* rValue */ ) 337 { 338 DBG_ASSERT( sal_False, "Implementation is missing" ); 339 return sal_False; 340 } 341 342 sal_Bool ScImportExport::ExportData( const String& rMimeType, 343 ::com::sun::star::uno::Any & rValue ) 344 { 345 SvMemoryStream aStrm; 346 // mba: no BaseURL for data exchange 347 if( ExportStream( aStrm, String(), 348 SotExchange::GetFormatIdFromMimeType( rMimeType ) )) 349 { 350 aStrm << (sal_uInt8) 0; 351 rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >( 352 (sal_Int8*)aStrm.GetData(), 353 aStrm.Seek( STREAM_SEEK_TO_END ) ); 354 return sal_True; 355 } 356 return sal_False; 357 } 358 359 360 sal_Bool ScImportExport::ImportString( const ::rtl::OUString& rText, sal_uLong nFmt ) 361 { 362 switch ( nFmt ) 363 { 364 // formats supporting unicode 365 case FORMAT_STRING : 366 { 367 ScImportStringStream aStrm( rText); 368 return ImportStream( aStrm, String(), nFmt ); 369 // ImportStream must handle RTL_TEXTENCODING_UNICODE 370 } 371 //break; 372 default: 373 { 374 rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); 375 ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc ); 376 SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ ); 377 aStrm.SetStreamCharSet( eEnc ); 378 SetNoEndianSwap( aStrm ); //! no swapping in memory 379 return ImportStream( aStrm, String(), nFmt ); 380 } 381 } 382 } 383 384 385 sal_Bool ScImportExport::ExportString( ::rtl::OUString& rText, sal_uLong nFmt ) 386 { 387 DBG_ASSERT( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" ); 388 if ( nFmt != FORMAT_STRING ) 389 { 390 rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); 391 ByteString aTmp; 392 sal_Bool bOk = ExportByteString( aTmp, eEnc, nFmt ); 393 rText = UniString( aTmp, eEnc ); 394 return bOk; 395 } 396 // nSizeLimit not needed for OUString 397 398 SvMemoryStream aStrm; 399 aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE ); 400 SetNoEndianSwap( aStrm ); //! no swapping in memory 401 // mba: no BaseURL for data exc 402 if( ExportStream( aStrm, String(), nFmt ) ) 403 { 404 aStrm << (sal_Unicode) 0; 405 aStrm.Seek( STREAM_SEEK_TO_END ); 406 407 rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() ); 408 return sal_True; 409 } 410 rText = rtl::OUString(); 411 return sal_False; 412 413 // ExportStream must handle RTL_TEXTENCODING_UNICODE 414 } 415 416 417 sal_Bool ScImportExport::ExportByteString( ByteString& rText, rtl_TextEncoding eEnc, sal_uLong nFmt ) 418 { 419 DBG_ASSERT( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" ); 420 if ( eEnc == RTL_TEXTENCODING_UNICODE ) 421 eEnc = gsl_getSystemTextEncoding(); 422 423 if (!nSizeLimit) 424 nSizeLimit = STRING_MAXLEN; 425 426 SvMemoryStream aStrm; 427 aStrm.SetStreamCharSet( eEnc ); 428 SetNoEndianSwap( aStrm ); //! no swapping in memory 429 // mba: no BaseURL for data exchange 430 if( ExportStream( aStrm, String(), nFmt ) ) 431 { 432 aStrm << (sal_Char) 0; 433 aStrm.Seek( STREAM_SEEK_TO_END ); 434 // Sicherheits-Check: 435 if( aStrm.Tell() <= (sal_uLong) STRING_MAXLEN ) 436 { 437 rText = (const sal_Char*) aStrm.GetData(); 438 return sal_True; 439 } 440 } 441 rText.Erase(); 442 return sal_False; 443 } 444 445 446 sal_Bool ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt ) 447 { 448 if( nFmt == FORMAT_STRING ) 449 { 450 if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten 451 return sal_True; 452 } 453 if( nFmt == SOT_FORMATSTR_ID_SYLK ) 454 { 455 if( Sylk2Doc( rStrm ) ) 456 return sal_True; 457 } 458 if( nFmt == SOT_FORMATSTR_ID_DIF ) 459 { 460 if( Dif2Doc( rStrm ) ) 461 return sal_True; 462 } 463 if( nFmt == FORMAT_RTF ) 464 { 465 if( RTF2Doc( rStrm, rBaseURL ) ) 466 return sal_True; 467 } 468 if( nFmt == SOT_FORMATSTR_ID_LINK ) 469 return sal_True; // Link-Import? 470 if ( nFmt == SOT_FORMATSTR_ID_HTML ) 471 { 472 if( HTML2Doc( rStrm, rBaseURL ) ) 473 return sal_True; 474 } 475 if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE ) 476 { 477 MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data 478 SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm ); 479 if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) ) 480 return sal_True; 481 } 482 483 return sal_False; 484 } 485 486 487 sal_Bool ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt ) 488 { 489 if( nFmt == FORMAT_STRING ) 490 { 491 if( Doc2Text( rStrm ) ) 492 return sal_True; 493 } 494 if( nFmt == SOT_FORMATSTR_ID_SYLK ) 495 { 496 if( Doc2Sylk( rStrm ) ) 497 return sal_True; 498 } 499 if( nFmt == SOT_FORMATSTR_ID_DIF ) 500 { 501 if( Doc2Dif( rStrm ) ) 502 return sal_True; 503 } 504 if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll ) 505 { 506 String aDocName; 507 if ( pDoc->IsClipboard() ) 508 aDocName = ScGlobal::GetClipDocName(); 509 else 510 { 511 SfxObjectShell* pShell = pDoc->GetDocumentShell(); 512 if (pShell) 513 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME ); 514 } 515 516 DBG_ASSERT( aDocName.Len(), "ClipBoard document has no name! :-/" ); 517 if( aDocName.Len() ) 518 { 519 String aRefName; 520 sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D; 521 if( bSingle ) 522 aRange.aStart.Format( aRefName, nFlags, pDoc, pDoc->GetAddressConvention() ); 523 else 524 { 525 if( aRange.aStart.Tab() != aRange.aEnd.Tab() ) 526 nFlags |= SCA_TAB2_3D; 527 aRange.Format( aRefName, nFlags, pDoc ); 528 } 529 String aAppName = Application::GetAppName(); 530 531 WriteUnicodeOrByteString( rStrm, aAppName, sal_True ); 532 WriteUnicodeOrByteString( rStrm, aDocName, sal_True ); 533 WriteUnicodeOrByteString( rStrm, aRefName, sal_True ); 534 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) 535 rStrm << sal_Unicode(0); 536 else 537 rStrm << sal_Char(0); 538 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 539 } 540 } 541 if( nFmt == SOT_FORMATSTR_ID_HTML ) 542 { 543 if( Doc2HTML( rStrm, rBaseURL ) ) 544 return sal_True; 545 } 546 if( nFmt == FORMAT_RTF ) 547 { 548 if( Doc2RTF( rStrm ) ) 549 return sal_True; 550 } 551 552 return sal_False; 553 } 554 555 556 //static 557 void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, sal_Bool bZero ) 558 { 559 rtl_TextEncoding eEnc = rStrm.GetStreamCharSet(); 560 if ( eEnc == RTL_TEXTENCODING_UNICODE ) 561 { 562 if ( !IsEndianSwap( rStrm ) ) 563 rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) ); 564 else 565 { 566 const sal_Unicode* p = rString.GetBuffer(); 567 const sal_Unicode* const pStop = p + rString.Len(); 568 while ( p < pStop ) 569 { 570 rStrm << *p; 571 } 572 } 573 if ( bZero ) 574 rStrm << sal_Unicode(0); 575 } 576 else 577 { 578 ByteString aByteStr( rString, eEnc ); 579 rStrm << aByteStr.GetBuffer(); 580 if ( bZero ) 581 rStrm << sal_Char(0); 582 } 583 } 584 585 586 // This function could be replaced by endlub() 587 // static 588 void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm ) 589 { 590 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) 591 { // same as endl() but unicode 592 switch ( rStrm.GetLineDelimiter() ) 593 { 594 case LINEEND_CR : 595 rStrm << sal_Unicode(_CR); 596 break; 597 case LINEEND_LF : 598 rStrm << sal_Unicode(_LF); 599 break; 600 default: 601 rStrm << sal_Unicode(_CR) << sal_Unicode(_LF); 602 } 603 } 604 else 605 endl( rStrm ); 606 } 607 608 609 enum DoubledQuoteMode 610 { 611 DQM_KEEP, // both are taken 612 DQM_ESCAPE, // escaped quote, one is taken, one ignored 613 DQM_CONCAT, // first is end, next is start, both ignored => strings combined 614 DQM_SEPARATE // end one string and begin next 615 }; 616 617 static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString, 618 sal_Unicode cStr, DoubledQuoteMode eMode ) 619 { 620 p++; //! jump over opening quote 621 sal_Bool bCont; 622 do 623 { 624 bCont = sal_False; 625 const sal_Unicode* p0 = p; 626 for( ;; ) 627 { 628 if( !*p ) 629 break; 630 if( *p == cStr ) 631 { 632 if ( *++p != cStr ) 633 break; 634 // doubled quote char 635 switch ( eMode ) 636 { 637 case DQM_KEEP : 638 p++; // both for us (not breaking for-loop) 639 break; 640 case DQM_ESCAPE : 641 p++; // one for us (breaking for-loop) 642 bCont = sal_True; // and more 643 break; 644 case DQM_CONCAT : 645 if ( p0+1 < p ) 646 rString.Append( p0, sal::static_int_cast<xub_StrLen>( (p-1) - p0 ) ); // first part 647 p0 = ++p; // text of next part starts here 648 break; 649 case DQM_SEPARATE : 650 // positioned on next opening quote 651 break; 652 } 653 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE ) 654 break; 655 } 656 else 657 p++; 658 } 659 if ( p0 < p ) 660 rString.Append( p0, sal::static_int_cast<xub_StrLen>( ((*p || *(p-1) == cStr) ? p-1 : p) - p0 ) ); 661 } while ( bCont ); 662 return p; 663 } 664 665 void lcl_UnescapeSylk( String & rString, SylkVersion eVersion ) 666 { 667 // Older versions didn't escape the semicolon. 668 // Older versions quoted the string and doubled embedded quotes, but not 669 // the semicolons, which was plain wrong. 670 if (eVersion >= SYLK_OOO32) 671 rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' ); 672 else 673 rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' ); 674 675 rString.SearchAndReplaceAll( SYLK_LF, _LF ); 676 } 677 678 static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p, 679 String& rString, SylkVersion eVersion ) 680 { 681 const sal_Unicode* pStartQuote = p; 682 const sal_Unicode* pEndQuote = 0; 683 while( *(++p) ) 684 { 685 if( *p == '"' ) 686 { 687 pEndQuote = p; 688 if (eVersion >= SYLK_OOO32) 689 { 690 if (*(p+1) == ';') 691 { 692 if (*(p+2) == ';') 693 { 694 p += 2; // escaped ';' 695 pEndQuote = 0; 696 } 697 else 698 break; // end field 699 } 700 } 701 else 702 { 703 if (*(p+1) == '"') 704 { 705 ++p; // escaped '"' 706 pEndQuote = 0; 707 } 708 else if (*(p+1) == ';') 709 break; // end field 710 } 711 } 712 } 713 if (!pEndQuote) 714 pEndQuote = p; // Take all data as string. 715 rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) ); 716 lcl_UnescapeSylk( rString, eVersion); 717 return p; 718 } 719 720 static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p, 721 String& rString, SylkVersion eVersion ) 722 { 723 const sal_Unicode* pStart = p; 724 if (eVersion >= SYLK_OOO32) 725 { 726 while (*p) 727 { 728 if (*p == ';') 729 { 730 if (*(p+1) == ';') 731 ++p; // escaped ';' 732 else 733 break; // end field 734 } 735 ++p; 736 } 737 rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); 738 lcl_UnescapeSylk( rString, eVersion); 739 } 740 else 741 { 742 // Nasty. If in old versions the formula contained a semicolon, it was 743 // quoted and embedded quotes were doubled, but semicolons were not. If 744 // there was no semicolon, it could still contain quotes and doubled 745 // embedded quotes if it was something like ="a""b", which was saved as 746 // E"a""b" as is and has to be preserved, even if older versions 747 // couldn't even load it correctly. However, theoretically another 748 // field might follow and thus the line contain a semicolon again, such 749 // as ...;E"a""b";... 750 bool bQuoted = false; 751 if (*p == '"') 752 { 753 // May be a quoted expression or just a string constant expression 754 // with quotes. 755 while (*(++p)) 756 { 757 if (*p == '"') 758 { 759 if (*(p+1) == '"') 760 ++p; // escaped '"' 761 else 762 break; // closing '"', had no ';' yet 763 } 764 else if (*p == ';') 765 { 766 bQuoted = true; // ';' within quoted expression 767 break; 768 } 769 } 770 p = pStart; 771 } 772 if (bQuoted) 773 p = lcl_ScanSylkString( p, rString, eVersion); 774 else 775 { 776 while (*p && *p != ';') 777 ++p; 778 rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); 779 } 780 } 781 return p; 782 } 783 784 static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr ) 785 { 786 xub_StrLen n = 0; 787 while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND ) 788 { 789 rString.Insert( cStr, n ); 790 n += 2; 791 } 792 } 793 794 static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc ) 795 { 796 if (cEsc) 797 lcl_DoubleEscapeChar( rString, cEsc ); 798 799 if (cQuote) 800 { 801 rString.Insert( cQuote, 0 ); 802 rString.Append( cQuote ); 803 } 804 805 ScImportExport::WriteUnicodeOrByteString( rStrm, rString ); 806 } 807 808 inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString ) 809 { 810 ScImportExport::WriteUnicodeOrByteString( rStrm, rString ); 811 } 812 813 ////////////////////////////////////////////////////////////////////////////// 814 815 816 sal_Bool ScImportExport::Text2Doc( SvStream& rStrm ) 817 { 818 sal_Bool bOk = sal_True; 819 820 SCCOL nStartCol = aRange.aStart.Col(); 821 SCROW nStartRow = aRange.aStart.Row(); 822 SCCOL nEndCol = aRange.aEnd.Col(); 823 SCROW nEndRow = aRange.aEnd.Row(); 824 sal_uLong nOldPos = rStrm.Tell(); 825 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() ); 826 sal_Bool bData = sal_Bool( !bSingle ); 827 if( !bSingle) 828 bOk = StartPaste(); 829 830 while( bOk ) 831 { 832 ByteString aByteLine; 833 String aLine, aCell; 834 SCROW nRow = nStartRow; 835 rStrm.Seek( nOldPos ); 836 for( ;; ) 837 { 838 rStrm.ReadUniOrByteStringLine( aLine ); 839 if( rStrm.IsEof() ) 840 break; 841 SCCOL nCol = nStartCol; 842 const sal_Unicode* p = aLine.GetBuffer(); 843 while( *p ) 844 { 845 aCell.Erase(); 846 847 if( *p == cStr )//cStr = " 848 { 849 p = lcl_ScanString( p, aCell, cStr, DQM_KEEP ); 850 } 851 852 const sal_Unicode* q = p; 853 while( *p && *p != cSep )// cSep = tab 854 p++; 855 856 aCell.Append( q, sal::static_int_cast<xub_StrLen>( p - q ) ); 857 858 if( *p ) 859 p++; 860 if (ValidCol(nCol) && ValidRow(nRow) ) 861 { 862 if( bSingle ) 863 { 864 if (nCol>nEndCol) nEndCol = nCol; 865 if (nRow>nEndRow) nEndRow = nRow; 866 } 867 if( bData && nCol <= nEndCol && nRow <= nEndRow ) 868 pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 869 } 870 else // zuviele Spalten/Zeilen 871 bOverflow = sal_True; // beim Import Warnung ausgeben 872 ++nCol; 873 } 874 ++nRow; 875 } 876 877 if( !bData ) 878 { 879 aRange.aEnd.SetCol( nEndCol ); 880 aRange.aEnd.SetRow( nEndRow ); 881 bOk = StartPaste(); 882 bData = sal_True; 883 } 884 else 885 break; 886 } 887 888 EndPaste(); 889 return bOk; 890 } 891 892 // 893 // erweiterter Ascii-Import 894 // 895 896 897 static bool lcl_PutString( 898 ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat, 899 SvNumberFormatter* pFormatter, bool bDetectNumFormat, 900 ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar, 901 ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar ) 902 { 903 bool bMultiLine = false; 904 if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) ) 905 return bMultiLine; 906 907 if ( nColFormat == SC_COL_TEXT ) 908 { 909 pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) ); 910 return bMultiLine; 911 } 912 913 if ( nColFormat == SC_COL_ENGLISH ) 914 { 915 //! SetString mit Extra-Flag ??? 916 917 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable(); 918 sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US); 919 double fVal; 920 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) ) 921 { 922 // Zahlformat wird nicht auf englisch gesetzt 923 pDoc->SetValue( nCol, nRow, nTab, fVal ); 924 return bMultiLine; 925 } 926 // sonst weiter mit SetString 927 } 928 else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate 929 { 930 const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t 931 xub_StrLen nLen = rStr.Len(); 932 xub_StrLen nStart[nMaxNumberParts]; 933 xub_StrLen nEnd[nMaxNumberParts]; 934 935 sal_uInt16 nDP, nMP, nYP; 936 switch ( nColFormat ) 937 { 938 case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break; 939 case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break; 940 case SC_COL_DMY: 941 default: nDP = 0; nMP = 1; nYP = 2; break; 942 } 943 944 sal_uInt16 nFound = 0; 945 sal_Bool bInNum = sal_False; 946 for ( xub_StrLen nPos=0; nPos<nLen && (bInNum || 947 nFound<nMaxNumberParts); nPos++ ) 948 { 949 if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD && 950 nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T') 951 bInNum = sal_False; // ISO-8601: YYYY-MM-DDThh:mm... 952 else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1)) 953 && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos)) 954 || ScGlobal::pCharClass->isDigit( rStr, nPos)) 955 { 956 if (!bInNum) 957 { 958 bInNum = sal_True; 959 nStart[nFound] = nPos; 960 ++nFound; 961 } 962 nEnd[nFound-1] = nPos; 963 } 964 else 965 bInNum = sal_False; 966 } 967 968 if ( nFound == 1 ) 969 { 970 // try to break one number (without separators) into date fields 971 972 xub_StrLen nDateStart = nStart[0]; 973 xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart; 974 975 if ( nDateLen >= 5 && nDateLen <= 8 && 976 ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) ) 977 { 978 // 6 digits: 2 each for day, month, year 979 // 8 digits: 4 for year, 2 each for day and month 980 // 5 or 7 digits: first field is shortened by 1 981 982 sal_Bool bLongYear = ( nDateLen >= 7 ); 983 sal_Bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 ); 984 985 sal_uInt16 nFieldStart = nDateStart; 986 for (sal_uInt16 nPos=0; nPos<3; nPos++) 987 { 988 sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits 989 if ( bLongYear && nPos == nYP ) 990 nFieldEnd += 2; // 2 extra digits for long year 991 if ( bShortFirst && nPos == 0 ) 992 --nFieldEnd; // first field shortened? 993 994 nStart[nPos] = nFieldStart; 995 nEnd[nPos] = nFieldEnd; 996 nFieldStart = nFieldEnd + 1; 997 } 998 nFound = 3; 999 } 1000 } 1001 1002 if ( nFound >= 3 ) 1003 { 1004 using namespace ::com::sun::star; 1005 sal_Bool bSecondCal = sal_False; 1006 sal_uInt16 nDay = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32(); 1007 sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32(); 1008 String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] ); 1009 sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32(); 1010 if (!nMonth) 1011 { 1012 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) ); 1013 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) ); 1014 uno::Sequence< i18n::CalendarItem > xMonths; 1015 sal_Int32 i, nMonthCount; 1016 // first test all month names from local international 1017 xMonths = rCalendar.getMonths(); 1018 nMonthCount = xMonths.getLength(); 1019 for (i=0; i<nMonthCount && !nMonth; i++) 1020 { 1021 if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) || 1022 rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) ) 1023 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1024 else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect, 1025 xMonths[i].AbbrevName ) && 1026 rTransliteration.isEqual( aMStr, aSepShortened ) ) 1027 { // #102136# correct English abbreviation is SEPT, 1028 // but data mostly contains SEP only 1029 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1030 } 1031 } 1032 // if none found, then test english month names 1033 if ( !nMonth && pSecondCalendar && pSecondTransliteration ) 1034 { 1035 xMonths = pSecondCalendar->getMonths(); 1036 nMonthCount = xMonths.getLength(); 1037 for (i=0; i<nMonthCount && !nMonth; i++) 1038 { 1039 if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) || 1040 pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) ) 1041 { 1042 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1043 bSecondCal = sal_True; 1044 } 1045 else if ( i == 8 && pSecondTransliteration->isEqual( 1046 aMStr, aSepShortened ) ) 1047 { // #102136# correct English abbreviation is SEPT, 1048 // but data mostly contains SEP only 1049 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1050 bSecondCal = sal_True; 1051 } 1052 } 1053 } 1054 } 1055 1056 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable(); 1057 if ( nYear < 100 ) 1058 nYear = pDocFormatter->ExpandTwoDigitYear( nYear ); 1059 1060 CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar); 1061 sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear(); 1062 if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths ) 1063 { 1064 --nMonth; 1065 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay ); 1066 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth ); 1067 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear ); 1068 sal_Int16 nHour, nMinute, nSecond, nMilli; 1069 // #i14974# The imported value should have no fractional value, so set the 1070 // time fields to zero (ICU calendar instance defaults to current date/time) 1071 nHour = nMinute = nSecond = nMilli = 0; 1072 if (nFound > 3) 1073 nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32(); 1074 if (nFound > 4) 1075 nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32(); 1076 if (nFound > 5) 1077 nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32(); 1078 if (nFound > 6) 1079 { 1080 sal_Unicode cDec = '.'; 1081 rtl::OUString aT( &cDec, 1); 1082 aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]); 1083 rtl_math_ConversionStatus eStatus; 1084 double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0); 1085 if (eStatus == rtl_math_ConversionStatus_Ok) 1086 nMilli = (sal_Int16) (1000.0 * fV + 0.5); 1087 } 1088 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour ); 1089 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute ); 1090 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond ); 1091 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli ); 1092 if ( pCalendar->isValid() ) 1093 { 1094 double fDiff = DateTime(*pDocFormatter->GetNullDate()) - 1095 pCalendar->getEpochStart(); 1096 // #i14974# must use getLocalDateTime to get the same 1097 // date values as set above 1098 double fDays = pCalendar->getLocalDateTime(); 1099 fDays -= fDiff; 1100 1101 LanguageType eLatin, eCjk, eCtl; 1102 pDoc->GetLanguage( eLatin, eCjk, eCtl ); 1103 LanguageType eDocLang = eLatin; //! which language for date formats? 1104 1105 short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE); 1106 sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang ); 1107 // maybe there is a special format including seconds or milliseconds 1108 if (nFound > 5) 1109 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang); 1110 1111 pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, sal_False ); 1112 1113 return bMultiLine; // success 1114 } 1115 } 1116 } 1117 } 1118 1119 // Standard or date not determined -> SetString / EditCell 1120 if( rStr.Search( _LF ) == STRING_NOTFOUND ) 1121 pDoc->SetString( nCol, nRow, nTab, rStr, pFormatter, bDetectNumFormat ); 1122 else 1123 { 1124 bMultiLine = true; 1125 pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) ); 1126 } 1127 return bMultiLine; 1128 } 1129 1130 1131 String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted ) 1132 { 1133 xub_StrLen nLen = rLine.Len(); 1134 if (nNext > nLen) 1135 nNext = nLen; 1136 if ( nNext <= nStart ) 1137 return EMPTY_STRING; 1138 1139 const sal_Unicode* pStr = rLine.GetBuffer(); 1140 1141 xub_StrLen nSpace = nNext; 1142 while ( nSpace > nStart && pStr[nSpace-1] == ' ' ) 1143 --nSpace; 1144 1145 rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"')); 1146 if (rbIsQuoted) 1147 return rLine.Copy(nStart+1, nSpace-nStart-2); 1148 else 1149 return rLine.Copy(nStart, nSpace-nStart); 1150 } 1151 1152 sal_Bool ScImportExport::ExtText2Doc( SvStream& rStrm ) 1153 { 1154 if (!pExtOptions) 1155 return Text2Doc( rStrm ); 1156 1157 sal_uLong nOldPos = rStrm.Tell(); 1158 rStrm.Seek( STREAM_SEEK_TO_END ); 1159 ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh, 1160 ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos )); 1161 rStrm.Seek( nOldPos ); 1162 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() ); 1163 1164 sal_Bool bOld = ScColumn::bDoubleAlloc; 1165 ScColumn::bDoubleAlloc = sal_True; 1166 1167 SCCOL nStartCol = aRange.aStart.Col(); 1168 SCCOL nEndCol = aRange.aEnd.Col(); 1169 SCROW nStartRow = aRange.aStart.Row(); 1170 SCTAB nTab = aRange.aStart.Tab(); 1171 1172 sal_Bool bFixed = pExtOptions->IsFixedLen(); 1173 const String& rSeps = pExtOptions->GetFieldSeps(); 1174 const sal_Unicode* pSeps = rSeps.GetBuffer(); 1175 sal_Bool bMerge = pExtOptions->IsMergeSeps(); 1176 sal_uInt16 nInfoCount = pExtOptions->GetInfoCount(); 1177 const xub_StrLen* pColStart = pExtOptions->GetColStart(); 1178 const sal_uInt8* pColFormat = pExtOptions->GetColFormat(); 1179 long nSkipLines = pExtOptions->GetStartRow(); 1180 1181 LanguageType eDocLang = pExtOptions->GetLanguage(); 1182 SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang); 1183 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber(); 1184 1185 // For date recognition 1186 ::utl::TransliterationWrapper aTransliteration( 1187 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); 1188 aTransliteration.loadModuleIfNeeded( eDocLang ); 1189 CalendarWrapper aCalendar( pDoc->GetServiceManager() ); 1190 aCalendar.loadDefaultCalendar( 1191 MsLangId::convertLanguageToLocale( eDocLang ) ); 1192 ::utl::TransliterationWrapper* pEnglishTransliteration = NULL; 1193 CalendarWrapper* pEnglishCalendar = NULL; 1194 if ( eDocLang != LANGUAGE_ENGLISH_US ) 1195 { 1196 pEnglishTransliteration = new ::utl::TransliterationWrapper ( 1197 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); 1198 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US ); 1199 pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() ); 1200 pEnglishCalendar->loadDefaultCalendar( 1201 MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) ); 1202 } 1203 1204 String aLine, aCell; 1205 sal_uInt16 i; 1206 SCROW nRow = nStartRow; 1207 1208 while(--nSkipLines>0) 1209 { 1210 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored 1211 if ( rStrm.IsEof() ) 1212 break; 1213 } 1214 1215 // Determine range for Undo. 1216 // TODO: we don't need this during import of a file to a new sheet or 1217 // document, could set bDetermineRange=false then. 1218 bool bDetermineRange = true; 1219 1220 // Row heights don't need to be adjusted on the fly if EndPaste() is called 1221 // afterwards, which happens only if bDetermineRange. This variable also 1222 // survives the toggle of bDetermineRange down at the end of the do{} loop. 1223 bool bRangeIsDetermined = bDetermineRange; 1224 1225 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText(); 1226 1227 sal_uLong nOriginalStreamPos = rStrm.Tell(); 1228 1229 do 1230 { 1231 for( ;; ) 1232 { 1233 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); 1234 if ( rStrm.IsEof() ) 1235 break; 1236 1237 xub_StrLen nLineLen = aLine.Len(); 1238 SCCOL nCol = nStartCol; 1239 bool bMultiLine = false; 1240 if ( bFixed ) // Feste Satzlaenge 1241 { 1242 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an 1243 // overflow if there is really data following to be put behind 1244 // the last column, which doesn't happen if info is 1245 // SC_COL_SKIP. 1246 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ ) 1247 { 1248 sal_uInt8 nFmt = pColFormat[i]; 1249 if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen 1250 { 1251 if (nCol > MAXCOL) 1252 bOverflow = sal_True; // display warning on import 1253 else if (!bDetermineRange) 1254 { 1255 xub_StrLen nStart = pColStart[i]; 1256 xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen; 1257 bool bIsQuoted = false; 1258 aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted ); 1259 if (bIsQuoted && bQuotedAsText) 1260 nFmt = SC_COL_TEXT; 1261 1262 bMultiLine |= lcl_PutString( 1263 pDoc, nCol, nRow, nTab, aCell, nFmt, 1264 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar, 1265 pEnglishTransliteration, pEnglishCalendar); 1266 } 1267 ++nCol; 1268 } 1269 } 1270 } 1271 else // Nach Trennzeichen suchen 1272 { 1273 SCCOL nSourceCol = 0; 1274 sal_uInt16 nInfoStart = 0; 1275 const sal_Unicode* p = aLine.GetBuffer(); 1276 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an 1277 // overflow if there is really data following to be put behind 1278 // the last column, which doesn't happen if info is 1279 // SC_COL_SKIP. 1280 while (*p && nCol <= MAXCOL+1) 1281 { 1282 bool bIsQuoted = false; 1283 p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted ); 1284 1285 sal_uInt8 nFmt = SC_COL_STANDARD; 1286 for ( i=nInfoStart; i<nInfoCount; i++ ) 1287 { 1288 if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert 1289 { 1290 nFmt = pColFormat[i]; 1291 nInfoStart = i + 1; // ColInfos sind in Reihenfolge 1292 break; // for 1293 } 1294 } 1295 if ( nFmt != SC_COL_SKIP ) 1296 { 1297 if (nCol > MAXCOL) 1298 bOverflow = sal_True; // display warning on import 1299 else if (!bDetermineRange) 1300 { 1301 if (bIsQuoted && bQuotedAsText) 1302 nFmt = SC_COL_TEXT; 1303 1304 bMultiLine |= lcl_PutString( 1305 pDoc, nCol, nRow, nTab, aCell, nFmt, 1306 &aNumFormatter, bDetectNumFormat, aTransliteration, 1307 aCalendar, pEnglishTransliteration, pEnglishCalendar); 1308 } 1309 ++nCol; 1310 } 1311 1312 ++nSourceCol; 1313 } 1314 } 1315 if (nEndCol < nCol) 1316 nEndCol = nCol; //! points to the next free or even MAXCOL+2 1317 1318 if (!bDetermineRange) 1319 { 1320 if (bMultiLine && !bRangeIsDetermined && pDocSh) 1321 pDocSh->AdjustRowHeight( nRow, nRow, nTab); 1322 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos ); 1323 } 1324 ++nRow; 1325 if ( nRow > MAXROW ) 1326 { 1327 bOverflow = sal_True; // display warning on import 1328 break; // for 1329 } 1330 } 1331 // so far nRow/nEndCol pointed to the next free 1332 if (nRow > nStartRow) 1333 --nRow; 1334 if (nEndCol > nStartCol) 1335 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL); 1336 1337 if (bDetermineRange) 1338 { 1339 aRange.aEnd.SetCol( nEndCol ); 1340 aRange.aEnd.SetRow( nRow ); 1341 1342 if ( !mbApi && nStartCol != nEndCol && 1343 !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) ) 1344 { 1345 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() ); 1346 if ( aBox.Execute() != RET_YES ) 1347 { 1348 delete pEnglishTransliteration; 1349 delete pEnglishCalendar; 1350 return sal_False; 1351 } 1352 } 1353 1354 rStrm.Seek( nOriginalStreamPos ); 1355 nRow = nStartRow; 1356 if (!StartPaste()) 1357 { 1358 EndPaste(); 1359 return sal_False; 1360 } 1361 } 1362 1363 bDetermineRange = !bDetermineRange; // toggle 1364 } while (!bDetermineRange); 1365 1366 ScColumn::bDoubleAlloc = bOld; 1367 pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 ); 1368 1369 delete pEnglishTransliteration; 1370 delete pEnglishCalendar; 1371 1372 xProgress.reset(); // make room for AdjustRowHeight progress 1373 if (bRangeIsDetermined) 1374 EndPaste(); 1375 1376 return sal_True; 1377 } 1378 1379 1380 // static 1381 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p, 1382 String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted ) 1383 { 1384 rbIsQuoted = false; 1385 rField.Erase(); 1386 if ( *p == cStr ) // String in Anfuehrungszeichen 1387 { 1388 rbIsQuoted = true; 1389 const sal_Unicode* p1; 1390 p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE ); 1391 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1392 p++; 1393 // Append remaining unquoted and undelimited data (dirty, dirty) to 1394 // this field. 1395 if (p > p1) 1396 rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) ); 1397 if( *p ) 1398 p++; 1399 } 1400 else // bis zum Trennzeichen 1401 { 1402 const sal_Unicode* p0 = p; 1403 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1404 p++; 1405 rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); 1406 if( *p ) 1407 p++; 1408 } 1409 if ( bMergeSeps ) // folgende Trennzeichen ueberspringen 1410 { 1411 while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1412 p++; 1413 } 1414 return p; 1415 } 1416 1417 // 1418 // 1419 // 1420 1421 1422 sal_Bool ScImportExport::Doc2Text( SvStream& rStrm ) 1423 { 1424 SCCOL nCol; 1425 SCROW nRow; 1426 SCCOL nStartCol = aRange.aStart.Col(); 1427 SCROW nStartRow = aRange.aStart.Row(); 1428 SCCOL nEndCol = aRange.aEnd.Col(); 1429 SCROW nEndRow = aRange.aEnd.Row(); 1430 String aCell; 1431 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF); 1432 1433 for (nRow = nStartRow; nRow <= nEndRow; nRow++) 1434 { 1435 if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() )) 1436 { 1437 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 1438 { 1439 CellType eType; 1440 pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType ); 1441 switch (eType) 1442 { 1443 case CELLTYPE_FORMULA: 1444 { 1445 if (bFormulas) 1446 { 1447 pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, sal_True ); 1448 if( aCell.Search( cSep ) != STRING_NOTFOUND ) 1449 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1450 else 1451 lcl_WriteSimpleString( rStrm, aCell ); 1452 } 1453 else 1454 { 1455 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1456 1457 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); 1458 if( bMultiLineText ) 1459 { 1460 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) 1461 aCell.SearchAndReplaceAll( _LF, ' ' ); 1462 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) 1463 aCell.ConvertLineEnd(); 1464 } 1465 1466 if( mExportTextOptions.mcSeparatorConvertTo && cSep ) 1467 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); 1468 1469 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) 1470 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1471 else 1472 lcl_WriteSimpleString( rStrm, aCell ); 1473 } 1474 } 1475 break; 1476 case CELLTYPE_VALUE: 1477 { 1478 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1479 lcl_WriteSimpleString( rStrm, aCell ); 1480 } 1481 break; 1482 case CELLTYPE_NOTE: 1483 case CELLTYPE_NONE: 1484 break; 1485 default: 1486 { 1487 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1488 1489 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); 1490 if( bMultiLineText ) 1491 { 1492 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) 1493 aCell.SearchAndReplaceAll( _LF, ' ' ); 1494 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) 1495 aCell.ConvertLineEnd(); 1496 } 1497 1498 if( mExportTextOptions.mcSeparatorConvertTo && cSep ) 1499 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); 1500 1501 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) 1502 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1503 else 1504 lcl_WriteSimpleString( rStrm, aCell ); 1505 } 1506 } 1507 if( nCol < nEndCol ) 1508 lcl_WriteSimpleString( rStrm, String(cSep) ); 1509 } 1510 // if( nRow < nEndRow ) 1511 WriteUnicodeOrByteEndl( rStrm ); 1512 if( rStrm.GetError() != SVSTREAM_OK ) 1513 break; 1514 if( nSizeLimit && rStrm.Tell() > nSizeLimit ) 1515 break; 1516 } 1517 } 1518 1519 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1520 } 1521 1522 1523 sal_Bool ScImportExport::Sylk2Doc( SvStream& rStrm ) 1524 { 1525 sal_Bool bOk = sal_True; 1526 sal_Bool bMyDoc = sal_False; 1527 SylkVersion eVersion = SYLK_OTHER; 1528 1529 // US-English separators for StringToDouble 1530 sal_Unicode cDecSep = '.'; 1531 sal_Unicode cGrpSep = ','; 1532 1533 SCCOL nStartCol = aRange.aStart.Col(); 1534 SCROW nStartRow = aRange.aStart.Row(); 1535 SCCOL nEndCol = aRange.aEnd.Col(); 1536 SCROW nEndRow = aRange.aEnd.Row(); 1537 sal_uLong nOldPos = rStrm.Tell(); 1538 sal_Bool bData = sal_Bool( !bSingle ); 1539 SvULongs aFormats; 1540 1541 if( !bSingle) 1542 bOk = StartPaste(); 1543 1544 while( bOk ) 1545 { 1546 String aLine; 1547 String aText; 1548 ByteString aByteLine; 1549 SCCOL nCol = nStartCol; 1550 SCROW nRow = nStartRow; 1551 SCCOL nRefCol = 1; 1552 SCROW nRefRow = 1; 1553 rStrm.Seek( nOldPos ); 1554 for( ;; ) 1555 { 1556 //! allow unicode 1557 rStrm.ReadLine( aByteLine ); 1558 aLine = String( aByteLine, rStrm.GetStreamCharSet() ); 1559 if( rStrm.IsEof() ) 1560 break; 1561 const sal_Unicode* p = aLine.GetBuffer(); 1562 sal_Unicode cTag = *p++; 1563 if( cTag == 'C' ) // Content 1564 { 1565 if( *p++ != ';' ) 1566 return sal_False; 1567 while( *p ) 1568 { 1569 sal_Unicode ch = *p++; 1570 ch = ScGlobal::ToUpperAlpha( ch ); 1571 switch( ch ) 1572 { 1573 case 'X': 1574 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1575 break; 1576 case 'Y': 1577 nRow = String( p ).ToInt32() + nStartRow - 1; 1578 break; 1579 case 'C': 1580 nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1581 break; 1582 case 'R': 1583 nRefRow = String( p ).ToInt32() + nStartRow - 1; 1584 break; 1585 case 'K': 1586 { 1587 if( !bSingle && 1588 ( nCol < nStartCol || nCol > nEndCol 1589 || nRow < nStartRow || nRow > nEndRow 1590 || nCol > MAXCOL || nRow > MAXROW ) ) 1591 break; 1592 if( !bData ) 1593 { 1594 if( nRow > nEndRow ) 1595 nEndRow = nRow; 1596 if( nCol > nEndCol ) 1597 nEndCol = nCol; 1598 break; 1599 } 1600 sal_Bool bText; 1601 if( *p == '"' ) 1602 { 1603 bText = sal_True; 1604 aText.Erase(); 1605 p = lcl_ScanSylkString( p, aText, eVersion); 1606 } 1607 else 1608 bText = sal_False; 1609 const sal_Unicode* q = p; 1610 while( *q && *q != ';' ) 1611 q++; 1612 if ( !(*q == ';' && *(q+1) == 'I') ) 1613 { // don't ignore value 1614 if( bText ) 1615 { 1616 pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(), 1617 ScBaseCell::CreateTextCell( aText, pDoc), 1618 (sal_Bool) sal_True); 1619 } 1620 else 1621 { 1622 double fVal = rtl_math_uStringToDouble( p, 1623 aLine.GetBuffer() + aLine.Len(), 1624 cDecSep, cGrpSep, NULL, NULL ); 1625 pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal ); 1626 } 1627 } 1628 } 1629 break; 1630 case 'E': 1631 case 'M': 1632 { 1633 if ( ch == 'M' ) 1634 { 1635 if ( nRefCol < nCol ) 1636 nRefCol = nCol; 1637 if ( nRefRow < nRow ) 1638 nRefRow = nRow; 1639 if ( !bData ) 1640 { 1641 if( nRefRow > nEndRow ) 1642 nEndRow = nRefRow; 1643 if( nRefCol > nEndCol ) 1644 nEndCol = nRefCol; 1645 } 1646 } 1647 if( !bMyDoc || !bData ) 1648 break; 1649 aText = '='; 1650 p = lcl_ScanSylkFormula( p, aText, eVersion); 1651 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() ); 1652 /* FIXME: do we want GRAM_ODFF_A1 instead? At the 1653 * end it probably should be GRAM_ODFF_R1C1, since 1654 * R1C1 is what Excel writes in SYLK. */ 1655 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1; 1656 ScCompiler aComp( pDoc, aPos); 1657 aComp.SetGrammar(eGrammar); 1658 ScTokenArray* pCode = aComp.CompileString( aText ); 1659 if ( ch == 'M' ) 1660 { 1661 ScMarkData aMark; 1662 aMark.SelectTable( aPos.Tab(), sal_True ); 1663 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol, 1664 nRefRow, aMark, EMPTY_STRING, pCode ); 1665 } 1666 else 1667 { 1668 ScFormulaCell* pFCell = new ScFormulaCell( 1669 pDoc, aPos, pCode, eGrammar, MM_NONE); 1670 pDoc->PutCell( aPos, pFCell ); 1671 } 1672 delete pCode; // ctor/InsertMatrixFormula did copy TokenArray 1673 } 1674 break; 1675 } 1676 while( *p && *p != ';' ) 1677 p++; 1678 if( *p ) 1679 p++; 1680 } 1681 } 1682 else if( cTag == 'F' ) // Format 1683 { 1684 if( *p++ != ';' ) 1685 return sal_False; 1686 sal_Int32 nFormat = -1; 1687 while( *p ) 1688 { 1689 sal_Unicode ch = *p++; 1690 ch = ScGlobal::ToUpperAlpha( ch ); 1691 switch( ch ) 1692 { 1693 case 'X': 1694 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1695 break; 1696 case 'Y': 1697 nRow = String( p ).ToInt32() + nStartRow - 1; 1698 break; 1699 case 'P' : 1700 if ( bData ) 1701 { 1702 // F;P<n> sets format code of P;P<code> at 1703 // current position, or at ;X;Y if specified. 1704 // Note that ;X;Y may appear after ;P 1705 const sal_Unicode* p0 = p; 1706 while( *p && *p != ';' ) 1707 p++; 1708 String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); 1709 nFormat = aNumber.ToInt32(); 1710 } 1711 break; 1712 } 1713 while( *p && *p != ';' ) 1714 p++; 1715 if( *p ) 1716 p++; 1717 } 1718 if ( !bData ) 1719 { 1720 if( nRow > nEndRow ) 1721 nEndRow = nRow; 1722 if( nCol > nEndCol ) 1723 nEndCol = nCol; 1724 } 1725 if ( 0 <= nFormat && nFormat < aFormats.Count() ) 1726 { 1727 sal_uLong nKey = aFormats[(sal_uInt16)nFormat]; 1728 pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(), 1729 SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) ); 1730 } 1731 } 1732 else if( cTag == 'P' ) 1733 { 1734 if ( bData && *p == ';' && *(p+1) == 'P' ) 1735 { 1736 String aCode( p+2 ); 1737 // unescape doubled semicolons 1738 xub_StrLen nPos = 0; 1739 String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;")); 1740 while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND ) 1741 aCode.Erase( nPos++, 1 ); 1742 // get rid of Xcl escape characters 1743 nPos = 0; 1744 while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND ) 1745 aCode.Erase( nPos, 1 ); 1746 xub_StrLen nCheckPos; 1747 short nType; 1748 sal_uInt32 nKey; 1749 pDoc->GetFormatTable()->PutandConvertEntry( 1750 aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US, 1751 ScGlobal::eLnge ); 1752 if ( nCheckPos ) 1753 nKey = 0; 1754 aFormats.Insert( nKey, aFormats.Count() ); 1755 } 1756 } 1757 else if( cTag == 'I' && *p == 'D' ) 1758 { 1759 aLine.Erase( 0, 4 ); 1760 if (aLine.EqualsAscii( "CALCOOO32" )) 1761 eVersion = SYLK_OOO32; 1762 else if (aLine.EqualsAscii( "SCALC3" )) 1763 eVersion = SYLK_SCALC3; 1764 bMyDoc = (eVersion <= SYLK_OWN); 1765 } 1766 else if( cTag == 'E' ) // Ende 1767 break; 1768 } 1769 if( !bData ) 1770 { 1771 aRange.aEnd.SetCol( nEndCol ); 1772 aRange.aEnd.SetRow( nEndRow ); 1773 bOk = StartPaste(); 1774 bData = sal_True; 1775 } 1776 else 1777 break; 1778 } 1779 1780 EndPaste(); 1781 return bOk; 1782 } 1783 1784 1785 sal_Bool ScImportExport::Doc2Sylk( SvStream& rStrm ) 1786 { 1787 SCCOL nCol; 1788 SCROW nRow; 1789 SCCOL nStartCol = aRange.aStart.Col(); 1790 SCROW nStartRow = aRange.aStart.Row(); 1791 SCCOL nEndCol = aRange.aEnd.Col(); 1792 SCROW nEndRow = aRange.aEnd.Row(); 1793 String aCellStr; 1794 String aValStr; 1795 lcl_WriteSimpleString( rStrm, 1796 String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32"))); 1797 WriteUnicodeOrByteEndl( rStrm ); 1798 1799 for (nRow = nStartRow; nRow <= nEndRow; nRow++) 1800 { 1801 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 1802 { 1803 String aBufStr; 1804 double nVal; 1805 sal_Bool bForm = sal_False; 1806 SCROW r = nRow - nStartRow + 1; 1807 SCCOL c = nCol - nStartCol + 1; 1808 ScBaseCell* pCell; 1809 pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell ); 1810 CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE); 1811 switch( eType ) 1812 { 1813 case CELLTYPE_FORMULA: 1814 bForm = bFormulas; 1815 if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) ) 1816 goto hasvalue; 1817 else 1818 goto hasstring; 1819 1820 case CELLTYPE_VALUE: 1821 hasvalue: 1822 pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal ); 1823 1824 aValStr = ::rtl::math::doubleToUString( nVal, 1825 rtl_math_StringFormat_Automatic, 1826 rtl_math_DecimalPlaces_Max, '.', sal_True ); 1827 1828 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); 1829 aBufStr += String::CreateFromInt32( c ); 1830 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); 1831 aBufStr += String::CreateFromInt32( r ); 1832 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); 1833 aBufStr += aValStr; 1834 lcl_WriteSimpleString( rStrm, aBufStr ); 1835 goto checkformula; 1836 1837 case CELLTYPE_STRING: 1838 case CELLTYPE_EDIT: 1839 hasstring: 1840 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr ); 1841 aCellStr.SearchAndReplaceAll( _LF, SYLK_LF ); 1842 1843 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); 1844 aBufStr += String::CreateFromInt32( c ); 1845 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); 1846 aBufStr += String::CreateFromInt32( r ); 1847 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); 1848 lcl_WriteSimpleString( rStrm, aBufStr ); 1849 lcl_WriteString( rStrm, aCellStr, '"', ';' ); 1850 1851 checkformula: 1852 if( bForm ) 1853 { 1854 const ScFormulaCell* pFCell = 1855 static_cast<const ScFormulaCell*>(pCell); 1856 switch ( pFCell->GetMatrixFlag() ) 1857 { 1858 case MM_REFERENCE : 1859 aCellStr.Erase(); 1860 break; 1861 default: 1862 pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1); 1863 /* FIXME: do we want GRAM_ODFF_A1 instead? At 1864 * the end it probably should be 1865 * GRAM_ODFF_R1C1, since R1C1 is what Excel 1866 * writes in SYLK. */ 1867 } 1868 if ( pFCell->GetMatrixFlag() != MM_NONE && 1869 aCellStr.Len() > 2 && 1870 aCellStr.GetChar(0) == '{' && 1871 aCellStr.GetChar(aCellStr.Len()-1) == '}' ) 1872 { // cut off matrix {} characters 1873 aCellStr.Erase(aCellStr.Len()-1,1); 1874 aCellStr.Erase(0,1); 1875 } 1876 if ( aCellStr.GetChar(0) == '=' ) 1877 aCellStr.Erase(0,1); 1878 String aPrefix; 1879 switch ( pFCell->GetMatrixFlag() ) 1880 { 1881 case MM_FORMULA : 1882 { // diff expression with 'M' M$-extension 1883 SCCOL nC; 1884 SCROW nR; 1885 pFCell->GetMatColsRows( nC, nR ); 1886 nC += c - 1; 1887 nR += r - 1; 1888 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) ); 1889 aPrefix += String::CreateFromInt32( nR ); 1890 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); 1891 aPrefix += String::CreateFromInt32( nC ); 1892 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) ); 1893 } 1894 break; 1895 case MM_REFERENCE : 1896 { // diff expression with 'I' M$-extension 1897 ScAddress aPos; 1898 pFCell->GetMatrixOrigin( aPos ); 1899 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) ); 1900 aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 ); 1901 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); 1902 aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 ); 1903 } 1904 break; 1905 default: 1906 // formula Expression 1907 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) ); 1908 } 1909 lcl_WriteSimpleString( rStrm, aPrefix ); 1910 if ( aCellStr.Len() ) 1911 lcl_WriteString( rStrm, aCellStr, 0, ';' ); 1912 } 1913 WriteUnicodeOrByteEndl( rStrm ); 1914 break; 1915 1916 default: 1917 { 1918 // added to avoid warnings 1919 } 1920 } 1921 } 1922 } 1923 lcl_WriteSimpleString( rStrm, String( 'E' ) ); 1924 WriteUnicodeOrByteEndl( rStrm ); 1925 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1926 } 1927 1928 1929 sal_Bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL ) 1930 { 1931 // CharSet is ignored in ScExportHTML, read from Load/Save HTML options 1932 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll, 1933 aStreamPath, aNonConvertibleChars ); 1934 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1935 } 1936 1937 sal_Bool ScImportExport::Doc2RTF( SvStream& rStrm ) 1938 { 1939 // CharSet is ignored in ScExportRTF 1940 ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW ); 1941 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1942 } 1943 1944 1945 sal_Bool ScImportExport::Doc2Dif( SvStream& rStrm ) 1946 { 1947 // for DIF in the clipboard, IBM_850 is always used 1948 ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 ); 1949 return sal_True; 1950 } 1951 1952 1953 sal_Bool ScImportExport::Dif2Doc( SvStream& rStrm ) 1954 { 1955 SCTAB nTab = aRange.aStart.Tab(); 1956 ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO ); 1957 pImportDoc->InitUndo( pDoc, nTab, nTab ); 1958 1959 // for DIF in the clipboard, IBM_850 is always used 1960 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 ); 1961 1962 SCCOL nEndCol; 1963 SCROW nEndRow; 1964 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow ); 1965 // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start 1966 if ( nEndCol < aRange.aStart.Col() ) 1967 nEndCol = aRange.aStart.Col(); 1968 if ( nEndRow < aRange.aStart.Row() ) 1969 nEndRow = aRange.aStart.Row(); 1970 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab ); 1971 1972 sal_Bool bOk = StartPaste(); 1973 if (bOk) 1974 { 1975 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 1976 pDoc->DeleteAreaTab( aRange, nFlags ); 1977 pImportDoc->CopyToDocument( aRange, nFlags, sal_False, pDoc ); 1978 EndPaste(); 1979 } 1980 1981 delete pImportDoc; 1982 1983 return bOk; 1984 } 1985 1986 1987 sal_Bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL ) 1988 { 1989 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange ); 1990 if (!pImp) 1991 return false; 1992 pImp->Read( rStrm, rBaseURL ); 1993 aRange = pImp->GetRange(); 1994 1995 sal_Bool bOk = StartPaste(); 1996 if (bOk) 1997 { 1998 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 1999 pDoc->DeleteAreaTab( aRange, nFlags ); 2000 pImp->WriteToDocument(); 2001 EndPaste(); 2002 } 2003 delete pImp; 2004 return bOk; 2005 } 2006 2007 2008 sal_Bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL ) 2009 { 2010 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, sal_True); 2011 if (!pImp) 2012 return false; 2013 pImp->Read( rStrm, rBaseURL ); 2014 aRange = pImp->GetRange(); 2015 2016 sal_Bool bOk = StartPaste(); 2017 if (bOk) 2018 { 2019 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in 2020 // a Draw Layer but no Draw View -> create Draw Layer and View here 2021 if (pDocSh) 2022 pDocSh->MakeDrawLayer(); 2023 2024 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 2025 pDoc->DeleteAreaTab( aRange, nFlags ); 2026 pImp->WriteToDocument(); 2027 EndPaste(); 2028 } 2029 delete pImp; 2030 return bOk; 2031 } 2032 2033 #define RETURN_ERROR { return eERR_INTERN; } 2034 class ScFormatFilterMissing : public ScFormatFilterPlugin { 2035 public: 2036 ScFormatFilterMissing() 2037 { 2038 OSL_ASSERT ("Missing file filters"); 2039 } 2040 virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR 2041 virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR 2042 virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR 2043 virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR 2044 virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&, 2045 const CharSet, sal_uInt32 ) RETURN_ERROR 2046 virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR 2047 virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, sal_Bool, SvNumberFormatter*, bool ) RETURN_ERROR 2048 2049 virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; } 2050 virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, sal_Bool ) { return NULL; } 2051 virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); } 2052 2053 #if ENABLE_LOTUS123_EXPORT 2054 virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR 2055 #endif 2056 virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR 2057 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR 2058 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR 2059 virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, sal_Bool, 2060 const String&, String& ) RETURN_ERROR 2061 virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR 2062 }; 2063 2064 extern "C" { static void SAL_CALL thisModule() {} } 2065 typedef ScFormatFilterPlugin * (*FilterFn)(void); 2066 ScFormatFilterPlugin &ScFormatFilter::Get() 2067 { 2068 static ScFormatFilterPlugin *plugin; 2069 2070 if (plugin != NULL) 2071 return *plugin; 2072 2073 static ::osl::Module aModule; 2074 if ( aModule.loadRelative( &thisModule, 2075 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) ) 2076 { 2077 oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) ); 2078 if (fn != NULL) 2079 plugin = reinterpret_cast<FilterFn>(fn)(); 2080 } 2081 if (plugin == NULL) 2082 plugin = new ScFormatFilterMissing(); 2083 2084 return *plugin; 2085 } 2086