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( !this, "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 if( *p == cStr ) 847 { 848 p = lcl_ScanString( p, aCell, cStr, DQM_KEEP ); 849 while( *p && *p != cSep ) 850 p++; 851 if( *p ) 852 p++; 853 } 854 else 855 { 856 const sal_Unicode* q = p; 857 while( *p && *p != cSep ) 858 p++; 859 aCell.Assign( q, sal::static_int_cast<xub_StrLen>( p - q ) ); 860 if( *p ) 861 p++; 862 } 863 if (ValidCol(nCol) && ValidRow(nRow) ) 864 { 865 if( bSingle ) 866 { 867 if (nCol>nEndCol) nEndCol = nCol; 868 if (nRow>nEndRow) nEndRow = nRow; 869 } 870 if( bData && nCol <= nEndCol && nRow <= nEndRow ) 871 pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 872 } 873 else // zuviele Spalten/Zeilen 874 bOverflow = sal_True; // beim Import Warnung ausgeben 875 ++nCol; 876 } 877 ++nRow; 878 } 879 880 if( !bData ) 881 { 882 aRange.aEnd.SetCol( nEndCol ); 883 aRange.aEnd.SetRow( nEndRow ); 884 bOk = StartPaste(); 885 bData = sal_True; 886 } 887 else 888 break; 889 } 890 891 EndPaste(); 892 return bOk; 893 } 894 895 // 896 // erweiterter Ascii-Import 897 // 898 899 900 static bool lcl_PutString( 901 ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat, 902 SvNumberFormatter* pFormatter, bool bDetectNumFormat, 903 ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar, 904 ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar ) 905 { 906 bool bMultiLine = false; 907 if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) ) 908 return bMultiLine; 909 910 if ( nColFormat == SC_COL_TEXT ) 911 { 912 pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) ); 913 return bMultiLine; 914 } 915 916 if ( nColFormat == SC_COL_ENGLISH ) 917 { 918 //! SetString mit Extra-Flag ??? 919 920 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable(); 921 sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US); 922 double fVal; 923 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) ) 924 { 925 // Zahlformat wird nicht auf englisch gesetzt 926 pDoc->SetValue( nCol, nRow, nTab, fVal ); 927 return bMultiLine; 928 } 929 // sonst weiter mit SetString 930 } 931 else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate 932 { 933 const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t 934 xub_StrLen nLen = rStr.Len(); 935 xub_StrLen nStart[nMaxNumberParts]; 936 xub_StrLen nEnd[nMaxNumberParts]; 937 938 sal_uInt16 nDP, nMP, nYP; 939 switch ( nColFormat ) 940 { 941 case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break; 942 case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break; 943 case SC_COL_DMY: 944 default: nDP = 0; nMP = 1; nYP = 2; break; 945 } 946 947 sal_uInt16 nFound = 0; 948 sal_Bool bInNum = sal_False; 949 for ( xub_StrLen nPos=0; nPos<nLen && (bInNum || 950 nFound<nMaxNumberParts); nPos++ ) 951 { 952 if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD && 953 nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T') 954 bInNum = sal_False; // ISO-8601: YYYY-MM-DDThh:mm... 955 else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1)) 956 && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos)) 957 || ScGlobal::pCharClass->isDigit( rStr, nPos)) 958 { 959 if (!bInNum) 960 { 961 bInNum = sal_True; 962 nStart[nFound] = nPos; 963 ++nFound; 964 } 965 nEnd[nFound-1] = nPos; 966 } 967 else 968 bInNum = sal_False; 969 } 970 971 if ( nFound == 1 ) 972 { 973 // try to break one number (without separators) into date fields 974 975 xub_StrLen nDateStart = nStart[0]; 976 xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart; 977 978 if ( nDateLen >= 5 && nDateLen <= 8 && 979 ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) ) 980 { 981 // 6 digits: 2 each for day, month, year 982 // 8 digits: 4 for year, 2 each for day and month 983 // 5 or 7 digits: first field is shortened by 1 984 985 sal_Bool bLongYear = ( nDateLen >= 7 ); 986 sal_Bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 ); 987 988 sal_uInt16 nFieldStart = nDateStart; 989 for (sal_uInt16 nPos=0; nPos<3; nPos++) 990 { 991 sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits 992 if ( bLongYear && nPos == nYP ) 993 nFieldEnd += 2; // 2 extra digits for long year 994 if ( bShortFirst && nPos == 0 ) 995 --nFieldEnd; // first field shortened? 996 997 nStart[nPos] = nFieldStart; 998 nEnd[nPos] = nFieldEnd; 999 nFieldStart = nFieldEnd + 1; 1000 } 1001 nFound = 3; 1002 } 1003 } 1004 1005 if ( nFound >= 3 ) 1006 { 1007 using namespace ::com::sun::star; 1008 sal_Bool bSecondCal = sal_False; 1009 sal_uInt16 nDay = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32(); 1010 sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32(); 1011 String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] ); 1012 sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32(); 1013 if (!nMonth) 1014 { 1015 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) ); 1016 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) ); 1017 uno::Sequence< i18n::CalendarItem > xMonths; 1018 sal_Int32 i, nMonthCount; 1019 // first test all month names from local international 1020 xMonths = rCalendar.getMonths(); 1021 nMonthCount = xMonths.getLength(); 1022 for (i=0; i<nMonthCount && !nMonth; i++) 1023 { 1024 if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) || 1025 rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) ) 1026 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1027 else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect, 1028 xMonths[i].AbbrevName ) && 1029 rTransliteration.isEqual( aMStr, aSepShortened ) ) 1030 { // #102136# correct English abbreviation is SEPT, 1031 // but data mostly contains SEP only 1032 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1033 } 1034 } 1035 // if none found, then test english month names 1036 if ( !nMonth && pSecondCalendar && pSecondTransliteration ) 1037 { 1038 xMonths = pSecondCalendar->getMonths(); 1039 nMonthCount = xMonths.getLength(); 1040 for (i=0; i<nMonthCount && !nMonth; i++) 1041 { 1042 if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) || 1043 pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) ) 1044 { 1045 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1046 bSecondCal = sal_True; 1047 } 1048 else if ( i == 8 && pSecondTransliteration->isEqual( 1049 aMStr, aSepShortened ) ) 1050 { // #102136# correct English abbreviation is SEPT, 1051 // but data mostly contains SEP only 1052 nMonth = sal::static_int_cast<sal_Int16>( i+1 ); 1053 bSecondCal = sal_True; 1054 } 1055 } 1056 } 1057 } 1058 1059 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable(); 1060 if ( nYear < 100 ) 1061 nYear = pDocFormatter->ExpandTwoDigitYear( nYear ); 1062 1063 CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar); 1064 sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear(); 1065 if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths ) 1066 { 1067 --nMonth; 1068 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay ); 1069 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth ); 1070 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear ); 1071 sal_Int16 nHour, nMinute, nSecond, nMilli; 1072 // #i14974# The imported value should have no fractional value, so set the 1073 // time fields to zero (ICU calendar instance defaults to current date/time) 1074 nHour = nMinute = nSecond = nMilli = 0; 1075 if (nFound > 3) 1076 nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32(); 1077 if (nFound > 4) 1078 nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32(); 1079 if (nFound > 5) 1080 nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32(); 1081 if (nFound > 6) 1082 { 1083 sal_Unicode cDec = '.'; 1084 rtl::OUString aT( &cDec, 1); 1085 aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]); 1086 rtl_math_ConversionStatus eStatus; 1087 double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0); 1088 if (eStatus == rtl_math_ConversionStatus_Ok) 1089 nMilli = (sal_Int16) (1000.0 * fV + 0.5); 1090 } 1091 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour ); 1092 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute ); 1093 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond ); 1094 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli ); 1095 if ( pCalendar->isValid() ) 1096 { 1097 double fDiff = DateTime(*pDocFormatter->GetNullDate()) - 1098 pCalendar->getEpochStart(); 1099 // #i14974# must use getLocalDateTime to get the same 1100 // date values as set above 1101 double fDays = pCalendar->getLocalDateTime(); 1102 fDays -= fDiff; 1103 1104 LanguageType eLatin, eCjk, eCtl; 1105 pDoc->GetLanguage( eLatin, eCjk, eCtl ); 1106 LanguageType eDocLang = eLatin; //! which language for date formats? 1107 1108 short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE); 1109 sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang ); 1110 // maybe there is a special format including seconds or milliseconds 1111 if (nFound > 5) 1112 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang); 1113 1114 pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, sal_False ); 1115 1116 return bMultiLine; // success 1117 } 1118 } 1119 } 1120 } 1121 1122 // Standard or date not determined -> SetString / EditCell 1123 if( rStr.Search( _LF ) == STRING_NOTFOUND ) 1124 pDoc->SetString( nCol, nRow, nTab, rStr, pFormatter, bDetectNumFormat ); 1125 else 1126 { 1127 bMultiLine = true; 1128 pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) ); 1129 } 1130 return bMultiLine; 1131 } 1132 1133 1134 String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted ) 1135 { 1136 xub_StrLen nLen = rLine.Len(); 1137 if (nNext > nLen) 1138 nNext = nLen; 1139 if ( nNext <= nStart ) 1140 return EMPTY_STRING; 1141 1142 const sal_Unicode* pStr = rLine.GetBuffer(); 1143 1144 xub_StrLen nSpace = nNext; 1145 while ( nSpace > nStart && pStr[nSpace-1] == ' ' ) 1146 --nSpace; 1147 1148 rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"')); 1149 if (rbIsQuoted) 1150 return rLine.Copy(nStart+1, nSpace-nStart-2); 1151 else 1152 return rLine.Copy(nStart, nSpace-nStart); 1153 } 1154 1155 sal_Bool ScImportExport::ExtText2Doc( SvStream& rStrm ) 1156 { 1157 if (!pExtOptions) 1158 return Text2Doc( rStrm ); 1159 1160 sal_uLong nOldPos = rStrm.Tell(); 1161 rStrm.Seek( STREAM_SEEK_TO_END ); 1162 ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh, 1163 ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos )); 1164 rStrm.Seek( nOldPos ); 1165 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() ); 1166 1167 sal_Bool bOld = ScColumn::bDoubleAlloc; 1168 ScColumn::bDoubleAlloc = sal_True; 1169 1170 SCCOL nStartCol = aRange.aStart.Col(); 1171 SCCOL nEndCol = aRange.aEnd.Col(); 1172 SCROW nStartRow = aRange.aStart.Row(); 1173 SCTAB nTab = aRange.aStart.Tab(); 1174 1175 sal_Bool bFixed = pExtOptions->IsFixedLen(); 1176 const String& rSeps = pExtOptions->GetFieldSeps(); 1177 const sal_Unicode* pSeps = rSeps.GetBuffer(); 1178 sal_Bool bMerge = pExtOptions->IsMergeSeps(); 1179 sal_uInt16 nInfoCount = pExtOptions->GetInfoCount(); 1180 const xub_StrLen* pColStart = pExtOptions->GetColStart(); 1181 const sal_uInt8* pColFormat = pExtOptions->GetColFormat(); 1182 long nSkipLines = pExtOptions->GetStartRow(); 1183 1184 LanguageType eDocLang = pExtOptions->GetLanguage(); 1185 SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang); 1186 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber(); 1187 1188 // For date recognition 1189 ::utl::TransliterationWrapper aTransliteration( 1190 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); 1191 aTransliteration.loadModuleIfNeeded( eDocLang ); 1192 CalendarWrapper aCalendar( pDoc->GetServiceManager() ); 1193 aCalendar.loadDefaultCalendar( 1194 MsLangId::convertLanguageToLocale( eDocLang ) ); 1195 ::utl::TransliterationWrapper* pEnglishTransliteration = NULL; 1196 CalendarWrapper* pEnglishCalendar = NULL; 1197 if ( eDocLang != LANGUAGE_ENGLISH_US ) 1198 { 1199 pEnglishTransliteration = new ::utl::TransliterationWrapper ( 1200 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); 1201 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US ); 1202 pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() ); 1203 pEnglishCalendar->loadDefaultCalendar( 1204 MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) ); 1205 } 1206 1207 String aLine, aCell; 1208 sal_uInt16 i; 1209 SCROW nRow = nStartRow; 1210 1211 while(--nSkipLines>0) 1212 { 1213 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored 1214 if ( rStrm.IsEof() ) 1215 break; 1216 } 1217 1218 // Determine range for Undo. 1219 // TODO: we don't need this during import of a file to a new sheet or 1220 // document, could set bDetermineRange=false then. 1221 bool bDetermineRange = true; 1222 1223 // Row heights don't need to be adjusted on the fly if EndPaste() is called 1224 // afterwards, which happens only if bDetermineRange. This variable also 1225 // survives the toggle of bDetermineRange down at the end of the do{} loop. 1226 bool bRangeIsDetermined = bDetermineRange; 1227 1228 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText(); 1229 1230 sal_uLong nOriginalStreamPos = rStrm.Tell(); 1231 1232 do 1233 { 1234 for( ;; ) 1235 { 1236 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); 1237 if ( rStrm.IsEof() ) 1238 break; 1239 1240 xub_StrLen nLineLen = aLine.Len(); 1241 SCCOL nCol = nStartCol; 1242 bool bMultiLine = false; 1243 if ( bFixed ) // Feste Satzlaenge 1244 { 1245 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an 1246 // overflow if there is really data following to be put behind 1247 // the last column, which doesn't happen if info is 1248 // SC_COL_SKIP. 1249 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ ) 1250 { 1251 sal_uInt8 nFmt = pColFormat[i]; 1252 if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen 1253 { 1254 if (nCol > MAXCOL) 1255 bOverflow = sal_True; // display warning on import 1256 else if (!bDetermineRange) 1257 { 1258 xub_StrLen nStart = pColStart[i]; 1259 xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen; 1260 bool bIsQuoted = false; 1261 aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted ); 1262 if (bIsQuoted && bQuotedAsText) 1263 nFmt = SC_COL_TEXT; 1264 1265 bMultiLine |= lcl_PutString( 1266 pDoc, nCol, nRow, nTab, aCell, nFmt, 1267 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar, 1268 pEnglishTransliteration, pEnglishCalendar); 1269 } 1270 ++nCol; 1271 } 1272 } 1273 } 1274 else // Nach Trennzeichen suchen 1275 { 1276 SCCOL nSourceCol = 0; 1277 sal_uInt16 nInfoStart = 0; 1278 const sal_Unicode* p = aLine.GetBuffer(); 1279 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an 1280 // overflow if there is really data following to be put behind 1281 // the last column, which doesn't happen if info is 1282 // SC_COL_SKIP. 1283 while (*p && nCol <= MAXCOL+1) 1284 { 1285 bool bIsQuoted = false; 1286 p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted ); 1287 1288 sal_uInt8 nFmt = SC_COL_STANDARD; 1289 for ( i=nInfoStart; i<nInfoCount; i++ ) 1290 { 1291 if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert 1292 { 1293 nFmt = pColFormat[i]; 1294 nInfoStart = i + 1; // ColInfos sind in Reihenfolge 1295 break; // for 1296 } 1297 } 1298 if ( nFmt != SC_COL_SKIP ) 1299 { 1300 if (nCol > MAXCOL) 1301 bOverflow = sal_True; // display warning on import 1302 else if (!bDetermineRange) 1303 { 1304 if (bIsQuoted && bQuotedAsText) 1305 nFmt = SC_COL_TEXT; 1306 1307 bMultiLine |= lcl_PutString( 1308 pDoc, nCol, nRow, nTab, aCell, nFmt, 1309 &aNumFormatter, bDetectNumFormat, aTransliteration, 1310 aCalendar, pEnglishTransliteration, pEnglishCalendar); 1311 } 1312 ++nCol; 1313 } 1314 1315 ++nSourceCol; 1316 } 1317 } 1318 if (nEndCol < nCol) 1319 nEndCol = nCol; //! points to the next free or even MAXCOL+2 1320 1321 if (!bDetermineRange) 1322 { 1323 if (bMultiLine && !bRangeIsDetermined && pDocSh) 1324 pDocSh->AdjustRowHeight( nRow, nRow, nTab); 1325 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos ); 1326 } 1327 ++nRow; 1328 if ( nRow > MAXROW ) 1329 { 1330 bOverflow = sal_True; // display warning on import 1331 break; // for 1332 } 1333 } 1334 // so far nRow/nEndCol pointed to the next free 1335 if (nRow > nStartRow) 1336 --nRow; 1337 if (nEndCol > nStartCol) 1338 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL); 1339 1340 if (bDetermineRange) 1341 { 1342 aRange.aEnd.SetCol( nEndCol ); 1343 aRange.aEnd.SetRow( nRow ); 1344 1345 if ( !mbApi && nStartCol != nEndCol && 1346 !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) ) 1347 { 1348 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() ); 1349 if ( aBox.Execute() != RET_YES ) 1350 { 1351 delete pEnglishTransliteration; 1352 delete pEnglishCalendar; 1353 return sal_False; 1354 } 1355 } 1356 1357 rStrm.Seek( nOriginalStreamPos ); 1358 nRow = nStartRow; 1359 if (!StartPaste()) 1360 { 1361 EndPaste(); 1362 return sal_False; 1363 } 1364 } 1365 1366 bDetermineRange = !bDetermineRange; // toggle 1367 } while (!bDetermineRange); 1368 1369 ScColumn::bDoubleAlloc = bOld; 1370 pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 ); 1371 1372 delete pEnglishTransliteration; 1373 delete pEnglishCalendar; 1374 1375 xProgress.reset(); // make room for AdjustRowHeight progress 1376 if (bRangeIsDetermined) 1377 EndPaste(); 1378 1379 return sal_True; 1380 } 1381 1382 1383 // static 1384 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p, 1385 String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted ) 1386 { 1387 rbIsQuoted = false; 1388 rField.Erase(); 1389 if ( *p == cStr ) // String in Anfuehrungszeichen 1390 { 1391 rbIsQuoted = true; 1392 const sal_Unicode* p1; 1393 p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE ); 1394 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1395 p++; 1396 // Append remaining unquoted and undelimited data (dirty, dirty) to 1397 // this field. 1398 if (p > p1) 1399 rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) ); 1400 if( *p ) 1401 p++; 1402 } 1403 else // bis zum Trennzeichen 1404 { 1405 const sal_Unicode* p0 = p; 1406 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1407 p++; 1408 rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); 1409 if( *p ) 1410 p++; 1411 } 1412 if ( bMergeSeps ) // folgende Trennzeichen ueberspringen 1413 { 1414 while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) ) 1415 p++; 1416 } 1417 return p; 1418 } 1419 1420 // 1421 // 1422 // 1423 1424 1425 sal_Bool ScImportExport::Doc2Text( SvStream& rStrm ) 1426 { 1427 SCCOL nCol; 1428 SCROW nRow; 1429 SCCOL nStartCol = aRange.aStart.Col(); 1430 SCROW nStartRow = aRange.aStart.Row(); 1431 SCCOL nEndCol = aRange.aEnd.Col(); 1432 SCROW nEndRow = aRange.aEnd.Row(); 1433 String aCell; 1434 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF); 1435 1436 for (nRow = nStartRow; nRow <= nEndRow; nRow++) 1437 { 1438 if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() )) 1439 { 1440 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 1441 { 1442 CellType eType; 1443 pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType ); 1444 switch (eType) 1445 { 1446 case CELLTYPE_FORMULA: 1447 { 1448 if (bFormulas) 1449 { 1450 pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, sal_True ); 1451 if( aCell.Search( cSep ) != STRING_NOTFOUND ) 1452 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1453 else 1454 lcl_WriteSimpleString( rStrm, aCell ); 1455 } 1456 else 1457 { 1458 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1459 1460 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); 1461 if( bMultiLineText ) 1462 { 1463 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) 1464 aCell.SearchAndReplaceAll( _LF, ' ' ); 1465 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) 1466 aCell.ConvertLineEnd(); 1467 } 1468 1469 if( mExportTextOptions.mcSeparatorConvertTo && cSep ) 1470 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); 1471 1472 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) 1473 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1474 else 1475 lcl_WriteSimpleString( rStrm, aCell ); 1476 } 1477 } 1478 break; 1479 case CELLTYPE_VALUE: 1480 { 1481 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1482 lcl_WriteSimpleString( rStrm, aCell ); 1483 } 1484 break; 1485 case CELLTYPE_NOTE: 1486 case CELLTYPE_NONE: 1487 break; 1488 default: 1489 { 1490 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); 1491 1492 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); 1493 if( bMultiLineText ) 1494 { 1495 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) 1496 aCell.SearchAndReplaceAll( _LF, ' ' ); 1497 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) 1498 aCell.ConvertLineEnd(); 1499 } 1500 1501 if( mExportTextOptions.mcSeparatorConvertTo && cSep ) 1502 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); 1503 1504 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) 1505 lcl_WriteString( rStrm, aCell, cStr, cStr ); 1506 else 1507 lcl_WriteSimpleString( rStrm, aCell ); 1508 } 1509 } 1510 if( nCol < nEndCol ) 1511 lcl_WriteSimpleString( rStrm, String(cSep) ); 1512 } 1513 // if( nRow < nEndRow ) 1514 WriteUnicodeOrByteEndl( rStrm ); 1515 if( rStrm.GetError() != SVSTREAM_OK ) 1516 break; 1517 if( nSizeLimit && rStrm.Tell() > nSizeLimit ) 1518 break; 1519 } 1520 } 1521 1522 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1523 } 1524 1525 1526 sal_Bool ScImportExport::Sylk2Doc( SvStream& rStrm ) 1527 { 1528 sal_Bool bOk = sal_True; 1529 sal_Bool bMyDoc = sal_False; 1530 SylkVersion eVersion = SYLK_OTHER; 1531 1532 // US-English separators for StringToDouble 1533 sal_Unicode cDecSep = '.'; 1534 sal_Unicode cGrpSep = ','; 1535 1536 SCCOL nStartCol = aRange.aStart.Col(); 1537 SCROW nStartRow = aRange.aStart.Row(); 1538 SCCOL nEndCol = aRange.aEnd.Col(); 1539 SCROW nEndRow = aRange.aEnd.Row(); 1540 sal_uLong nOldPos = rStrm.Tell(); 1541 sal_Bool bData = sal_Bool( !bSingle ); 1542 SvULongs aFormats; 1543 1544 if( !bSingle) 1545 bOk = StartPaste(); 1546 1547 while( bOk ) 1548 { 1549 String aLine; 1550 String aText; 1551 ByteString aByteLine; 1552 SCCOL nCol = nStartCol; 1553 SCROW nRow = nStartRow; 1554 SCCOL nRefCol = 1; 1555 SCROW nRefRow = 1; 1556 rStrm.Seek( nOldPos ); 1557 for( ;; ) 1558 { 1559 //! allow unicode 1560 rStrm.ReadLine( aByteLine ); 1561 aLine = String( aByteLine, rStrm.GetStreamCharSet() ); 1562 if( rStrm.IsEof() ) 1563 break; 1564 const sal_Unicode* p = aLine.GetBuffer(); 1565 sal_Unicode cTag = *p++; 1566 if( cTag == 'C' ) // Content 1567 { 1568 if( *p++ != ';' ) 1569 return sal_False; 1570 while( *p ) 1571 { 1572 sal_Unicode ch = *p++; 1573 ch = ScGlobal::ToUpperAlpha( ch ); 1574 switch( ch ) 1575 { 1576 case 'X': 1577 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1578 break; 1579 case 'Y': 1580 nRow = String( p ).ToInt32() + nStartRow - 1; 1581 break; 1582 case 'C': 1583 nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1584 break; 1585 case 'R': 1586 nRefRow = String( p ).ToInt32() + nStartRow - 1; 1587 break; 1588 case 'K': 1589 { 1590 if( !bSingle && 1591 ( nCol < nStartCol || nCol > nEndCol 1592 || nRow < nStartRow || nRow > nEndRow 1593 || nCol > MAXCOL || nRow > MAXROW ) ) 1594 break; 1595 if( !bData ) 1596 { 1597 if( nRow > nEndRow ) 1598 nEndRow = nRow; 1599 if( nCol > nEndCol ) 1600 nEndCol = nCol; 1601 break; 1602 } 1603 sal_Bool bText; 1604 if( *p == '"' ) 1605 { 1606 bText = sal_True; 1607 aText.Erase(); 1608 p = lcl_ScanSylkString( p, aText, eVersion); 1609 } 1610 else 1611 bText = sal_False; 1612 const sal_Unicode* q = p; 1613 while( *q && *q != ';' ) 1614 q++; 1615 if ( !(*q == ';' && *(q+1) == 'I') ) 1616 { // don't ignore value 1617 if( bText ) 1618 { 1619 pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(), 1620 ScBaseCell::CreateTextCell( aText, pDoc), 1621 (sal_Bool) sal_True); 1622 } 1623 else 1624 { 1625 double fVal = rtl_math_uStringToDouble( p, 1626 aLine.GetBuffer() + aLine.Len(), 1627 cDecSep, cGrpSep, NULL, NULL ); 1628 pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal ); 1629 } 1630 } 1631 } 1632 break; 1633 case 'E': 1634 case 'M': 1635 { 1636 if ( ch == 'M' ) 1637 { 1638 if ( nRefCol < nCol ) 1639 nRefCol = nCol; 1640 if ( nRefRow < nRow ) 1641 nRefRow = nRow; 1642 if ( !bData ) 1643 { 1644 if( nRefRow > nEndRow ) 1645 nEndRow = nRefRow; 1646 if( nRefCol > nEndCol ) 1647 nEndCol = nRefCol; 1648 } 1649 } 1650 if( !bMyDoc || !bData ) 1651 break; 1652 aText = '='; 1653 p = lcl_ScanSylkFormula( p, aText, eVersion); 1654 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() ); 1655 /* FIXME: do we want GRAM_ODFF_A1 instead? At the 1656 * end it probably should be GRAM_ODFF_R1C1, since 1657 * R1C1 is what Excel writes in SYLK. */ 1658 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1; 1659 ScCompiler aComp( pDoc, aPos); 1660 aComp.SetGrammar(eGrammar); 1661 ScTokenArray* pCode = aComp.CompileString( aText ); 1662 if ( ch == 'M' ) 1663 { 1664 ScMarkData aMark; 1665 aMark.SelectTable( aPos.Tab(), sal_True ); 1666 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol, 1667 nRefRow, aMark, EMPTY_STRING, pCode ); 1668 } 1669 else 1670 { 1671 ScFormulaCell* pFCell = new ScFormulaCell( 1672 pDoc, aPos, pCode, eGrammar, MM_NONE); 1673 pDoc->PutCell( aPos, pFCell ); 1674 } 1675 delete pCode; // ctor/InsertMatrixFormula did copy TokenArray 1676 } 1677 break; 1678 } 1679 while( *p && *p != ';' ) 1680 p++; 1681 if( *p ) 1682 p++; 1683 } 1684 } 1685 else if( cTag == 'F' ) // Format 1686 { 1687 if( *p++ != ';' ) 1688 return sal_False; 1689 sal_Int32 nFormat = -1; 1690 while( *p ) 1691 { 1692 sal_Unicode ch = *p++; 1693 ch = ScGlobal::ToUpperAlpha( ch ); 1694 switch( ch ) 1695 { 1696 case 'X': 1697 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; 1698 break; 1699 case 'Y': 1700 nRow = String( p ).ToInt32() + nStartRow - 1; 1701 break; 1702 case 'P' : 1703 if ( bData ) 1704 { 1705 // F;P<n> sets format code of P;P<code> at 1706 // current position, or at ;X;Y if specified. 1707 // Note that ;X;Y may appear after ;P 1708 const sal_Unicode* p0 = p; 1709 while( *p && *p != ';' ) 1710 p++; 1711 String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); 1712 nFormat = aNumber.ToInt32(); 1713 } 1714 break; 1715 } 1716 while( *p && *p != ';' ) 1717 p++; 1718 if( *p ) 1719 p++; 1720 } 1721 if ( !bData ) 1722 { 1723 if( nRow > nEndRow ) 1724 nEndRow = nRow; 1725 if( nCol > nEndCol ) 1726 nEndCol = nCol; 1727 } 1728 if ( 0 <= nFormat && nFormat < aFormats.Count() ) 1729 { 1730 sal_uLong nKey = aFormats[(sal_uInt16)nFormat]; 1731 pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(), 1732 SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) ); 1733 } 1734 } 1735 else if( cTag == 'P' ) 1736 { 1737 if ( bData && *p == ';' && *(p+1) == 'P' ) 1738 { 1739 String aCode( p+2 ); 1740 // unescape doubled semicolons 1741 xub_StrLen nPos = 0; 1742 String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;")); 1743 while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND ) 1744 aCode.Erase( nPos++, 1 ); 1745 // get rid of Xcl escape characters 1746 nPos = 0; 1747 while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND ) 1748 aCode.Erase( nPos, 1 ); 1749 xub_StrLen nCheckPos; 1750 short nType; 1751 sal_uInt32 nKey; 1752 pDoc->GetFormatTable()->PutandConvertEntry( 1753 aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US, 1754 ScGlobal::eLnge ); 1755 if ( nCheckPos ) 1756 nKey = 0; 1757 aFormats.Insert( nKey, aFormats.Count() ); 1758 } 1759 } 1760 else if( cTag == 'I' && *p == 'D' ) 1761 { 1762 aLine.Erase( 0, 4 ); 1763 if (aLine.EqualsAscii( "CALCOOO32" )) 1764 eVersion = SYLK_OOO32; 1765 else if (aLine.EqualsAscii( "SCALC3" )) 1766 eVersion = SYLK_SCALC3; 1767 bMyDoc = (eVersion <= SYLK_OWN); 1768 } 1769 else if( cTag == 'E' ) // Ende 1770 break; 1771 } 1772 if( !bData ) 1773 { 1774 aRange.aEnd.SetCol( nEndCol ); 1775 aRange.aEnd.SetRow( nEndRow ); 1776 bOk = StartPaste(); 1777 bData = sal_True; 1778 } 1779 else 1780 break; 1781 } 1782 1783 EndPaste(); 1784 return bOk; 1785 } 1786 1787 1788 sal_Bool ScImportExport::Doc2Sylk( SvStream& rStrm ) 1789 { 1790 SCCOL nCol; 1791 SCROW nRow; 1792 SCCOL nStartCol = aRange.aStart.Col(); 1793 SCROW nStartRow = aRange.aStart.Row(); 1794 SCCOL nEndCol = aRange.aEnd.Col(); 1795 SCROW nEndRow = aRange.aEnd.Row(); 1796 String aCellStr; 1797 String aValStr; 1798 lcl_WriteSimpleString( rStrm, 1799 String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32"))); 1800 WriteUnicodeOrByteEndl( rStrm ); 1801 1802 for (nRow = nStartRow; nRow <= nEndRow; nRow++) 1803 { 1804 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 1805 { 1806 String aBufStr; 1807 double nVal; 1808 sal_Bool bForm = sal_False; 1809 SCROW r = nRow - nStartRow + 1; 1810 SCCOL c = nCol - nStartCol + 1; 1811 ScBaseCell* pCell; 1812 pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell ); 1813 CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE); 1814 switch( eType ) 1815 { 1816 case CELLTYPE_FORMULA: 1817 bForm = bFormulas; 1818 if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) ) 1819 goto hasvalue; 1820 else 1821 goto hasstring; 1822 1823 case CELLTYPE_VALUE: 1824 hasvalue: 1825 pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal ); 1826 1827 aValStr = ::rtl::math::doubleToUString( nVal, 1828 rtl_math_StringFormat_Automatic, 1829 rtl_math_DecimalPlaces_Max, '.', sal_True ); 1830 1831 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); 1832 aBufStr += String::CreateFromInt32( c ); 1833 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); 1834 aBufStr += String::CreateFromInt32( r ); 1835 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); 1836 aBufStr += aValStr; 1837 lcl_WriteSimpleString( rStrm, aBufStr ); 1838 goto checkformula; 1839 1840 case CELLTYPE_STRING: 1841 case CELLTYPE_EDIT: 1842 hasstring: 1843 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr ); 1844 aCellStr.SearchAndReplaceAll( _LF, SYLK_LF ); 1845 1846 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); 1847 aBufStr += String::CreateFromInt32( c ); 1848 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); 1849 aBufStr += String::CreateFromInt32( r ); 1850 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); 1851 lcl_WriteSimpleString( rStrm, aBufStr ); 1852 lcl_WriteString( rStrm, aCellStr, '"', ';' ); 1853 1854 checkformula: 1855 if( bForm ) 1856 { 1857 const ScFormulaCell* pFCell = 1858 static_cast<const ScFormulaCell*>(pCell); 1859 switch ( pFCell->GetMatrixFlag() ) 1860 { 1861 case MM_REFERENCE : 1862 aCellStr.Erase(); 1863 break; 1864 default: 1865 pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1); 1866 /* FIXME: do we want GRAM_ODFF_A1 instead? At 1867 * the end it probably should be 1868 * GRAM_ODFF_R1C1, since R1C1 is what Excel 1869 * writes in SYLK. */ 1870 } 1871 if ( pFCell->GetMatrixFlag() != MM_NONE && 1872 aCellStr.Len() > 2 && 1873 aCellStr.GetChar(0) == '{' && 1874 aCellStr.GetChar(aCellStr.Len()-1) == '}' ) 1875 { // cut off matrix {} characters 1876 aCellStr.Erase(aCellStr.Len()-1,1); 1877 aCellStr.Erase(0,1); 1878 } 1879 if ( aCellStr.GetChar(0) == '=' ) 1880 aCellStr.Erase(0,1); 1881 String aPrefix; 1882 switch ( pFCell->GetMatrixFlag() ) 1883 { 1884 case MM_FORMULA : 1885 { // diff expression with 'M' M$-extension 1886 SCCOL nC; 1887 SCROW nR; 1888 pFCell->GetMatColsRows( nC, nR ); 1889 nC += c - 1; 1890 nR += r - 1; 1891 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) ); 1892 aPrefix += String::CreateFromInt32( nR ); 1893 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); 1894 aPrefix += String::CreateFromInt32( nC ); 1895 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) ); 1896 } 1897 break; 1898 case MM_REFERENCE : 1899 { // diff expression with 'I' M$-extension 1900 ScAddress aPos; 1901 pFCell->GetMatrixOrigin( aPos ); 1902 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) ); 1903 aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 ); 1904 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); 1905 aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 ); 1906 } 1907 break; 1908 default: 1909 // formula Expression 1910 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) ); 1911 } 1912 lcl_WriteSimpleString( rStrm, aPrefix ); 1913 if ( aCellStr.Len() ) 1914 lcl_WriteString( rStrm, aCellStr, 0, ';' ); 1915 } 1916 WriteUnicodeOrByteEndl( rStrm ); 1917 break; 1918 1919 default: 1920 { 1921 // added to avoid warnings 1922 } 1923 } 1924 } 1925 } 1926 lcl_WriteSimpleString( rStrm, String( 'E' ) ); 1927 WriteUnicodeOrByteEndl( rStrm ); 1928 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1929 } 1930 1931 1932 sal_Bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL ) 1933 { 1934 // CharSet is ignored in ScExportHTML, read from Load/Save HTML options 1935 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll, 1936 aStreamPath, aNonConvertibleChars ); 1937 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1938 } 1939 1940 sal_Bool ScImportExport::Doc2RTF( SvStream& rStrm ) 1941 { 1942 // CharSet is ignored in ScExportRTF 1943 ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW ); 1944 return sal_Bool( rStrm.GetError() == SVSTREAM_OK ); 1945 } 1946 1947 1948 sal_Bool ScImportExport::Doc2Dif( SvStream& rStrm ) 1949 { 1950 // for DIF in the clipboard, IBM_850 is always used 1951 ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 ); 1952 return sal_True; 1953 } 1954 1955 1956 sal_Bool ScImportExport::Dif2Doc( SvStream& rStrm ) 1957 { 1958 SCTAB nTab = aRange.aStart.Tab(); 1959 ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO ); 1960 pImportDoc->InitUndo( pDoc, nTab, nTab ); 1961 1962 // for DIF in the clipboard, IBM_850 is always used 1963 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 ); 1964 1965 SCCOL nEndCol; 1966 SCROW nEndRow; 1967 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow ); 1968 // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start 1969 if ( nEndCol < aRange.aStart.Col() ) 1970 nEndCol = aRange.aStart.Col(); 1971 if ( nEndRow < aRange.aStart.Row() ) 1972 nEndRow = aRange.aStart.Row(); 1973 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab ); 1974 1975 sal_Bool bOk = StartPaste(); 1976 if (bOk) 1977 { 1978 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 1979 pDoc->DeleteAreaTab( aRange, nFlags ); 1980 pImportDoc->CopyToDocument( aRange, nFlags, sal_False, pDoc ); 1981 EndPaste(); 1982 } 1983 1984 delete pImportDoc; 1985 1986 return bOk; 1987 } 1988 1989 1990 sal_Bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL ) 1991 { 1992 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange ); 1993 if (!pImp) 1994 return false; 1995 pImp->Read( rStrm, rBaseURL ); 1996 aRange = pImp->GetRange(); 1997 1998 sal_Bool bOk = StartPaste(); 1999 if (bOk) 2000 { 2001 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 2002 pDoc->DeleteAreaTab( aRange, nFlags ); 2003 pImp->WriteToDocument(); 2004 EndPaste(); 2005 } 2006 delete pImp; 2007 return bOk; 2008 } 2009 2010 2011 sal_Bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL ) 2012 { 2013 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, sal_True); 2014 if (!pImp) 2015 return false; 2016 pImp->Read( rStrm, rBaseURL ); 2017 aRange = pImp->GetRange(); 2018 2019 sal_Bool bOk = StartPaste(); 2020 if (bOk) 2021 { 2022 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in 2023 // a Draw Layer but no Draw View -> create Draw Layer and View here 2024 if (pDocSh) 2025 pDocSh->MakeDrawLayer(); 2026 2027 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES; 2028 pDoc->DeleteAreaTab( aRange, nFlags ); 2029 pImp->WriteToDocument(); 2030 EndPaste(); 2031 } 2032 delete pImp; 2033 return bOk; 2034 } 2035 2036 #define RETURN_ERROR { return eERR_INTERN; } 2037 class ScFormatFilterMissing : public ScFormatFilterPlugin { 2038 public: 2039 ScFormatFilterMissing() 2040 { 2041 OSL_ASSERT ("Missing file filters"); 2042 } 2043 virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR 2044 virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR 2045 virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR 2046 virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR 2047 virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&, 2048 const CharSet, sal_uInt32 ) RETURN_ERROR 2049 virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR 2050 virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, sal_Bool, SvNumberFormatter*, bool ) RETURN_ERROR 2051 2052 virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; } 2053 virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, sal_Bool ) { return NULL; } 2054 virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); } 2055 2056 #if ENABLE_LOTUS123_EXPORT 2057 virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR 2058 #endif 2059 virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR 2060 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR 2061 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR 2062 virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, sal_Bool, 2063 const String&, String& ) RETURN_ERROR 2064 virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR 2065 }; 2066 2067 extern "C" { static void SAL_CALL thisModule() {} } 2068 typedef ScFormatFilterPlugin * (*FilterFn)(void); 2069 ScFormatFilterPlugin &ScFormatFilter::Get() 2070 { 2071 static ScFormatFilterPlugin *plugin; 2072 2073 if (plugin != NULL) 2074 return *plugin; 2075 2076 static ::osl::Module aModule; 2077 if ( aModule.loadRelative( &thisModule, 2078 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) ) 2079 { 2080 oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) ); 2081 if (fn != NULL) 2082 plugin = reinterpret_cast<FilterFn>(fn)(); 2083 } 2084 if (plugin == NULL) 2085 plugin = new ScFormatFilterMissing(); 2086 2087 return *plugin; 2088 } 2089