1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
29 #include "scerrors.hxx"
31 #include "undoblk.hxx"
32 #include "rangenam.hxx"
33 #include "viewdata.hxx"
34 #include "tabvwsh.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"
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
64 static const sal_Int32 nArbitraryLineLengthLimit
= 2 * MAXCOLCOUNT
* STRING_MAXLEN
;
68 const char SYLK_LF
[] = "\x1b :";
69 const char DOUBLE_SEMICOLON
[] = ";;";
70 const char DOUBLE_DOUBLEQUOTE
[] = "\"\"";
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()
97 // Insert am Punkt ohne Bereichschecks
100 ScImportExport::ScImportExport( ScDocument
* p
, const ScAddress
& rPt
)
101 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
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()
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
),
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()
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()
147 SCTAB nTab
= ScDocShell::GetCurTab();
148 aRange
.aStart
.SetTab( nTab
);
149 OUString
aPos( rPos
);
150 // Benannter Bereich?
151 ScRangeName
* pRange
= pDoc
->GetRangeName();
154 const ScRangeData
* pData
= pRange
->findByUpperName(ScGlobal::pCharClass
->uppercase(aPos
));
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();
165 if( aRange
.Parse( aPos
, pDoc
, eConv
) & SCA_VALID
)
168 else if( aRange
.aStart
.Parse( aPos
, pDoc
, eConv
) & SCA_VALID
)
169 aRange
.aEnd
= aRange
.aStart
;
175 ScImportExport::~ScImportExport()
182 void ScImportExport::SetExtOptions( const ScAsciiOptions
& rOpt
)
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()
216 ScEditableTester
aTester( pDoc
, aRange
);
217 if ( !aTester
.IsEditable() )
219 InfoBox
aInfoBox(Application::GetDefDialogParent(),
220 ScGlobal::GetRscString( aTester
.GetMessageId() ) );
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
);
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
));
256 pDocSh
->PostPaint( aRange
, PAINT_GRID
); // AdjustRowHeight paintet evtl. selber
257 pDocSh
->SetDocumentModified();
259 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
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" );
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
) );
292 bool ScImportExport::ImportString( const OUString
& rText
, sal_uLong nFmt
)
296 // formats supporting unicode
299 ScImportStringStream
aStrm( rText
);
300 return ImportStream( aStrm
, OUString(), nFmt
);
301 // ImportStream must handle RTL_TEXTENCODING_UNICODE
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();
324 bool bOk
= ExportByteString( aTmp
, eEnc
, nFmt
);
325 rText
= OStringToOUString( aTmp
, eEnc
);
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() );
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();
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();
378 bool ScImportExport::ImportStream( SvStream
& rStrm
, const OUString
& rBaseURL
, sal_uLong nFmt
)
380 if( nFmt
== FORMAT_STRING
)
382 if( ExtText2Doc( rStrm
) ) // pExtOptions auswerten
385 if( nFmt
== SOT_FORMATSTR_ID_SYLK
)
387 if( Sylk2Doc( rStrm
) )
390 if( nFmt
== SOT_FORMATSTR_ID_DIF
)
392 if( Dif2Doc( rStrm
) )
395 if( nFmt
== FORMAT_RTF
)
397 if( RTF2Doc( rStrm
, rBaseURL
) )
400 if( nFmt
== SOT_FORMATSTR_ID_LINK
)
401 return true; // Link-Import?
402 if ( nFmt
== SOT_FORMATSTR_ID_HTML
)
404 if( HTML2Doc( rStrm
, rBaseURL
) )
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
) )
419 bool ScImportExport::ExportStream( SvStream
& rStrm
, const OUString
& rBaseURL
, sal_uLong nFmt
)
421 if( nFmt
== FORMAT_STRING
)
423 if( Doc2Text( rStrm
) )
426 if( nFmt
== SOT_FORMATSTR_ID_SYLK
)
428 if( Doc2Sylk( rStrm
) )
431 if( nFmt
== SOT_FORMATSTR_ID_DIF
)
433 if( Doc2Dif( rStrm
) )
436 if( nFmt
== SOT_FORMATSTR_ID_LINK
&& !bAll
)
439 if ( pDoc
->IsClipboard() )
440 aDocName
= ScGlobal::GetClipDocName();
443 SfxObjectShell
* pShell
= pDoc
->GetDocumentShell();
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.
453 sal_uInt16 nFlags
= SCA_VALID
| SCA_TAB_3D
;
455 aRefName
= aRange
.aStart
.Format(nFlags
, pDoc
, formula::FormulaGrammar::CONV_OOO
);
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
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);
475 rStrm
<< sal_Char(0);
476 return rStrm
.GetError() == SVSTREAM_OK
;
479 if( nFmt
== SOT_FORMATSTR_ID_HTML
)
481 if( Doc2HTML( rStrm
, rBaseURL
) )
484 if( nFmt
== FORMAT_RTF
)
486 if( Doc2RTF( rStrm
) )
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
) );
503 const sal_Unicode
* p
= rString
.getStr();
504 const sal_Unicode
* const pStop
= p
+ rString
.getLength();
511 rStrm
<< sal_Unicode(0);
515 OString
aByteStr(OUStringToOString(rString
, eEnc
));
516 rStrm
<< aByteStr
.getStr();
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() )
531 rStrm
<< sal_Unicode('\r');
534 rStrm
<< sal_Unicode('\n');
537 rStrm
<< sal_Unicode('\r') << sal_Unicode('\n');
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.
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
)
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
582 Precondition: *p is a quote.
585 Quote characters encountered so far.
586 Odd (after opening quote) means either no embedded quotes or only quote
588 Even means either not in a quoted field or already one quote
589 encountered, the first of a pair.
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)
609 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
610 return FIELDSTART_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
) );
633 rField
+= OUString( p1
, STRING_MAXLEN
- rField
.getLength() );
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
657 const sal_Unicode
* p0
= p
;
666 // break or continue for loop
667 if (eMode
== DQM_ESCAPE
)
669 if (lcl_isFieldEndQuote( p
-1, pSeps
) == FIELDEND_QUOTE
)
677 // doubled quote char
682 p
++; // both for us (not breaking for-loop)
685 p
++; // one for us (breaking for-loop)
686 bCont
= true; // and more
692 if (!lcl_appendLineData( rString
, p0
, p
-1))
693 rbOverflowCell
= true;
695 p0
= ++p
; // text of next part starts here
698 // positioned on next opening quote
701 if ( eMode
== DQM_ESCAPE
|| eMode
== DQM_SEPARATE
)
709 if (!lcl_appendLineData( rString
, p0
, ((eMode
!= DQM_KEEP_ALL
&& (*p
|| *(p
-1) == cStr
)) ? p
-1 : p
)))
710 rbOverflowCell
= true;
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(';') );
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;
739 if (eVersion
>= SYLK_OOO32
)
745 p
+= 2; // escaped ';'
759 else if (*(p
+1) == ';')
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
);
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
)
788 rString
+= OUString( pStart
, sal::static_int_cast
<sal_Int32
>( p
- pStart
));
789 lcl_UnescapeSylk( rString
, eVersion
);
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;
804 // May be a quoted expression or just a string constant expression
813 break; // closing '"', had no ';' yet
817 bQuoted
= true; // ';' within quoted expression
824 p
= lcl_ScanSylkString( p
, rString
, eVersion
);
827 while (*p
&& *p
!= ';')
829 rString
+= OUString( pStart
, sal::static_int_cast
<sal_Int32
>( p
- pStart
));
835 static void lcl_DoubleEscapeChar( OUString
& rString
, sal_Unicode cStr
)
838 while( ( n
= rString
.indexOf( cStr
, n
) ) != -1 )
840 rString
= rString
.replaceAt( n
, 0, OUString(cStr
) );
845 static void lcl_WriteString( SvStream
& rStrm
, OUString
& rString
, sal_Unicode cQuote
, sal_Unicode cEsc
)
848 lcl_DoubleEscapeChar( rString
, cEsc
);
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
)
870 sal_Unicode pSeps
[2];
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
;
888 SCROW nRow
= nStartRow
;
889 rStrm
.Seek( nOldPos
);
892 rStrm
.ReadUniOrByteStringLine( aLine
, rStrm
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
895 SCCOL nCol
= nStartCol
;
896 const sal_Unicode
* p
= aLine
.getStr();
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
)
909 if (!lcl_appendLineData( aCell
, q
, p
))
910 bOverflowCell
= true; // display warning on import
915 if (ValidCol(nCol
) && ValidRow(nRow
) )
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
928 bOverflowRow
= true; // display warning on import
930 bOverflowCol
= true; // display warning on import
939 aRange
.aEnd
.SetCol( nEndCol
);
940 aRange
.aEnd
.SetRow( nEndRow
);
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
) )
968 if ( nColFormat
== SC_COL_TEXT
)
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());
991 rDocImport
.setStringCell(ScAddress(nCol
, nRow
, nTab
), rStr
);
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
);
1003 if ( pDocFormatter
->IsNumberFormat( rStr
, nEnglish
, fVal
) )
1005 // Zahlformat wird nicht auf englisch gesetzt
1006 rDocImport
.setNumericCell( ScAddress( nCol
, nRow
, nTab
), fVal
);
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;
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
))
1042 nStart
[nFound
] = nPos
;
1045 nEnd
[nFound
-1] = nPos
;
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;
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();
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 );
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 );
1139 SvNumberFormatter
* pDocFormatter
= pDoc
->GetFormatTable();
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
)
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;
1156 nHour
= (sal_Int16
) rStr
.copy( nStart
[3], nEnd
[3]+1-nStart
[3]).toInt32();
1158 nMinute
= (sal_Int16
) rStr
.copy( nStart
[4], nEnd
[4]+1-nStart
[4]).toInt32();
1160 nSecond
= (sal_Int16
) rStr
.copy( nStart
[5], nEnd
[5]+1-nStart
[5]).toInt32();
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();
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
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
);
1217 ScFieldEditEngine
& rEngine
= pDoc
->GetEditEngine();
1218 rEngine
.SetText(rStr
);
1219 rDocImport
.setEditCell(ScAddress(nCol
, nRow
, nTab
), rEngine
.CreateTextObject());
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();
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] == ' ' )
1240 rbIsQuoted
= (pStr
[nStart
] == '"' && pStr
[nSpace
-1] == '"');
1243 bool bFits
= (nSpace
- nStart
- 3 <= STRING_MAXLEN
);
1244 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1246 return rLine
.copy(nStart
+1, nSpace
-nStart
-2);
1249 rbOverflowCell
= true;
1250 return rLine
.copy(nStart
+1, STRING_MAXLEN
);
1255 bool bFits
= (nSpace
- nStart
<= STRING_MAXLEN
);
1256 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1258 return rLine
.copy(nStart
, nSpace
-nStart
);
1261 rbOverflowCell
= true;
1262 return rLine
.copy(nStart
, STRING_MAXLEN
);
1267 bool ScImportExport::ExtText2Doc( SvStream
& rStrm
)
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
) );
1319 SCROW nRow
= nStartRow
;
1321 while(--nSkipLines
>0)
1323 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
); // content is ignored
1324 if ( rStrm
.IsEof() )
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
);
1347 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
);
1348 if ( rStrm
.IsEof() && aLine
.isEmpty() )
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
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
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
)
1378 bMultiLine
|= lcl_PutString(
1379 aDocImport
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1380 &aNumFormatter
, bDetectNumFormat
, aTransliteration
, aCalendar
,
1381 pEnglishTransliteration
.get(), pEnglishCalendar
.get());
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
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
1412 if ( nFmt
!= SC_COL_SKIP
)
1415 bOverflowCol
= true; // display warning on import
1416 else if (!bDetermineRange
)
1418 if (bIsQuoted
&& bQuotedAsText
)
1421 bMultiLine
|= lcl_PutString(
1422 aDocImport
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1423 &aNumFormatter
, bDetectNumFormat
, aTransliteration
,
1424 aCalendar
, pEnglishTransliteration
.get(), pEnglishCalendar
.get());
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
);
1442 if ( nRow
> MAXROW
)
1444 bOverflowRow
= true; // display warning on import
1448 // so far nRow/nEndCol pointed to the next free
1449 if (nRow
> nStartRow
)
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
)
1469 rStrm
.Seek( nOriginalStreamPos
);
1478 bDetermineRange
= !bDetermineRange
; // toggle
1479 } while (!bDetermineRange
);
1480 aDocImport
.finalize();
1482 xProgress
.reset(); // make room for AdjustRowHeight progress
1483 if (bRangeIsDetermined
)
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
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
)
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
)
1525 if ( *p
== cStr
) // String in quotes
1528 const sal_Unicode
* p1
;
1529 p1
= p
= lcl_ScanString( p
, rField
, pSeps
, cStr
, DQM_ESCAPE
, rbOverflowCell
);
1530 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1532 // Append remaining unquoted and undelimited data (dirty, dirty) to
1536 if (!lcl_appendLineData( rField
, p1
, p
))
1537 rbOverflowCell
= true;
1542 else // up to delimiter
1544 const sal_Unicode
* p0
= p
;
1545 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1547 if (!lcl_appendLineData( rField
, p0
, p
))
1548 rbOverflowCell
= true;
1552 if ( bMergeSeps
) // skip following delimiters
1554 while ( *p
&& ScGlobal::UnicodeStrChr( pSeps
, *p
) )
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
)
1582 // line break found.
1593 bool ScImportExport::Doc2Text( SvStream
& rStrm
)
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
);
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
++)
1618 pDoc
->GetCellType( nCol
, nRow
, nStartTab
, eType
);
1621 case CELLTYPE_FORMULA
:
1625 pDoc
->GetFormula( nCol
, nRow
, nStartTab
, aCell
);
1626 if( aCell
.indexOf( cSep
) != -1 )
1627 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1629 lcl_WriteSimpleString( rStrm
, aCell
);
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
);
1650 lcl_WriteSimpleString( rStrm
, aCell
);
1654 case CELLTYPE_VALUE
:
1656 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1657 lcl_WriteSimpleString( rStrm
, aCell
);
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
);
1681 lcl_WriteSimpleString( rStrm
, aCell
);
1684 if( nCol
< nEndCol
)
1685 lcl_WriteSimpleString( rStrm
, OUString(cSep
) );
1687 WriteUnicodeOrByteEndl( rStrm
);
1688 if( rStrm
.GetError() != SVSTREAM_OK
)
1690 if( nSizeLimit
&& rStrm
.Tell() > nSizeLimit
)
1695 return rStrm
.GetError() == SVSTREAM_OK
;
1699 bool ScImportExport::Sylk2Doc( SvStream
& rStrm
)
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
;
1725 SCCOL nCol
= nStartCol
;
1726 SCROW nRow
= nStartRow
;
1729 rStrm
.Seek( nOldPos
);
1733 rStrm
.ReadLine( aByteLine
);
1734 aLine
= OStringToOUString(aByteLine
, rStrm
.GetStreamCharSet());
1737 const sal_Unicode
* p
= aLine
.getStr();
1738 sal_Unicode cTag
= *p
++;
1739 if( cTag
== 'C' ) // Content
1745 sal_Unicode ch
= *p
++;
1746 ch
= ScGlobal::ToUpperAlpha( ch
);
1750 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1753 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
1756 nRefCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1759 nRefRow
= OUString(p
).toInt32() + nStartRow
- 1;
1764 ( nCol
< nStartCol
|| nCol
> nEndCol
1765 || nRow
< nStartRow
|| nRow
> nEndRow
1766 || nCol
> MAXCOL
|| nRow
> MAXROW
) )
1770 if( nRow
> nEndRow
)
1772 if( nCol
> nEndCol
)
1781 p
= lcl_ScanSylkString( p
, aText
, eVersion
);
1785 const sal_Unicode
* q
= p
;
1786 while( *q
&& *q
!= ';' )
1788 if ( !(*q
== ';' && *(q
+1) == 'I') )
1789 { // don't ignore value
1792 pDoc
->EnsureTable(aRange
.aStart
.Tab());
1794 ScAddress(nCol
, nRow
, aRange
.aStart
.Tab()), aText
);
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
);
1811 if ( nRefCol
< nCol
)
1813 if ( nRefRow
< nRow
)
1817 if( nRefRow
> nEndRow
)
1819 if( nRefCol
> nEndCol
)
1823 if( !bMyDoc
|| !bData
)
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
);
1838 aMark
.SelectTable( aPos
.Tab(), true );
1839 pDoc
->InsertMatrixFormula( nCol
, nRow
, nRefCol
,
1840 nRefRow
, aMark
, EMPTY_OUSTRING
, pCode
);
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
1852 while( *p
&& *p
!= ';' )
1858 else if( cTag
== 'F' ) // Format
1862 sal_Int32 nFormat
= -1;
1865 sal_Unicode ch
= *p
++;
1866 ch
= ScGlobal::ToUpperAlpha( ch
);
1870 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1873 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
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
!= ';' )
1884 OUString
aNumber(p0
, p
- p0
);
1885 nFormat
= aNumber
.toInt32();
1889 while( *p
&& *p
!= ';' )
1896 if( nRow
> nEndRow
)
1898 if( nCol
> nEndCol
)
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
;
1920 pDoc
->GetFormatTable()->PutandConvertEntry( aCode
, nCheckPos
, nType
, nKey
,
1921 LANGUAGE_ENGLISH_US
, ScGlobal::eLnge
);
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
1941 aRange
.aEnd
.SetCol( nEndCol
);
1942 aRange
.aEnd
.SetRow( nEndRow
);
1955 bool ScImportExport::Doc2Sylk( SvStream
& rStrm
)
1959 SCCOL nStartCol
= aRange
.aStart
.Col();
1960 SCROW nStartRow
= aRange
.aStart
.Row();
1961 SCCOL nEndCol
= aRange
.aEnd
.Col();
1962 SCROW nEndRow
= aRange
.aEnd
.Row();
1965 lcl_WriteSimpleString( rStrm
, OUString("ID;PCALCOOO32") );
1966 WriteUnicodeOrByteEndl( rStrm
);
1968 for (nRow
= nStartRow
; nRow
<= nEndRow
; nRow
++)
1970 for (nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
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
;
1982 case CELLTYPE_FORMULA
:
1984 if( pDoc
->HasValueData( nCol
, nRow
, aRange
.aStart
.Tab()) )
1989 case CELLTYPE_VALUE
:
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 );
1998 aBufStr
+= OUString::number( c
);
2000 aBufStr
+= OUString::number( r
);
2003 lcl_WriteSimpleString( rStrm
, aBufStr
);
2006 case CELLTYPE_STRING
:
2009 aCellStr
= pDoc
->GetString(nCol
, nRow
, aRange
.aStart
.Tab());
2010 aCellStr
= aCellStr
.replaceAll( OUString('\n'), OUString(SYLK_LF
) );
2013 aBufStr
+= OUString::number( c
);
2015 aBufStr
+= OUString::number( r
);
2017 lcl_WriteSimpleString( rStrm
, aBufStr
);
2018 lcl_WriteString( rStrm
, aCellStr
, '"', ';' );
2023 const ScFormulaCell
* pFCell
= aCell
.mpFormula
;
2024 switch ( pFCell
->GetMatrixFlag() )
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);
2047 switch ( pFCell
->GetMatrixFlag() )
2050 { // diff expression with 'M' M$-extension
2053 pFCell
->GetMatColsRows( nC
, nR
);
2057 aPrefix
+= OUString::number( nR
);
2059 aPrefix
+= OUString::number( nC
);
2064 { // diff expression with 'I' M$-extension
2066 pFCell
->GetMatrixOrigin( aPos
);
2068 aPrefix
+= OUString::number( aPos
.Row() - nStartRow
+ 1 );
2070 aPrefix
+= OUString::number( aPos
.Col() - nStartCol
+ 1 );
2074 // formula Expression
2077 lcl_WriteSimpleString( rStrm
, aPrefix
);
2078 if ( !aCellStr
.isEmpty() )
2079 lcl_WriteString( rStrm
, aCellStr
, 0, ';' );
2081 WriteUnicodeOrByteEndl( rStrm
);
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
);
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
);
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();
2143 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2144 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2145 pImportDoc
->CopyToDocument( aRange
, nFlags
, false, pDoc
);
2155 bool ScImportExport::RTF2Doc( SvStream
& rStrm
, const OUString
& rBaseURL
)
2157 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateRTFImport( pDoc
, aRange
);
2160 pImp
->Read( rStrm
, rBaseURL
);
2161 aRange
= pImp
->GetRange();
2163 bool bOk
= StartPaste();
2166 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2167 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2168 pImp
->WriteToDocument();
2176 bool ScImportExport::HTML2Doc( SvStream
& rStrm
, const OUString
& rBaseURL
)
2178 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateHTMLImport( pDoc
, rBaseURL
, aRange
, true);
2181 pImp
->Read( rStrm
, rBaseURL
);
2182 aRange
= pImp
->GetRange();
2184 bool bOk
= StartPaste();
2187 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2188 // a Draw Layer but no Draw View -> create Draw Layer and View here
2190 pDocSh
->MakeDrawLayer();
2192 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2193 pDoc
->DeleteAreaTab( aRange
, nFlags
);
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
);
2204 // Regular import, with no options.
2205 pImp
->WriteToDocument();
2213 #ifndef DISABLE_DYNLOADING
2215 #define RETURN_ERROR { return eERR_INTERN; }
2216 class ScFormatFilterMissing
: public ScFormatFilterPlugin
{
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() {} }
2251 ScFormatFilterPlugin
* ScFilterCreate();
2256 typedef ScFormatFilterPlugin
* (*FilterFn
)(void);
2257 ScFormatFilterPlugin
&ScFormatFilter::Get()
2259 static ScFormatFilterPlugin
*plugin
;
2264 #ifndef DISABLE_DYNLOADING
2265 OUString
sFilterLib(SVLIBRARY("scfilt"));
2266 static ::osl::Module aModule
;
2267 bool bLoaded
= aModule
.loadRelative(&thisModule
, sFilterLib
);
2269 bLoaded
= aModule
.load(sFilterLib
);
2272 oslGenericFunction fn
= aModule
.getFunctionSymbol( OUString( "ScFilterCreate" ) );
2274 plugin
= reinterpret_cast<FilterFn
>(fn
)();
2277 plugin
= new ScFormatFilterMissing();
2279 plugin
= ScFilterCreate();
2285 // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2287 static inline const sal_Unicode
* lcl_UnicodeStrChr( const sal_Unicode
* pStr
,
2299 OUString
ReadCsvLine( SvStream
&rStream
, bool bEmbeddedLineBreak
,
2300 const OUString
& rFieldSeparators
, sal_Unicode cFieldQuote
)
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();
2323 if (*p
== cFieldQuote
)
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
)
2343 else if (eQuoteState
== FIELDEND_QUOTE
)
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
);
2351 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2356 if (*p
== cFieldQuote
&& bFieldStart
)
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.
2369 bFieldStart
= (*p
== ' ' || lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2371 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2374 // A quote character inside a field content does not start
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.
2386 nLastOffset
= aStr
.getLength();
2388 rStream
.ReadUniOrByteStringLine(aNext
, rStream
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
2389 aStr
+= OUString('\n');
2397 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */