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