Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / docshell / impex.cxx
blob1ca265e2c6be192982dd04ea4015e8eee5947da4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sc.hrc"
22 #include <comphelper/processfactory.hxx>
23 #include <i18nlangtag/languagetag.hxx>
24 #include <sot/formats.hxx>
25 #include <sfx2/mieclip.hxx>
26 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
28 #include "global.hxx"
29 #include "scerrors.hxx"
30 #include "docsh.hxx"
31 #include "undoblk.hxx"
32 #include "rangenam.hxx"
33 #include "viewdata.hxx"
34 #include "tabvwsh.hxx"
35 #include "filter.hxx"
36 #include "asciiopt.hxx"
37 #include "formulacell.hxx"
38 #include "docoptio.hxx"
39 #include "progress.hxx"
40 #include "scitems.hxx"
41 #include "editable.hxx"
42 #include "compiler.hxx"
43 #include "warnbox.hxx"
44 #include "clipparam.hxx"
45 #include "impex.hxx"
46 #include "editutil.hxx"
47 #include "patattr.hxx"
48 #include "docpool.hxx"
49 #include "stringutil.hxx"
50 #include "cellvalue.hxx"
51 #include "tokenarray.hxx"
52 #include "documentimport.hxx"
54 #include "globstr.hrc"
55 #include <vcl/svapp.hxx>
57 //========================================================================
59 // We don't want to end up with 2GB read in one line just because of malformed
60 // multiline fields, so chop it _somewhere_, which is twice supported columns
61 // times maximum cell content length, 2*1024*64K=128M, and because it's
62 // sal_Unicode that's 256MB. If it's 2GB of data without LF we're out of luck
63 // anyway.
64 static const sal_Int32 nArbitraryLineLengthLimit = 2 * MAXCOLCOUNT * STRING_MAXLEN;
66 namespace
68 const char SYLK_LF[] = "\x1b :";
69 const char DOUBLE_SEMICOLON[] = ";;";
70 const char DOUBLE_DOUBLEQUOTE[] = "\"\"";
73 enum SylkVersion
75 SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
76 SYLK_OOO32, // Correct strings, plus multiline content.
77 SYLK_OWN, // Place our new versions, if any, before this value.
78 SYLK_OTHER // Assume that aliens wrote correct strings.
82 // Gesamtdokument ohne Undo
85 ScImportExport::ScImportExport( ScDocument* p )
86 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
87 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
88 bFormulas( false ), bIncludeFiltered( true ),
89 bAll( true ), bSingle( true ), bUndo( false ),
90 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
91 mbApi( true ), mExportTextOptions()
93 pUndoDoc = NULL;
94 pExtOptions = NULL;
97 // Insert am Punkt ohne Bereichschecks
100 ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
101 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
102 aRange( rPt ),
103 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
104 bFormulas( false ), bIncludeFiltered( true ),
105 bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
106 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
107 mbApi( true ), mExportTextOptions()
109 pUndoDoc = NULL;
110 pExtOptions = NULL;
114 // ctor with a range is only used for export
115 //! ctor with a string (and bSingle=true) is also used for DdeSetData
117 ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
118 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
119 aRange( r ),
120 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
121 bFormulas( false ), bIncludeFiltered( true ),
122 bAll( false ), bSingle( false ), bUndo( pDocSh != NULL ),
123 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
124 mbApi( true ), mExportTextOptions()
126 pUndoDoc = NULL;
127 pExtOptions = NULL;
128 // Zur Zeit nur in einer Tabelle!
129 aRange.aEnd.SetTab( aRange.aStart.Tab() );
132 // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
133 // Falls eine View existiert, wird die TabNo der View entnommen!
136 ScImportExport::ScImportExport( ScDocument* p, const OUString& rPos )
137 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
138 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
139 bFormulas( false ), bIncludeFiltered( true ),
140 bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
141 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
142 mbApi( true ), mExportTextOptions()
144 pUndoDoc = NULL;
145 pExtOptions = NULL;
147 SCTAB nTab = ScDocShell::GetCurTab();
148 aRange.aStart.SetTab( nTab );
149 OUString aPos( rPos );
150 // Benannter Bereich?
151 ScRangeName* pRange = pDoc->GetRangeName();
152 if( pRange )
154 const ScRangeData* pData = pRange->findByUpperName(ScGlobal::pCharClass->uppercase(aPos));
155 if (pData)
157 if( pData->HasType( RT_REFAREA )
158 || pData->HasType( RT_ABSAREA )
159 || pData->HasType( RT_ABSPOS ) )
160 pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten
163 formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
164 // Bereich?
165 if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID )
166 bSingle = false;
167 // Zelle?
168 else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID )
169 aRange.aEnd = aRange.aStart;
170 else
171 bAll = true;
175 ScImportExport::~ScImportExport()
177 delete pUndoDoc;
178 delete pExtOptions;
182 void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
184 if ( pExtOptions )
185 *pExtOptions = rOpt;
186 else
187 pExtOptions = new ScAsciiOptions( rOpt );
189 // "normale" Optionen uebernehmen
191 cSep = ScAsciiOptions::GetWeightedFieldSep( rOpt.GetFieldSeps(), false);
192 cStr = rOpt.GetTextSep();
196 bool ScImportExport::IsFormatSupported( sal_uLong nFormat )
198 return nFormat == FORMAT_STRING
199 || nFormat == SOT_FORMATSTR_ID_SYLK
200 || nFormat == SOT_FORMATSTR_ID_LINK
201 || nFormat == SOT_FORMATSTR_ID_HTML
202 || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE
203 || nFormat == SOT_FORMATSTR_ID_DIF;
207 //////////////////////////////////////////////////////////////////////////////
209 // Vorbereitung fuer Undo: Undo-Dokument erzeugen
212 bool ScImportExport::StartPaste()
214 if ( !bAll )
216 ScEditableTester aTester( pDoc, aRange );
217 if ( !aTester.IsEditable() )
219 InfoBox aInfoBox(Application::GetDefDialogParent(),
220 ScGlobal::GetRscString( aTester.GetMessageId() ) );
221 aInfoBox.Execute();
222 return false;
225 if( bUndo && pDocSh && pDoc->IsUndoEnabled())
227 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
228 pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
229 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pUndoDoc );
231 return true;
234 // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
237 void ScImportExport::EndPaste(bool bAutoRowHeight)
239 bool bHeight = bAutoRowHeight && pDocSh && pDocSh->AdjustRowHeight(
240 aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
242 if( pUndoDoc && pDoc->IsUndoEnabled() )
244 ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
245 pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
246 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pRedoDoc );
247 ScMarkData aDestMark;
248 aDestMark.SetMarkArea(aRange);
249 pDocSh->GetUndoManager()->AddUndoAction(
250 new ScUndoPaste(pDocSh, aRange, aDestMark, pUndoDoc, pRedoDoc, IDF_ALL, NULL));
252 pUndoDoc = NULL;
253 if( pDocSh )
255 if (!bHeight)
256 pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber
257 pDocSh->SetDocumentModified();
259 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
260 if ( pViewSh )
261 pViewSh->UpdateInputHandler();
265 /////////////////////////////////////////////////////////////////////////////
267 bool ScImportExport::ImportData( const OUString& /* rMimeType */,
268 const ::com::sun::star::uno::Any & /* rValue */ )
270 OSL_ENSURE( !this, "Implementation is missing" );
271 return false;
274 bool ScImportExport::ExportData( const OUString& rMimeType,
275 ::com::sun::star::uno::Any & rValue )
277 SvMemoryStream aStrm;
278 // mba: no BaseURL for data exchange
279 if( ExportStream( aStrm, OUString(),
280 SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
282 aStrm << (sal_uInt8) 0;
283 rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
284 (sal_Int8*)aStrm.GetData(),
285 aStrm.Seek( STREAM_SEEK_TO_END ) );
286 return true;
288 return false;
292 bool ScImportExport::ImportString( const OUString& rText, sal_uLong nFmt )
294 switch ( nFmt )
296 // formats supporting unicode
297 case FORMAT_STRING :
299 ScImportStringStream aStrm( rText);
300 return ImportStream( aStrm, OUString(), nFmt );
301 // ImportStream must handle RTL_TEXTENCODING_UNICODE
303 //break;
304 default:
306 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
307 OString aTmp( rText.getStr(), rText.getLength(), eEnc );
308 SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ );
309 aStrm.SetStreamCharSet( eEnc );
310 SetNoEndianSwap( aStrm ); //! no swapping in memory
311 return ImportStream( aStrm, OUString(), nFmt );
317 bool ScImportExport::ExportString( OUString& rText, sal_uLong nFmt )
319 OSL_ENSURE( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
320 if ( nFmt != FORMAT_STRING )
322 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
323 OString aTmp;
324 bool bOk = ExportByteString( aTmp, eEnc, nFmt );
325 rText = OStringToOUString( aTmp, eEnc );
326 return bOk;
328 // nSizeLimit not needed for OUString
330 SvMemoryStream aStrm;
331 aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
332 SetNoEndianSwap( aStrm ); //! no swapping in memory
333 // mba: no BaseURL for data exc
334 if( ExportStream( aStrm, OUString(), nFmt ) )
336 aStrm << (sal_Unicode) 0;
337 aStrm.Seek( STREAM_SEEK_TO_END );
339 rText = OUString( (const sal_Unicode*) aStrm.GetData() );
340 return true;
342 rText = OUString();
343 return false;
345 // ExportStream must handle RTL_TEXTENCODING_UNICODE
349 bool ScImportExport::ExportByteString( OString& rText, rtl_TextEncoding eEnc, sal_uLong nFmt )
351 OSL_ENSURE( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
352 if ( eEnc == RTL_TEXTENCODING_UNICODE )
353 eEnc = osl_getThreadTextEncoding();
355 if (!nSizeLimit)
356 nSizeLimit = STRING_MAXLEN;
358 SvMemoryStream aStrm;
359 aStrm.SetStreamCharSet( eEnc );
360 SetNoEndianSwap( aStrm ); //! no swapping in memory
361 // mba: no BaseURL for data exchange
362 if( ExportStream( aStrm, OUString(), nFmt ) )
364 aStrm << (sal_Char) 0;
365 aStrm.Seek( STREAM_SEEK_TO_END );
366 // Sicherheits-Check:
367 if( aStrm.Tell() <= (sal_uLong) STRING_MAXLEN )
369 rText = (const sal_Char*) aStrm.GetData();
370 return true;
373 rText = OString();
374 return false;
378 bool ScImportExport::ImportStream( SvStream& rStrm, const OUString& rBaseURL, sal_uLong nFmt )
380 if( nFmt == FORMAT_STRING )
382 if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten
383 return true;
385 if( nFmt == SOT_FORMATSTR_ID_SYLK )
387 if( Sylk2Doc( rStrm ) )
388 return true;
390 if( nFmt == SOT_FORMATSTR_ID_DIF )
392 if( Dif2Doc( rStrm ) )
393 return true;
395 if( nFmt == FORMAT_RTF )
397 if( RTF2Doc( rStrm, rBaseURL ) )
398 return true;
400 if( nFmt == SOT_FORMATSTR_ID_LINK )
401 return true; // Link-Import?
402 if ( nFmt == SOT_FORMATSTR_ID_HTML )
404 if( HTML2Doc( rStrm, rBaseURL ) )
405 return true;
407 if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
409 MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
410 SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
411 if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
412 return true;
415 return false;
419 bool ScImportExport::ExportStream( SvStream& rStrm, const OUString& rBaseURL, sal_uLong nFmt )
421 if( nFmt == FORMAT_STRING )
423 if( Doc2Text( rStrm ) )
424 return true;
426 if( nFmt == SOT_FORMATSTR_ID_SYLK )
428 if( Doc2Sylk( rStrm ) )
429 return true;
431 if( nFmt == SOT_FORMATSTR_ID_DIF )
433 if( Doc2Dif( rStrm ) )
434 return true;
436 if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll )
438 OUString aDocName;
439 if ( pDoc->IsClipboard() )
440 aDocName = ScGlobal::GetClipDocName();
441 else
443 SfxObjectShell* pShell = pDoc->GetDocumentShell();
444 if (pShell)
445 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
448 OSL_ENSURE( !aDocName.isEmpty(), "ClipBoard document has no name! :-/" );
449 if( !aDocName.isEmpty() )
451 // Always use Calc A1 syntax for paste link.
452 OUString aRefName;
453 sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
454 if( bSingle )
455 aRefName = aRange.aStart.Format(nFlags, pDoc, formula::FormulaGrammar::CONV_OOO);
456 else
458 if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
459 nFlags |= SCA_TAB2_3D;
460 aRefName = aRange.Format(nFlags, pDoc, formula::FormulaGrammar::CONV_OOO);
462 OUString aAppName = Application::GetAppName();
464 // extra bits are used to tell the client to prefer external
465 // reference link.
466 OUString aExtraBits("calc:extref");
468 WriteUnicodeOrByteString( rStrm, aAppName, true );
469 WriteUnicodeOrByteString( rStrm, aDocName, true );
470 WriteUnicodeOrByteString( rStrm, aRefName, true );
471 WriteUnicodeOrByteString( rStrm, aExtraBits, true );
472 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
473 rStrm << sal_Unicode(0);
474 else
475 rStrm << sal_Char(0);
476 return rStrm.GetError() == SVSTREAM_OK;
479 if( nFmt == SOT_FORMATSTR_ID_HTML )
481 if( Doc2HTML( rStrm, rBaseURL ) )
482 return true;
484 if( nFmt == FORMAT_RTF )
486 if( Doc2RTF( rStrm ) )
487 return true;
490 return false;
494 void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const OUString& rString, bool bZero )
496 rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
497 if ( eEnc == RTL_TEXTENCODING_UNICODE )
499 if ( !IsEndianSwap( rStrm ) )
500 rStrm.Write( rString.getStr(), rString.getLength() * sizeof(sal_Unicode) );
501 else
503 const sal_Unicode* p = rString.getStr();
504 const sal_Unicode* const pStop = p + rString.getLength();
505 while ( p < pStop )
507 rStrm << *p;
510 if ( bZero )
511 rStrm << sal_Unicode(0);
513 else
515 OString aByteStr(OUStringToOString(rString, eEnc));
516 rStrm << aByteStr.getStr();
517 if ( bZero )
518 rStrm << sal_Char(0);
523 // This function could be replaced by endlub()
524 void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
526 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
527 { // same as endl() but unicode
528 switch ( rStrm.GetLineDelimiter() )
530 case LINEEND_CR :
531 rStrm << sal_Unicode('\r');
532 break;
533 case LINEEND_LF :
534 rStrm << sal_Unicode('\n');
535 break;
536 default:
537 rStrm << sal_Unicode('\r') << sal_Unicode('\n');
540 else
541 endl( rStrm );
545 enum QuoteType
547 FIELDSTART_QUOTE,
548 FIRST_QUOTE,
549 SECOND_QUOTE,
550 FIELDEND_QUOTE,
551 DONTKNOW_QUOTE
555 /** Determine if *p is a quote that ends a quoted field.
557 Precondition: we are parsing a quoted field already and *p is a quote.
559 @return
560 FIELDEND_QUOTE if end of field quote
561 DONTKNOW_QUOTE anything else
563 static QuoteType lcl_isFieldEndQuote( const sal_Unicode* p, const sal_Unicode* pSeps )
565 // Due to broken CSV generators that don't double embedded quotes check if
566 // a field separator immediately or with trailing spaces follows the quote,
567 // only then end the field, or at end of string.
568 const sal_Unicode cBlank = ' ';
569 if (p[1] == cBlank && ScGlobal::UnicodeStrChr( pSeps, cBlank))
570 return FIELDEND_QUOTE;
571 while (p[1] == cBlank)
572 ++p;
573 if (!p[1] || ScGlobal::UnicodeStrChr( pSeps, p[1]))
574 return FIELDEND_QUOTE;
575 return DONTKNOW_QUOTE;
579 /** Determine if *p is a quote that is escaped by being doubled or ends a
580 quoted field.
582 Precondition: *p is a quote.
584 @param nQuotes
585 Quote characters encountered so far.
586 Odd (after opening quote) means either no embedded quotes or only quote
587 pairs so far.
588 Even means either not in a quoted field or already one quote
589 encountered, the first of a pair.
591 @return
592 FIELDSTART_QUOTE if first quote in a field, either starting content or
593 embedded so caller should check beforehand.
594 FIRST_QUOTE if first of a doubled quote
595 SECOND_QUOTE if second of a doubled quote
596 FIELDEND_QUOTE if end of field quote
597 DONTKNOW_QUOTE if an unescaped quote we don't consider as end of field,
598 do not increment nQuotes in caller then!
600 static QuoteType lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes, const sal_Unicode* p,
601 const sal_Unicode* pSeps, sal_Unicode cStr )
603 if ((nQuotes % 2) == 0)
605 if (p[-1] == cStr)
606 return SECOND_QUOTE;
607 else
609 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
610 return FIELDSTART_QUOTE;
613 if (p[1] == cStr)
614 return FIRST_QUOTE;
615 return lcl_isFieldEndQuote( p, pSeps);
619 /** Append characters of [p1,p2) to rField.
621 @returns TRUE if ok; FALSE if data overflow, truncated
623 static bool lcl_appendLineData( OUString& rField, const sal_Unicode* p1, const sal_Unicode* p2 )
625 OSL_ENSURE( rField.getLength() + (p2 - p1) <= STRING_MAXLEN, "lcl_appendLineData: data overflow");
626 if (rField.getLength() + (p2 - p1) <= STRING_MAXLEN)
628 rField += OUString( p1, sal::static_int_cast<sal_Int32>( p2 - p1 ) );
629 return true;
631 else
633 rField += OUString( p1, STRING_MAXLEN - rField.getLength() );
634 return false;
639 enum DoubledQuoteMode
641 DQM_KEEP_ALL, // both are taken, additionally start and end quote are included in string
642 DQM_KEEP, // both are taken
643 DQM_ESCAPE, // escaped quote, one is taken, one ignored
644 DQM_CONCAT, // first is end, next is start, both ignored => strings combined
645 DQM_SEPARATE // end one string and begin next
648 static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rString,
649 const sal_Unicode* pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool& rbOverflowCell )
651 if (eMode != DQM_KEEP_ALL)
652 p++; //! jump over opening quote
653 bool bCont;
656 bCont = false;
657 const sal_Unicode* p0 = p;
658 for( ;; )
660 if( !*p )
661 break;
662 if( *p == cStr )
664 if ( *++p != cStr )
666 // break or continue for loop
667 if (eMode == DQM_ESCAPE)
669 if (lcl_isFieldEndQuote( p-1, pSeps) == FIELDEND_QUOTE)
670 break;
671 else
672 continue;
674 else
675 break;
677 // doubled quote char
678 switch ( eMode )
680 case DQM_KEEP_ALL :
681 case DQM_KEEP :
682 p++; // both for us (not breaking for-loop)
683 break;
684 case DQM_ESCAPE :
685 p++; // one for us (breaking for-loop)
686 bCont = true; // and more
687 break;
688 case DQM_CONCAT :
689 if ( p0+1 < p )
691 // first part
692 if (!lcl_appendLineData( rString, p0, p-1))
693 rbOverflowCell = true;
695 p0 = ++p; // text of next part starts here
696 break;
697 case DQM_SEPARATE :
698 // positioned on next opening quote
699 break;
701 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
702 break;
704 else
705 p++;
707 if ( p0 < p )
709 if (!lcl_appendLineData( rString, p0, ((eMode != DQM_KEEP_ALL && (*p || *(p-1) == cStr)) ? p-1 : p)))
710 rbOverflowCell = true;
712 } while ( bCont );
713 return p;
716 static void lcl_UnescapeSylk( OUString & rString, SylkVersion eVersion )
718 // Older versions didn't escape the semicolon.
719 // Older versions quoted the string and doubled embedded quotes, but not
720 // the semicolons, which was plain wrong.
721 if (eVersion >= SYLK_OOO32)
722 rString = rString.replaceAll( OUString(DOUBLE_SEMICOLON), OUString(';') );
723 else
724 rString = rString.replaceAll( OUString(DOUBLE_DOUBLEQUOTE), OUString('"') );
726 rString = rString.replaceAll( OUString(SYLK_LF), OUString('\n') );
729 static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
730 OUString& rString, SylkVersion eVersion )
732 const sal_Unicode* pStartQuote = p;
733 const sal_Unicode* pEndQuote = 0;
734 while( *(++p) )
736 if( *p == '"' )
738 pEndQuote = p;
739 if (eVersion >= SYLK_OOO32)
741 if (*(p+1) == ';')
743 if (*(p+2) == ';')
745 p += 2; // escaped ';'
746 pEndQuote = 0;
748 else
749 break; // end field
752 else
754 if (*(p+1) == '"')
756 ++p; // escaped '"'
757 pEndQuote = 0;
759 else if (*(p+1) == ';')
760 break; // end field
764 if (!pEndQuote)
765 pEndQuote = p; // Take all data as string.
766 rString += OUString(pStartQuote + 1, sal::static_int_cast<sal_Int32>( pEndQuote - pStartQuote - 1 ) );
767 lcl_UnescapeSylk( rString, eVersion);
768 return p;
771 static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
772 OUString& rString, SylkVersion eVersion )
774 const sal_Unicode* pStart = p;
775 if (eVersion >= SYLK_OOO32)
777 while (*p)
779 if (*p == ';')
781 if (*(p+1) == ';')
782 ++p; // escaped ';'
783 else
784 break; // end field
786 ++p;
788 rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
789 lcl_UnescapeSylk( rString, eVersion);
791 else
793 // Nasty. If in old versions the formula contained a semicolon, it was
794 // quoted and embedded quotes were doubled, but semicolons were not. If
795 // there was no semicolon, it could still contain quotes and doubled
796 // embedded quotes if it was something like ="a""b", which was saved as
797 // E"a""b" as is and has to be preserved, even if older versions
798 // couldn't even load it correctly. However, theoretically another
799 // field might follow and thus the line contain a semicolon again, such
800 // as ...;E"a""b";...
801 bool bQuoted = false;
802 if (*p == '"')
804 // May be a quoted expression or just a string constant expression
805 // with quotes.
806 while (*(++p))
808 if (*p == '"')
810 if (*(p+1) == '"')
811 ++p; // escaped '"'
812 else
813 break; // closing '"', had no ';' yet
815 else if (*p == ';')
817 bQuoted = true; // ';' within quoted expression
818 break;
821 p = pStart;
823 if (bQuoted)
824 p = lcl_ScanSylkString( p, rString, eVersion);
825 else
827 while (*p && *p != ';')
828 ++p;
829 rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
832 return p;
835 static void lcl_DoubleEscapeChar( OUString& rString, sal_Unicode cStr )
837 sal_Int32 n = 0;
838 while( ( n = rString.indexOf( cStr, n ) ) != -1 )
840 rString = rString.replaceAt( n, 0, OUString(cStr) );
841 n += 2;
845 static void lcl_WriteString( SvStream& rStrm, OUString& rString, sal_Unicode cQuote, sal_Unicode cEsc )
847 if (cEsc)
848 lcl_DoubleEscapeChar( rString, cEsc );
850 if (cQuote)
852 rString = OUString(cQuote) + rString + OUString(cQuote);
855 ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
858 static inline void lcl_WriteSimpleString( SvStream& rStrm, const OUString& rString )
860 ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
863 //////////////////////////////////////////////////////////////////////////////
866 bool ScImportExport::Text2Doc( SvStream& rStrm )
868 bool bOk = true;
870 sal_Unicode pSeps[2];
871 pSeps[0] = cSep;
872 pSeps[1] = 0;
874 SCCOL nStartCol = aRange.aStart.Col();
875 SCROW nStartRow = aRange.aStart.Row();
876 SCCOL nEndCol = aRange.aEnd.Col();
877 SCROW nEndRow = aRange.aEnd.Row();
878 sal_uLong nOldPos = rStrm.Tell();
879 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
880 bool bData = !bSingle;
881 if( !bSingle)
882 bOk = StartPaste();
884 while( bOk )
886 OUString aLine;
887 OUString aCell;
888 SCROW nRow = nStartRow;
889 rStrm.Seek( nOldPos );
890 for( ;; )
892 rStrm.ReadUniOrByteStringLine( aLine, rStrm.GetStreamCharSet(), nArbitraryLineLengthLimit );
893 if( rStrm.IsEof() )
894 break;
895 SCCOL nCol = nStartCol;
896 const sal_Unicode* p = aLine.getStr();
897 while( *p )
899 aCell = "";
900 const sal_Unicode* q = p;
901 while (*p && *p != cSep)
903 // Always look for a pairing quote and ignore separator in between.
904 while (*p && *p == cStr)
905 q = p = lcl_ScanString( p, aCell, pSeps, cStr, DQM_KEEP_ALL, bOverflowCell );
906 // All until next separator or quote.
907 while (*p && *p != cSep && *p != cStr)
908 ++p;
909 if (!lcl_appendLineData( aCell, q, p))
910 bOverflowCell = true; // display warning on import
911 q = p;
913 if (*p)
914 ++p;
915 if (ValidCol(nCol) && ValidRow(nRow) )
917 if( bSingle )
919 if (nCol>nEndCol) nEndCol = nCol;
920 if (nRow>nEndRow) nEndRow = nRow;
922 if( bData && nCol <= nEndCol && nRow <= nEndRow )
923 pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
925 else // zuviele Spalten/Zeilen
927 if (!ValidRow(nRow))
928 bOverflowRow = true; // display warning on import
929 if (!ValidCol(nCol))
930 bOverflowCol = true; // display warning on import
932 ++nCol;
934 ++nRow;
937 if( !bData )
939 aRange.aEnd.SetCol( nEndCol );
940 aRange.aEnd.SetRow( nEndRow );
941 bOk = StartPaste();
942 bData = true;
944 else
945 break;
948 EndPaste();
949 return bOk;
953 // erweiterter Ascii-Import
957 static bool lcl_PutString(
958 ScDocumentImport& rDocImport, SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rStr, sal_uInt8 nColFormat,
959 SvNumberFormatter* pFormatter, bool bDetectNumFormat,
960 ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
961 ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
963 ScDocument* pDoc = &rDocImport.getDoc();
964 bool bMultiLine = false;
965 if ( nColFormat == SC_COL_SKIP || rStr.isEmpty() || !ValidCol(nCol) || !ValidRow(nRow) )
966 return bMultiLine;
968 if ( nColFormat == SC_COL_TEXT )
970 double fDummy;
971 sal_uInt32 nIndex = 0;
972 if (pFormatter->IsNumberFormat(rStr, nIndex, fDummy))
974 // Set the format of this cell to Text.
975 sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
976 ScPatternAttr aNewAttrs(pDoc->GetPool());
977 SfxItemSet& rSet = aNewAttrs.GetItemSet();
978 rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
979 pDoc->ApplyPattern(nCol, nRow, nTab, aNewAttrs);
982 if(ScStringUtil::isMultiline(rStr))
984 ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
985 rEngine.SetText(rStr);
986 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
987 return true;
989 else
991 rDocImport.setStringCell(ScAddress(nCol, nRow, nTab), rStr);
992 return false;
996 if ( nColFormat == SC_COL_ENGLISH )
998 //! SetString mit Extra-Flag ???
1000 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1001 sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
1002 double fVal;
1003 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
1005 // Zahlformat wird nicht auf englisch gesetzt
1006 rDocImport.setNumericCell( ScAddress( nCol, nRow, nTab ), fVal );
1007 return bMultiLine;
1009 // sonst weiter mit SetString
1011 else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate
1013 const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
1014 sal_Int32 nLen = rStr.getLength();
1015 sal_Int32 nStart[nMaxNumberParts];
1016 sal_Int32 nEnd[nMaxNumberParts];
1018 sal_uInt16 nDP, nMP, nYP;
1019 switch ( nColFormat )
1021 case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
1022 case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
1023 case SC_COL_DMY:
1024 default: nDP = 0; nMP = 1; nYP = 2; break;
1027 sal_uInt16 nFound = 0;
1028 bool bInNum = false;
1029 for ( sal_Int32 nPos=0; nPos<nLen && (bInNum ||
1030 nFound<nMaxNumberParts); nPos++ )
1032 if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
1033 nPos <= nStart[nFound]+2 && rStr[nPos] == 'T')
1034 bInNum = false; // ISO-8601: YYYY-MM-DDThh:mm...
1035 else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
1036 && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
1037 || ScGlobal::pCharClass->isDigit( rStr, nPos))
1039 if (!bInNum)
1041 bInNum = true;
1042 nStart[nFound] = nPos;
1043 ++nFound;
1045 nEnd[nFound-1] = nPos;
1047 else
1048 bInNum = false;
1051 if ( nFound == 1 )
1053 // try to break one number (without separators) into date fields
1055 sal_Int32 nDateStart = nStart[0];
1056 sal_Int32 nDateLen = nEnd[0] + 1 - nDateStart;
1058 if ( nDateLen >= 5 && nDateLen <= 8 &&
1059 ScGlobal::pCharClass->isNumeric( rStr.copy( nDateStart, nDateLen ) ) )
1061 // 6 digits: 2 each for day, month, year
1062 // 8 digits: 4 for year, 2 each for day and month
1063 // 5 or 7 digits: first field is shortened by 1
1065 bool bLongYear = ( nDateLen >= 7 );
1066 bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
1068 sal_uInt16 nFieldStart = nDateStart;
1069 for (sal_uInt16 nPos=0; nPos<3; nPos++)
1071 sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits
1072 if ( bLongYear && nPos == nYP )
1073 nFieldEnd += 2; // 2 extra digits for long year
1074 if ( bShortFirst && nPos == 0 )
1075 --nFieldEnd; // first field shortened?
1077 nStart[nPos] = nFieldStart;
1078 nEnd[nPos] = nFieldEnd;
1079 nFieldStart = nFieldEnd + 1;
1081 nFound = 3;
1085 if ( nFound >= 3 )
1087 using namespace ::com::sun::star;
1088 bool bSecondCal = false;
1089 sal_uInt16 nDay = (sal_uInt16) rStr.copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).toInt32();
1090 sal_uInt16 nYear = (sal_uInt16) rStr.copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).toInt32();
1091 OUString aMStr = rStr.copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1092 sal_Int16 nMonth = (sal_Int16) aMStr.toInt32();
1093 if (!nMonth)
1095 static const OUString aSeptCorrect( "SEPT" );
1096 static const OUString aSepShortened( "SEP" );
1097 uno::Sequence< i18n::CalendarItem2 > xMonths;
1098 sal_Int32 i, nMonthCount;
1099 // first test all month names from local international
1100 xMonths = rCalendar.getMonths();
1101 nMonthCount = xMonths.getLength();
1102 for (i=0; i<nMonthCount && !nMonth; i++)
1104 if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
1105 rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
1106 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1107 else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
1108 xMonths[i].AbbrevName ) &&
1109 rTransliteration.isEqual( aMStr, aSepShortened ) )
1110 { // correct English abbreviation is SEPT,
1111 // but data mostly contains SEP only
1112 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1115 // if none found, then test english month names
1116 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
1118 xMonths = pSecondCalendar->getMonths();
1119 nMonthCount = xMonths.getLength();
1120 for (i=0; i<nMonthCount && !nMonth; i++)
1122 if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
1123 pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
1125 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1126 bSecondCal = true;
1128 else if ( i == 8 && pSecondTransliteration->isEqual(
1129 aMStr, aSepShortened ) )
1130 { // correct English abbreviation is SEPT,
1131 // but data mostly contains SEP only
1132 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1133 bSecondCal = true;
1139 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1140 if ( nYear < 100 )
1141 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1143 CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1144 sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1145 if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
1147 --nMonth;
1148 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1149 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1150 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1151 sal_Int16 nHour, nMinute, nSecond, nMilli;
1152 // #i14974# The imported value should have no fractional value, so set the
1153 // time fields to zero (ICU calendar instance defaults to current date/time)
1154 nHour = nMinute = nSecond = nMilli = 0;
1155 if (nFound > 3)
1156 nHour = (sal_Int16) rStr.copy( nStart[3], nEnd[3]+1-nStart[3]).toInt32();
1157 if (nFound > 4)
1158 nMinute = (sal_Int16) rStr.copy( nStart[4], nEnd[4]+1-nStart[4]).toInt32();
1159 if (nFound > 5)
1160 nSecond = (sal_Int16) rStr.copy( nStart[5], nEnd[5]+1-nStart[5]).toInt32();
1161 if (nFound > 6)
1163 sal_Unicode cDec = '.';
1164 OUString aT( &cDec, 1);
1165 aT += rStr.copy( nStart[6], nEnd[6]+1-nStart[6]);
1166 rtl_math_ConversionStatus eStatus;
1167 double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
1168 if (eStatus == rtl_math_ConversionStatus_Ok)
1169 nMilli = (sal_Int16) (1000.0 * fV + 0.5);
1171 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1172 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1173 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1174 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
1175 if ( pCalendar->isValid() )
1177 double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
1178 pCalendar->getEpochStart();
1179 // #i14974# must use getLocalDateTime to get the same
1180 // date values as set above
1181 double fDays = pCalendar->getLocalDateTime();
1182 fDays -= fDiff;
1184 LanguageType eLatin, eCjk, eCtl;
1185 pDoc->GetLanguage( eLatin, eCjk, eCtl );
1186 LanguageType eDocLang = eLatin; //! which language for date formats?
1188 short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
1189 sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1190 // maybe there is a special format including seconds or milliseconds
1191 if (nFound > 5)
1192 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1194 ScAddress aPos(nCol,nRow,nTab);
1195 rDocImport.setNumericCell(aPos, fDays);
1196 pDoc->SetNumberFormat(aPos, nFormat);
1198 return bMultiLine; // success
1204 // Standard or date not determined -> SetString / EditCell
1205 if( rStr.indexOf( '\n' ) == -1 )
1207 ScSetStringParam aParam;
1208 aParam.mpNumFormatter = pFormatter;
1209 aParam.mbDetectNumberFormat = bDetectNumFormat;
1210 aParam.meSetTextNumFormat = ScSetStringParam::SpecialNumberOnly;
1211 aParam.mbHandleApostrophe = false;
1212 rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr, &aParam);
1214 else
1216 bMultiLine = true;
1217 ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
1218 rEngine.SetText(rStr);
1219 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
1221 return bMultiLine;
1225 static OUString lcl_GetFixed( const OUString& rLine, sal_Int32 nStart, sal_Int32 nNext,
1226 bool& rbIsQuoted, bool& rbOverflowCell )
1228 sal_Int32 nLen = rLine.getLength();
1229 if (nNext > nLen)
1230 nNext = nLen;
1231 if ( nNext <= nStart )
1232 return EMPTY_OUSTRING;
1234 const sal_Unicode* pStr = rLine.getStr();
1236 sal_Int32 nSpace = nNext;
1237 while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
1238 --nSpace;
1240 rbIsQuoted = (pStr[nStart] == '"' && pStr[nSpace-1] == '"');
1241 if (rbIsQuoted)
1243 bool bFits = (nSpace - nStart - 3 <= STRING_MAXLEN);
1244 OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1245 if (bFits)
1246 return rLine.copy(nStart+1, nSpace-nStart-2);
1247 else
1249 rbOverflowCell = true;
1250 return rLine.copy(nStart+1, STRING_MAXLEN);
1253 else
1255 bool bFits = (nSpace - nStart <= STRING_MAXLEN);
1256 OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1257 if (bFits)
1258 return rLine.copy(nStart, nSpace-nStart);
1259 else
1261 rbOverflowCell = true;
1262 return rLine.copy(nStart, STRING_MAXLEN);
1267 bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1269 if (!pExtOptions)
1270 return Text2Doc( rStrm );
1272 sal_uLong nOldPos = rStrm.Tell();
1273 rStrm.Seek( STREAM_SEEK_TO_END );
1274 ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1275 ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
1276 rStrm.Seek( nOldPos );
1277 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
1279 SCCOL nStartCol = aRange.aStart.Col();
1280 SCCOL nEndCol = aRange.aEnd.Col();
1281 SCROW nStartRow = aRange.aStart.Row();
1282 SCTAB nTab = aRange.aStart.Tab();
1284 bool bFixed = pExtOptions->IsFixedLen();
1285 const OUString& rSeps = pExtOptions->GetFieldSeps();
1286 const sal_Unicode* pSeps = rSeps.getStr();
1287 bool bMerge = pExtOptions->IsMergeSeps();
1288 sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
1289 const sal_Int32* pColStart = pExtOptions->GetColStart();
1290 const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
1291 long nSkipLines = pExtOptions->GetStartRow();
1293 LanguageType eDocLang = pExtOptions->GetLanguage();
1294 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eDocLang);
1295 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1297 // For date recognition
1298 ::utl::TransliterationWrapper aTransliteration(
1299 comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE );
1300 aTransliteration.loadModuleIfNeeded( eDocLang );
1301 CalendarWrapper aCalendar( comphelper::getProcessComponentContext() );
1302 aCalendar.loadDefaultCalendar(
1303 LanguageTag::convertToLocale( eDocLang ) );
1304 boost::scoped_ptr< ::utl::TransliterationWrapper > pEnglishTransliteration;
1305 boost::scoped_ptr< CalendarWrapper > pEnglishCalendar;
1306 if ( eDocLang != LANGUAGE_ENGLISH_US )
1308 pEnglishTransliteration.reset(new ::utl::TransliterationWrapper (
1309 comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE ));
1310 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1311 pEnglishCalendar.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
1312 pEnglishCalendar->loadDefaultCalendar(
1313 LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) );
1316 OUString aLine;
1317 OUString aCell;
1318 sal_uInt16 i;
1319 SCROW nRow = nStartRow;
1321 while(--nSkipLines>0)
1323 aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr); // content is ignored
1324 if ( rStrm.IsEof() )
1325 break;
1328 // Determine range for Undo.
1329 // TODO: we don't need this during import of a file to a new sheet or
1330 // document, could set bDetermineRange=false then.
1331 bool bDetermineRange = true;
1333 // Row heights don't need to be adjusted on the fly if EndPaste() is called
1334 // afterwards, which happens only if bDetermineRange. This variable also
1335 // survives the toggle of bDetermineRange down at the end of the do{} loop.
1336 bool bRangeIsDetermined = bDetermineRange;
1338 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1340 sal_uLong nOriginalStreamPos = rStrm.Tell();
1342 ScDocumentImport aDocImport(*pDoc);
1345 for( ;; )
1347 aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr);
1348 if ( rStrm.IsEof() && aLine.isEmpty() )
1349 break;
1351 EmbeddedNullTreatment( aLine);
1353 sal_Int32 nLineLen = aLine.getLength();
1354 SCCOL nCol = nStartCol;
1355 bool bMultiLine = false;
1356 if ( bFixed ) // Feste Satzlaenge
1358 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1359 // overflow if there is really data following to be put behind
1360 // the last column, which doesn't happen if info is
1361 // SC_COL_SKIP.
1362 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
1364 sal_uInt8 nFmt = pColFormat[i];
1365 if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen
1367 if (nCol > MAXCOL)
1368 bOverflowCol = true; // display warning on import
1369 else if (!bDetermineRange)
1371 sal_Int32 nStart = pColStart[i];
1372 sal_Int32 nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
1373 bool bIsQuoted = false;
1374 aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted, bOverflowCell );
1375 if (bIsQuoted && bQuotedAsText)
1376 nFmt = SC_COL_TEXT;
1378 bMultiLine |= lcl_PutString(
1379 aDocImport, nCol, nRow, nTab, aCell, nFmt,
1380 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1381 pEnglishTransliteration.get(), pEnglishCalendar.get());
1383 ++nCol;
1387 else // Nach Trennzeichen suchen
1389 SCCOL nSourceCol = 0;
1390 sal_uInt16 nInfoStart = 0;
1391 const sal_Unicode* p = aLine.getStr();
1392 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1393 // overflow if there is really data following to be put behind
1394 // the last column, which doesn't happen if info is
1395 // SC_COL_SKIP.
1396 while (*p && nCol <= MAXCOL+1)
1398 bool bIsQuoted = false;
1399 p = ScImportExport::ScanNextFieldFromString( p, aCell,
1400 cStr, pSeps, bMerge, bIsQuoted, bOverflowCell );
1402 sal_uInt8 nFmt = SC_COL_STANDARD;
1403 for ( i=nInfoStart; i<nInfoCount; i++ )
1405 if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert
1407 nFmt = pColFormat[i];
1408 nInfoStart = i + 1; // ColInfos sind in Reihenfolge
1409 break; // for
1412 if ( nFmt != SC_COL_SKIP )
1414 if (nCol > MAXCOL)
1415 bOverflowCol = true; // display warning on import
1416 else if (!bDetermineRange)
1418 if (bIsQuoted && bQuotedAsText)
1419 nFmt = SC_COL_TEXT;
1421 bMultiLine |= lcl_PutString(
1422 aDocImport, nCol, nRow, nTab, aCell, nFmt,
1423 &aNumFormatter, bDetectNumFormat, aTransliteration,
1424 aCalendar, pEnglishTransliteration.get(), pEnglishCalendar.get());
1426 ++nCol;
1429 ++nSourceCol;
1432 if (nEndCol < nCol)
1433 nEndCol = nCol; //! points to the next free or even MAXCOL+2
1435 if (!bDetermineRange)
1437 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1438 pDocSh->AdjustRowHeight( nRow, nRow, nTab);
1439 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1441 ++nRow;
1442 if ( nRow > MAXROW )
1444 bOverflowRow = true; // display warning on import
1445 break; // for
1448 // so far nRow/nEndCol pointed to the next free
1449 if (nRow > nStartRow)
1450 --nRow;
1451 if (nEndCol > nStartCol)
1452 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
1454 if (bDetermineRange)
1456 aRange.aEnd.SetCol( nEndCol );
1457 aRange.aEnd.SetRow( nRow );
1459 if ( !mbApi && nStartCol != nEndCol &&
1460 !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
1462 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
1463 if ( aBox.Execute() != RET_YES )
1465 return false;
1469 rStrm.Seek( nOriginalStreamPos );
1470 nRow = nStartRow;
1471 if (!StartPaste())
1473 EndPaste(false);
1474 return false;
1478 bDetermineRange = !bDetermineRange; // toggle
1479 } while (!bDetermineRange);
1480 aDocImport.finalize();
1482 xProgress.reset(); // make room for AdjustRowHeight progress
1483 if (bRangeIsDetermined)
1484 EndPaste(false);
1486 return true;
1490 void ScImportExport::EmbeddedNullTreatment( OUString & rStr )
1492 // A nasty workaround for data with embedded NULL characters. As long as we
1493 // can't handle them properly as cell content (things assume 0-terminated
1494 // strings at too many places) simply strip all NULL characters from raw
1495 // data. Excel does the same. See fdo#57841 for sample data.
1497 // The normal case is no embedded NULL, check first before de-/allocating
1498 // ustring stuff.
1499 sal_Unicode cNull = 0;
1500 if (rStr.indexOf( cNull) >= 0)
1502 rStr = rStr.replaceAll( OUString( &cNull, 1), OUString());
1507 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
1508 OUString& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted,
1509 bool& rbOverflowCell )
1511 rbIsQuoted = false;
1512 rField = "";
1513 const sal_Unicode cBlank = ' ';
1514 if (!ScGlobal::UnicodeStrChr( pSeps, cBlank))
1516 // Cope with broken generators that put leading blanks before a quoted
1517 // field, like "field1", "field2", "..."
1518 // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1519 const sal_Unicode* pb = p;
1520 while (*pb == cBlank)
1521 ++pb;
1522 if (*pb == cStr)
1523 p = pb;
1525 if ( *p == cStr ) // String in quotes
1527 rbIsQuoted = true;
1528 const sal_Unicode* p1;
1529 p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DQM_ESCAPE, rbOverflowCell );
1530 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1531 p++;
1532 // Append remaining unquoted and undelimited data (dirty, dirty) to
1533 // this field.
1534 if (p > p1)
1536 if (!lcl_appendLineData( rField, p1, p))
1537 rbOverflowCell = true;
1539 if( *p )
1540 p++;
1542 else // up to delimiter
1544 const sal_Unicode* p0 = p;
1545 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1546 p++;
1547 if (!lcl_appendLineData( rField, p0, p))
1548 rbOverflowCell = true;
1549 if( *p )
1550 p++;
1552 if ( bMergeSeps ) // skip following delimiters
1554 while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
1555 p++;
1557 return p;
1560 namespace {
1563 * Check if a given string has any line break characters or separators.
1565 * @param rStr string to inspect.
1566 * @param cSep separator character.
1568 bool hasLineBreaksOrSeps( const OUString& rStr, sal_Unicode cSep )
1570 const sal_Unicode* p = rStr.getStr();
1571 for (sal_Int32 i = 0, n = rStr.getLength(); i < n; ++i, ++p)
1573 sal_Unicode c = *p;
1574 if (c == cSep)
1575 // separator found.
1576 return true;
1578 switch (c)
1580 case '\n':
1581 case '\r':
1582 // line break found.
1583 return true;
1584 default:
1588 return false;
1593 bool ScImportExport::Doc2Text( SvStream& rStrm )
1595 SCCOL nCol;
1596 SCROW nRow;
1597 SCCOL nStartCol = aRange.aStart.Col();
1598 SCROW nStartRow = aRange.aStart.Row();
1599 SCTAB nStartTab = aRange.aStart.Tab();
1600 SCCOL nEndCol = aRange.aEnd.Col();
1601 SCROW nEndRow = aRange.aEnd.Row();
1602 SCTAB nEndTab = aRange.aEnd.Tab();
1604 if (!pDoc->GetClipParam().isMultiRange() && nStartTab == nEndTab)
1605 pDoc->ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow );
1607 OUString aCell;
1609 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1611 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1613 if (bIncludeFiltered || !pDoc->RowFiltered( nRow, nStartTab ))
1615 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1617 CellType eType;
1618 pDoc->GetCellType( nCol, nRow, nStartTab, eType );
1619 switch (eType)
1621 case CELLTYPE_FORMULA:
1623 if (bFormulas)
1625 pDoc->GetFormula( nCol, nRow, nStartTab, aCell );
1626 if( aCell.indexOf( cSep ) != -1 )
1627 lcl_WriteString( rStrm, aCell, cStr, cStr );
1628 else
1629 lcl_WriteSimpleString( rStrm, aCell );
1631 else
1633 aCell = pDoc->GetString(nCol, nRow, nStartTab);
1635 bool bMultiLineText = ( aCell.indexOf( '\n' ) != -1 );
1636 if( bMultiLineText )
1638 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1639 aCell = aCell.replaceAll( "\n", " " );
1640 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1641 aCell = convertLineEnd(aCell, GetSystemLineEnd());
1644 if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1645 aCell = aCell.replaceAll( OUString(cSep), OUString(mExportTextOptions.mcSeparatorConvertTo) );
1647 if( mExportTextOptions.mbAddQuotes && ( aCell.indexOf( cSep ) != -1 ) )
1648 lcl_WriteString( rStrm, aCell, cStr, cStr );
1649 else
1650 lcl_WriteSimpleString( rStrm, aCell );
1653 break;
1654 case CELLTYPE_VALUE:
1656 aCell = pDoc->GetString(nCol, nRow, nStartTab);
1657 lcl_WriteSimpleString( rStrm, aCell );
1659 break;
1660 case CELLTYPE_NONE:
1661 break;
1662 default:
1664 aCell = pDoc->GetString(nCol, nRow, nStartTab);
1666 bool bMultiLineText = ( aCell.indexOf( '\n' ) != -1 );
1667 if( bMultiLineText )
1669 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1670 aCell = aCell.replaceAll( "\n", " " );
1671 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1672 aCell = convertLineEnd(aCell, GetSystemLineEnd());
1675 if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1676 aCell = aCell.replaceAll( OUString(cSep), OUString(mExportTextOptions.mcSeparatorConvertTo) );
1678 if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCell, cSep) )
1679 lcl_WriteString( rStrm, aCell, cStr, cStr );
1680 else
1681 lcl_WriteSimpleString( rStrm, aCell );
1684 if( nCol < nEndCol )
1685 lcl_WriteSimpleString( rStrm, OUString(cSep) );
1687 WriteUnicodeOrByteEndl( rStrm );
1688 if( rStrm.GetError() != SVSTREAM_OK )
1689 break;
1690 if( nSizeLimit && rStrm.Tell() > nSizeLimit )
1691 break;
1695 return rStrm.GetError() == SVSTREAM_OK;
1699 bool ScImportExport::Sylk2Doc( SvStream& rStrm )
1701 bool bOk = true;
1702 bool bMyDoc = false;
1703 SylkVersion eVersion = SYLK_OTHER;
1705 // US-English separators for StringToDouble
1706 sal_Unicode cDecSep = '.';
1707 sal_Unicode cGrpSep = ',';
1709 SCCOL nStartCol = aRange.aStart.Col();
1710 SCROW nStartRow = aRange.aStart.Row();
1711 SCCOL nEndCol = aRange.aEnd.Col();
1712 SCROW nEndRow = aRange.aEnd.Row();
1713 sal_uLong nOldPos = rStrm.Tell();
1714 bool bData = !bSingle;
1715 ::std::vector< sal_uInt32 > aFormats;
1717 if( !bSingle)
1718 bOk = StartPaste();
1720 while( bOk )
1722 OUString aLine;
1723 OUString aText;
1724 OString aByteLine;
1725 SCCOL nCol = nStartCol;
1726 SCROW nRow = nStartRow;
1727 SCCOL nRefCol = 1;
1728 SCROW nRefRow = 1;
1729 rStrm.Seek( nOldPos );
1730 for( ;; )
1732 //! allow unicode
1733 rStrm.ReadLine( aByteLine );
1734 aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
1735 if( rStrm.IsEof() )
1736 break;
1737 const sal_Unicode* p = aLine.getStr();
1738 sal_Unicode cTag = *p++;
1739 if( cTag == 'C' ) // Content
1741 if( *p++ != ';' )
1742 return false;
1743 while( *p )
1745 sal_Unicode ch = *p++;
1746 ch = ScGlobal::ToUpperAlpha( ch );
1747 switch( ch )
1749 case 'X':
1750 nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1751 break;
1752 case 'Y':
1753 nRow = OUString(p).toInt32() + nStartRow - 1;
1754 break;
1755 case 'C':
1756 nRefCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1757 break;
1758 case 'R':
1759 nRefRow = OUString(p).toInt32() + nStartRow - 1;
1760 break;
1761 case 'K':
1763 if( !bSingle &&
1764 ( nCol < nStartCol || nCol > nEndCol
1765 || nRow < nStartRow || nRow > nEndRow
1766 || nCol > MAXCOL || nRow > MAXROW ) )
1767 break;
1768 if( !bData )
1770 if( nRow > nEndRow )
1771 nEndRow = nRow;
1772 if( nCol > nEndCol )
1773 nEndCol = nCol;
1774 break;
1776 bool bText;
1777 if( *p == '"' )
1779 bText = true;
1780 aText = "";
1781 p = lcl_ScanSylkString( p, aText, eVersion);
1783 else
1784 bText = false;
1785 const sal_Unicode* q = p;
1786 while( *q && *q != ';' )
1787 q++;
1788 if ( !(*q == ';' && *(q+1) == 'I') )
1789 { // don't ignore value
1790 if( bText )
1792 pDoc->EnsureTable(aRange.aStart.Tab());
1793 pDoc->SetTextCell(
1794 ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
1796 else
1798 double fVal = rtl_math_uStringToDouble( p,
1799 aLine.getStr() + aLine.getLength(),
1800 cDecSep, cGrpSep, NULL, NULL );
1801 pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
1805 break;
1806 case 'E':
1807 case 'M':
1809 if ( ch == 'M' )
1811 if ( nRefCol < nCol )
1812 nRefCol = nCol;
1813 if ( nRefRow < nRow )
1814 nRefRow = nRow;
1815 if ( !bData )
1817 if( nRefRow > nEndRow )
1818 nEndRow = nRefRow;
1819 if( nRefCol > nEndCol )
1820 nEndCol = nRefCol;
1823 if( !bMyDoc || !bData )
1824 break;
1825 aText = "=";
1826 p = lcl_ScanSylkFormula( p, aText, eVersion);
1827 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
1828 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1829 * end it probably should be GRAM_ODFF_R1C1, since
1830 * R1C1 is what Excel writes in SYLK. */
1831 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
1832 ScCompiler aComp( pDoc, aPos);
1833 aComp.SetGrammar(eGrammar);
1834 ScTokenArray* pCode = aComp.CompileString( aText );
1835 if ( ch == 'M' )
1837 ScMarkData aMark;
1838 aMark.SelectTable( aPos.Tab(), true );
1839 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1840 nRefRow, aMark, EMPTY_OUSTRING, pCode );
1842 else
1844 ScFormulaCell* pFCell = new ScFormulaCell(
1845 pDoc, aPos, *pCode, eGrammar, MM_NONE);
1846 pDoc->SetFormulaCell(aPos, pFCell);
1848 delete pCode; // ctor/InsertMatrixFormula did copy TokenArray
1850 break;
1852 while( *p && *p != ';' )
1853 p++;
1854 if( *p )
1855 p++;
1858 else if( cTag == 'F' ) // Format
1860 if( *p++ != ';' )
1861 return false;
1862 sal_Int32 nFormat = -1;
1863 while( *p )
1865 sal_Unicode ch = *p++;
1866 ch = ScGlobal::ToUpperAlpha( ch );
1867 switch( ch )
1869 case 'X':
1870 nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1871 break;
1872 case 'Y':
1873 nRow = OUString(p).toInt32() + nStartRow - 1;
1874 break;
1875 case 'P' :
1876 if ( bData )
1878 // F;P<n> sets format code of P;P<code> at
1879 // current position, or at ;X;Y if specified.
1880 // Note that ;X;Y may appear after ;P
1881 const sal_Unicode* p0 = p;
1882 while( *p && *p != ';' )
1883 p++;
1884 OUString aNumber(p0, p - p0);
1885 nFormat = aNumber.toInt32();
1887 break;
1889 while( *p && *p != ';' )
1890 p++;
1891 if( *p )
1892 p++;
1894 if ( !bData )
1896 if( nRow > nEndRow )
1897 nEndRow = nRow;
1898 if( nCol > nEndCol )
1899 nEndCol = nCol;
1901 if ( 0 <= nFormat && nFormat < (sal_Int32)aFormats.size() )
1903 sal_uInt32 nKey = aFormats[nFormat];
1904 pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
1905 SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
1908 else if( cTag == 'P' )
1910 if ( bData && *p == ';' && *(p+1) == 'P' )
1912 OUString aCode( p+2 );
1913 // unescape doubled semicolons
1914 aCode = aCode.replaceAll(";;", ";");
1915 // get rid of Xcl escape characters
1916 aCode = aCode.replaceAll(OUString(static_cast<sal_Unicode>(0x1b)), OUString());
1917 sal_Int32 nCheckPos;
1918 short nType;
1919 sal_uInt32 nKey;
1920 pDoc->GetFormatTable()->PutandConvertEntry( aCode, nCheckPos, nType, nKey,
1921 LANGUAGE_ENGLISH_US, ScGlobal::eLnge );
1922 if ( nCheckPos )
1923 nKey = 0;
1924 aFormats.push_back( nKey );
1927 else if( cTag == 'I' && *p == 'D' )
1929 aLine = aLine.copy(4);
1930 if (aLine == "CALCOOO32")
1931 eVersion = SYLK_OOO32;
1932 else if (aLine == "SCALC3")
1933 eVersion = SYLK_SCALC3;
1934 bMyDoc = (eVersion <= SYLK_OWN);
1936 else if( cTag == 'E' ) // Ende
1937 break;
1939 if( !bData )
1941 aRange.aEnd.SetCol( nEndCol );
1942 aRange.aEnd.SetRow( nEndRow );
1943 bOk = StartPaste();
1944 bData = true;
1946 else
1947 break;
1950 EndPaste();
1951 return bOk;
1955 bool ScImportExport::Doc2Sylk( SvStream& rStrm )
1957 SCCOL nCol;
1958 SCROW nRow;
1959 SCCOL nStartCol = aRange.aStart.Col();
1960 SCROW nStartRow = aRange.aStart.Row();
1961 SCCOL nEndCol = aRange.aEnd.Col();
1962 SCROW nEndRow = aRange.aEnd.Row();
1963 OUString aCellStr;
1964 OUString aValStr;
1965 lcl_WriteSimpleString( rStrm, OUString("ID;PCALCOOO32") );
1966 WriteUnicodeOrByteEndl( rStrm );
1968 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1970 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1972 OUString aBufStr;
1973 double nVal;
1974 bool bForm = false;
1975 SCROW r = nRow - nStartRow + 1;
1976 SCCOL c = nCol - nStartCol + 1;
1977 ScRefCellValue aCell;
1978 aCell.assign(*pDoc, ScAddress(nCol, nRow, aRange.aStart.Tab()));
1979 CellType eType = aCell.meType;
1980 switch( eType )
1982 case CELLTYPE_FORMULA:
1983 bForm = bFormulas;
1984 if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1985 goto hasvalue;
1986 else
1987 goto hasstring;
1989 case CELLTYPE_VALUE:
1990 hasvalue:
1991 pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
1993 aValStr = ::rtl::math::doubleToUString( nVal,
1994 rtl_math_StringFormat_Automatic,
1995 rtl_math_DecimalPlaces_Max, '.', true );
1997 aBufStr = "C;X";
1998 aBufStr += OUString::number( c );
1999 aBufStr += ";Y";
2000 aBufStr += OUString::number( r );
2001 aBufStr += ";K";
2002 aBufStr += aValStr;
2003 lcl_WriteSimpleString( rStrm, aBufStr );
2004 goto checkformula;
2006 case CELLTYPE_STRING:
2007 case CELLTYPE_EDIT:
2008 hasstring:
2009 aCellStr = pDoc->GetString(nCol, nRow, aRange.aStart.Tab());
2010 aCellStr = aCellStr.replaceAll( OUString('\n'), OUString(SYLK_LF) );
2012 aBufStr = "C;X";
2013 aBufStr += OUString::number( c );
2014 aBufStr += ";Y";
2015 aBufStr += OUString::number( r );
2016 aBufStr += ";K";
2017 lcl_WriteSimpleString( rStrm, aBufStr );
2018 lcl_WriteString( rStrm, aCellStr, '"', ';' );
2020 checkformula:
2021 if( bForm )
2023 const ScFormulaCell* pFCell = aCell.mpFormula;
2024 switch ( pFCell->GetMatrixFlag() )
2026 case MM_REFERENCE :
2027 aCellStr = "";
2028 break;
2029 default:
2030 OUString aOUCellStr;
2031 pFCell->GetFormula( aOUCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
2032 aCellStr = aOUCellStr;
2033 /* FIXME: do we want GRAM_ODFF_A1 instead? At
2034 * the end it probably should be
2035 * GRAM_ODFF_R1C1, since R1C1 is what Excel
2036 * writes in SYLK. */
2038 if ( pFCell->GetMatrixFlag() != MM_NONE &&
2039 aCellStr.startsWith("{") &&
2040 aCellStr.endsWith("}") )
2041 { // cut off matrix {} characters
2042 aCellStr = aCellStr.copy(1, aCellStr.getLength()-2);
2044 if ( aCellStr[0] == '=' )
2045 aCellStr = aCellStr.copy(1);
2046 OUString aPrefix;
2047 switch ( pFCell->GetMatrixFlag() )
2049 case MM_FORMULA :
2050 { // diff expression with 'M' M$-extension
2051 SCCOL nC;
2052 SCROW nR;
2053 pFCell->GetMatColsRows( nC, nR );
2054 nC += c - 1;
2055 nR += r - 1;
2056 aPrefix = ";R";
2057 aPrefix += OUString::number( nR );
2058 aPrefix += ";C";
2059 aPrefix += OUString::number( nC );
2060 aPrefix += ";M";
2062 break;
2063 case MM_REFERENCE :
2064 { // diff expression with 'I' M$-extension
2065 ScAddress aPos;
2066 pFCell->GetMatrixOrigin( aPos );
2067 aPrefix = ";I;R";
2068 aPrefix += OUString::number( aPos.Row() - nStartRow + 1 );
2069 aPrefix += ";C";
2070 aPrefix += OUString::number( aPos.Col() - nStartCol + 1 );
2072 break;
2073 default:
2074 // formula Expression
2075 aPrefix = ";E";
2077 lcl_WriteSimpleString( rStrm, aPrefix );
2078 if ( !aCellStr.isEmpty() )
2079 lcl_WriteString( rStrm, aCellStr, 0, ';' );
2081 WriteUnicodeOrByteEndl( rStrm );
2082 break;
2084 default:
2086 // added to avoid warnings
2091 lcl_WriteSimpleString( rStrm, OUString( 'E' ) );
2092 WriteUnicodeOrByteEndl( rStrm );
2093 return rStrm.GetError() == SVSTREAM_OK;
2097 bool ScImportExport::Doc2HTML( SvStream& rStrm, const OUString& rBaseURL )
2099 // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
2100 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
2101 aStreamPath, aNonConvertibleChars );
2102 return rStrm.GetError() == SVSTREAM_OK;
2105 bool ScImportExport::Doc2RTF( SvStream& rStrm )
2107 // rtl_TextEncoding is ignored in ScExportRTF
2108 ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
2109 return rStrm.GetError() == SVSTREAM_OK;
2113 bool ScImportExport::Doc2Dif( SvStream& rStrm )
2115 // for DIF in the clipboard, IBM_850 is always used
2116 ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
2117 return true;
2121 bool ScImportExport::Dif2Doc( SvStream& rStrm )
2123 SCTAB nTab = aRange.aStart.Tab();
2124 ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
2125 pImportDoc->InitUndo( pDoc, nTab, nTab );
2127 // for DIF in the clipboard, IBM_850 is always used
2128 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
2130 SCCOL nEndCol;
2131 SCROW nEndRow;
2132 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
2133 // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2134 if ( nEndCol < aRange.aStart.Col() )
2135 nEndCol = aRange.aStart.Col();
2136 if ( nEndRow < aRange.aStart.Row() )
2137 nEndRow = aRange.aStart.Row();
2138 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
2140 bool bOk = StartPaste();
2141 if (bOk)
2143 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2144 pDoc->DeleteAreaTab( aRange, nFlags );
2145 pImportDoc->CopyToDocument( aRange, nFlags, false, pDoc );
2146 EndPaste();
2149 delete pImportDoc;
2151 return bOk;
2155 bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
2157 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
2158 if (!pImp)
2159 return false;
2160 pImp->Read( rStrm, rBaseURL );
2161 aRange = pImp->GetRange();
2163 bool bOk = StartPaste();
2164 if (bOk)
2166 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2167 pDoc->DeleteAreaTab( aRange, nFlags );
2168 pImp->WriteToDocument();
2169 EndPaste();
2171 delete pImp;
2172 return bOk;
2176 bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
2178 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, true);
2179 if (!pImp)
2180 return false;
2181 pImp->Read( rStrm, rBaseURL );
2182 aRange = pImp->GetRange();
2184 bool bOk = StartPaste();
2185 if (bOk)
2187 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2188 // a Draw Layer but no Draw View -> create Draw Layer and View here
2189 if (pDocSh)
2190 pDocSh->MakeDrawLayer();
2192 sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2193 pDoc->DeleteAreaTab( aRange, nFlags );
2195 if (pExtOptions)
2197 // Pick up import options if available.
2198 LanguageType eLang = pExtOptions->GetLanguage();
2199 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
2200 bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
2201 pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
2203 else
2204 // Regular import, with no options.
2205 pImp->WriteToDocument();
2207 EndPaste();
2209 delete pImp;
2210 return bOk;
2213 #ifndef DISABLE_DYNLOADING
2215 #define RETURN_ERROR { return eERR_INTERN; }
2216 class ScFormatFilterMissing : public ScFormatFilterPlugin {
2217 public:
2218 ScFormatFilterMissing()
2220 OSL_FAIL("Missing file filters");
2222 virtual ~ScFormatFilterMissing() {}
2223 virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, rtl_TextEncoding ) RETURN_ERROR
2224 virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
2225 virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
2226 virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
2227 virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
2228 const rtl_TextEncoding, sal_uInt32 ) RETURN_ERROR
2229 virtual FltError ScImportRTF( SvStream&, const OUString&, ScDocument*, ScRange& ) RETURN_ERROR
2230 virtual FltError ScImportHTML( SvStream&, const OUString&, ScDocument*, ScRange&, double, bool, SvNumberFormatter*, bool ) RETURN_ERROR
2232 virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
2233 virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const OUString&, const ScRange&, bool ) { return NULL; }
2234 virtual OUString GetHTMLRangeNameList( ScDocument*, const OUString& ) { return OUString(); }
2236 virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, rtl_TextEncoding ) RETURN_ERROR
2237 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const rtl_TextEncoding, sal_uInt32 ) RETURN_ERROR
2238 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const rtl_TextEncoding, sal_uInt32 ) RETURN_ERROR
2239 virtual FltError ScExportHTML( SvStream&, const OUString&, ScDocument*, const ScRange&, const rtl_TextEncoding, bool,
2240 const OUString&, OUString& ) RETURN_ERROR
2241 virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const rtl_TextEncoding ) RETURN_ERROR
2243 virtual ScOrcusFilters* GetOrcusFilters() { return NULL; }
2246 extern "C" { static void SAL_CALL thisModule() {} }
2248 #else
2250 extern "C" {
2251 ScFormatFilterPlugin* ScFilterCreate();
2254 #endif
2256 typedef ScFormatFilterPlugin * (*FilterFn)(void);
2257 ScFormatFilterPlugin &ScFormatFilter::Get()
2259 static ScFormatFilterPlugin *plugin;
2261 if (plugin != NULL)
2262 return *plugin;
2264 #ifndef DISABLE_DYNLOADING
2265 OUString sFilterLib(SVLIBRARY("scfilt"));
2266 static ::osl::Module aModule;
2267 bool bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
2268 if (!bLoaded)
2269 bLoaded = aModule.load(sFilterLib);
2270 if (bLoaded)
2272 oslGenericFunction fn = aModule.getFunctionSymbol( OUString( "ScFilterCreate" ) );
2273 if (fn != NULL)
2274 plugin = reinterpret_cast<FilterFn>(fn)();
2276 if (plugin == NULL)
2277 plugin = new ScFormatFilterMissing();
2278 #else
2279 plugin = ScFilterCreate();
2280 #endif
2282 return *plugin;
2285 // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2286 // array.
2287 static inline const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
2288 sal_Unicode c )
2290 while (*pStr)
2292 if (*pStr == c)
2293 return pStr;
2294 ++pStr;
2296 return 0;
2299 OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
2300 const OUString& rFieldSeparators, sal_Unicode cFieldQuote )
2302 OUString aStr;
2303 rStream.ReadUniOrByteStringLine(aStr, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
2305 if (bEmbeddedLineBreak)
2307 const sal_Unicode* pSeps = rFieldSeparators.getStr();
2309 QuoteType eQuoteState = FIELDEND_QUOTE;
2310 bool bFieldStart = true;
2312 sal_Int32 nLastOffset = 0;
2313 sal_Int32 nQuotes = 0;
2314 while (!rStream.IsEof() && aStr.getLength() < nArbitraryLineLengthLimit)
2316 const sal_Unicode *p, *pStart;
2317 p = pStart = aStr.getStr();
2318 p += nLastOffset;
2319 while (*p)
2321 if (nQuotes)
2323 if (*p == cFieldQuote)
2325 if (bFieldStart)
2327 ++nQuotes;
2328 bFieldStart = false;
2329 eQuoteState = FIELDSTART_QUOTE;
2331 // Do not detect a FIELDSTART_QUOTE if not in
2332 // bFieldStart mode, in which case for unquoted content
2333 // we are in FIELDEND_QUOTE state.
2334 else if (eQuoteState != FIELDEND_QUOTE)
2336 eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote);
2337 // DONTKNOW_QUOTE is an embedded unescaped quote we
2338 // don't count for pairing.
2339 if (eQuoteState != DONTKNOW_QUOTE)
2340 ++nQuotes;
2343 else if (eQuoteState == FIELDEND_QUOTE)
2345 if (bFieldStart)
2346 // If blank is a separator it starts a field, if it
2347 // is not and thus maybe leading before quote we
2348 // are still at start of field regarding quotes.
2349 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
2350 else
2351 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2354 else
2356 if (*p == cFieldQuote && bFieldStart)
2358 nQuotes = 1;
2359 eQuoteState = FIELDSTART_QUOTE;
2360 bFieldStart = false;
2362 else if (eQuoteState == FIELDEND_QUOTE)
2364 // This also skips leading blanks at beginning of line
2365 // if followed by a quote. It's debatable whether we
2366 // actually want that or not, but congruent with what
2367 // ScanNextFieldFromString() does.
2368 if (bFieldStart)
2369 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
2370 else
2371 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2374 // A quote character inside a field content does not start
2375 // a quote.
2376 ++p;
2379 if (nQuotes % 2 == 0)
2380 // We still have a (theoretical?) problem here if due to
2381 // nArbitraryLineLengthLimit we split a string right between a
2382 // doubled quote pair.
2383 break;
2384 else
2386 nLastOffset = aStr.getLength();
2387 OUString aNext;
2388 rStream.ReadUniOrByteStringLine(aNext, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
2389 aStr += OUString('\n');
2390 aStr += aNext;
2394 return aStr;
2397 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */