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"
53 #include "globstr.hrc"
54 #include <vcl/svapp.hxx>
56 //========================================================================
58 // We don't want to end up with 2GB read in one line just because of malformed
59 // multiline fields, so chop it _somewhere_, which is twice supported columns
60 // times maximum cell content length, 2*1024*64K=128M, and because it's
61 // sal_Unicode that's 256MB. If it's 2GB of data without LF we're out of luck
63 static const sal_Int32 nArbitraryLineLengthLimit
= 2 * MAXCOLCOUNT
* STRING_MAXLEN
;
67 const char SYLK_LF
[] = "\x1b :";
68 const char DOUBLE_SEMICOLON
[] = ";;";
69 const char DOUBLE_DOUBLEQUOTE
[] = "\"\"";
74 SYLK_SCALC3
, // Wrote wrongly quoted strings and unescaped semicolons.
75 SYLK_OOO32
, // Correct strings, plus multiline content.
76 SYLK_OWN
, // Place our new versions, if any, before this value.
77 SYLK_OTHER
// Assume that aliens wrote correct strings.
81 // Gesamtdokument ohne Undo
84 ScImportExport::ScImportExport( ScDocument
* p
)
85 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
86 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
87 bFormulas( false ), bIncludeFiltered( true ),
88 bAll( true ), bSingle( true ), bUndo( false ),
89 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
90 mbApi( true ), mExportTextOptions()
96 // Insert am Punkt ohne Bereichschecks
99 ScImportExport::ScImportExport( ScDocument
* p
, const ScAddress
& rPt
)
100 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
102 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
103 bFormulas( false ), bIncludeFiltered( true ),
104 bAll( false ), bSingle( true ), bUndo( pDocSh
!= NULL
),
105 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
106 mbApi( true ), mExportTextOptions()
113 // ctor with a range is only used for export
114 //! ctor with a string (and bSingle=true) is also used for DdeSetData
116 ScImportExport::ScImportExport( ScDocument
* p
, const ScRange
& r
)
117 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
119 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
120 bFormulas( false ), bIncludeFiltered( true ),
121 bAll( false ), bSingle( false ), bUndo( pDocSh
!= NULL
),
122 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
123 mbApi( true ), mExportTextOptions()
127 // Zur Zeit nur in einer Tabelle!
128 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() );
131 // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
132 // Falls eine View existiert, wird die TabNo der View entnommen!
135 ScImportExport::ScImportExport( ScDocument
* p
, const String
& rPos
)
136 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
137 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
138 bFormulas( false ), bIncludeFiltered( true ),
139 bAll( false ), bSingle( true ), bUndo( pDocSh
!= NULL
),
140 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
141 mbApi( true ), mExportTextOptions()
146 SCTAB nTab
= ScDocShell::GetCurTab();
147 aRange
.aStart
.SetTab( nTab
);
149 // Benannter Bereich?
150 ScRangeName
* pRange
= pDoc
->GetRangeName();
153 const ScRangeData
* pData
= pRange
->findByUpperName(ScGlobal::pCharClass
->uppercase(aPos
));
156 if( pData
->HasType( RT_REFAREA
)
157 || pData
->HasType( RT_ABSAREA
)
158 || pData
->HasType( RT_ABSPOS
) )
159 pData
->GetSymbol( aPos
); // mit dem Inhalt weitertesten
162 formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
164 if( aRange
.Parse( aPos
, pDoc
, eConv
) & SCA_VALID
)
167 else if( aRange
.aStart
.Parse( aPos
, pDoc
, eConv
) & SCA_VALID
)
168 aRange
.aEnd
= aRange
.aStart
;
174 ScImportExport::~ScImportExport()
181 void ScImportExport::SetExtOptions( const ScAsciiOptions
& rOpt
)
186 pExtOptions
= new ScAsciiOptions( rOpt
);
188 // "normale" Optionen uebernehmen
190 cSep
= rOpt
.GetFieldSeps().GetChar(0);
191 cStr
= rOpt
.GetTextSep();
195 bool ScImportExport::IsFormatSupported( sal_uLong nFormat
)
197 return nFormat
== FORMAT_STRING
198 || nFormat
== SOT_FORMATSTR_ID_SYLK
199 || nFormat
== SOT_FORMATSTR_ID_LINK
200 || nFormat
== SOT_FORMATSTR_ID_HTML
201 || nFormat
== SOT_FORMATSTR_ID_HTML_SIMPLE
202 || nFormat
== SOT_FORMATSTR_ID_DIF
;
206 //////////////////////////////////////////////////////////////////////////////
208 // Vorbereitung fuer Undo: Undo-Dokument erzeugen
211 bool ScImportExport::StartPaste()
215 ScEditableTester
aTester( pDoc
, aRange
);
216 if ( !aTester
.IsEditable() )
218 InfoBox
aInfoBox(Application::GetDefDialogParent(),
219 ScGlobal::GetRscString( aTester
.GetMessageId() ) );
224 if( bUndo
&& pDocSh
&& pDoc
->IsUndoEnabled())
226 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
227 pUndoDoc
->InitUndo( pDoc
, aRange
.aStart
.Tab(), aRange
.aEnd
.Tab() );
228 pDoc
->CopyToDocument( aRange
, IDF_ALL
| IDF_NOCAPTIONS
, false, pUndoDoc
);
233 // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
236 void ScImportExport::EndPaste()
238 bool bHeight
= pDocSh
&& pDocSh
->AdjustRowHeight(
239 aRange
.aStart
.Row(), aRange
.aEnd
.Row(), aRange
.aStart
.Tab() );
241 if( pUndoDoc
&& pDoc
->IsUndoEnabled() )
243 ScDocument
* pRedoDoc
= new ScDocument( SCDOCMODE_UNDO
);
244 pRedoDoc
->InitUndo( pDoc
, aRange
.aStart
.Tab(), aRange
.aEnd
.Tab() );
245 pDoc
->CopyToDocument( aRange
, IDF_ALL
| IDF_NOCAPTIONS
, false, pRedoDoc
);
246 ScMarkData aDestMark
;
247 aDestMark
.SetMarkArea(aRange
);
248 pDocSh
->GetUndoManager()->AddUndoAction(
249 new ScUndoPaste(pDocSh
, aRange
, aDestMark
, pUndoDoc
, pRedoDoc
, IDF_ALL
, NULL
));
255 pDocSh
->PostPaint( aRange
, PAINT_GRID
); // AdjustRowHeight paintet evtl. selber
256 pDocSh
->SetDocumentModified();
258 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
260 pViewSh
->UpdateInputHandler();
264 /////////////////////////////////////////////////////////////////////////////
266 bool ScImportExport::ImportData( const String
& /* rMimeType */,
267 const ::com::sun::star::uno::Any
& /* rValue */ )
269 OSL_ENSURE( !this, "Implementation is missing" );
273 bool ScImportExport::ExportData( const String
& rMimeType
,
274 ::com::sun::star::uno::Any
& rValue
)
276 SvMemoryStream aStrm
;
277 // mba: no BaseURL for data exchange
278 if( ExportStream( aStrm
, String(),
279 SotExchange::GetFormatIdFromMimeType( rMimeType
) ))
281 aStrm
<< (sal_uInt8
) 0;
282 rValue
<<= ::com::sun::star::uno::Sequence
< sal_Int8
>(
283 (sal_Int8
*)aStrm
.GetData(),
284 aStrm
.Seek( STREAM_SEEK_TO_END
) );
291 bool ScImportExport::ImportString( const OUString
& rText
, sal_uLong nFmt
)
295 // formats supporting unicode
298 ScImportStringStream
aStrm( rText
);
299 return ImportStream( aStrm
, String(), nFmt
);
300 // ImportStream must handle RTL_TEXTENCODING_UNICODE
305 rtl_TextEncoding eEnc
= osl_getThreadTextEncoding();
306 OString
aTmp( rText
.getStr(), rText
.getLength(), eEnc
);
307 SvMemoryStream
aStrm( (void*)aTmp
.getStr(), aTmp
.getLength() * sizeof(sal_Char
), STREAM_READ
);
308 aStrm
.SetStreamCharSet( eEnc
);
309 SetNoEndianSwap( aStrm
); //! no swapping in memory
310 return ImportStream( aStrm
, String(), nFmt
);
316 bool ScImportExport::ExportString( OUString
& rText
, sal_uLong nFmt
)
318 OSL_ENSURE( nFmt
== FORMAT_STRING
, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
319 if ( nFmt
!= FORMAT_STRING
)
321 rtl_TextEncoding eEnc
= osl_getThreadTextEncoding();
323 bool bOk
= ExportByteString( aTmp
, eEnc
, nFmt
);
324 rText
= OStringToOUString( aTmp
, eEnc
);
327 // nSizeLimit not needed for OUString
329 SvMemoryStream aStrm
;
330 aStrm
.SetStreamCharSet( RTL_TEXTENCODING_UNICODE
);
331 SetNoEndianSwap( aStrm
); //! no swapping in memory
332 // mba: no BaseURL for data exc
333 if( ExportStream( aStrm
, String(), nFmt
) )
335 aStrm
<< (sal_Unicode
) 0;
336 aStrm
.Seek( STREAM_SEEK_TO_END
);
338 rText
= OUString( (const sal_Unicode
*) aStrm
.GetData() );
344 // ExportStream must handle RTL_TEXTENCODING_UNICODE
348 bool ScImportExport::ExportByteString( OString
& rText
, rtl_TextEncoding eEnc
, sal_uLong nFmt
)
350 OSL_ENSURE( eEnc
!= RTL_TEXTENCODING_UNICODE
, "ScImportExport::ExportByteString: Unicode not supported" );
351 if ( eEnc
== RTL_TEXTENCODING_UNICODE
)
352 eEnc
= osl_getThreadTextEncoding();
355 nSizeLimit
= STRING_MAXLEN
;
357 SvMemoryStream aStrm
;
358 aStrm
.SetStreamCharSet( eEnc
);
359 SetNoEndianSwap( aStrm
); //! no swapping in memory
360 // mba: no BaseURL for data exchange
361 if( ExportStream( aStrm
, String(), nFmt
) )
363 aStrm
<< (sal_Char
) 0;
364 aStrm
.Seek( STREAM_SEEK_TO_END
);
365 // Sicherheits-Check:
366 if( aStrm
.Tell() <= (sal_uLong
) STRING_MAXLEN
)
368 rText
= (const sal_Char
*) aStrm
.GetData();
377 bool ScImportExport::ImportStream( SvStream
& rStrm
, const String
& rBaseURL
, sal_uLong nFmt
)
379 if( nFmt
== FORMAT_STRING
)
381 if( ExtText2Doc( rStrm
) ) // pExtOptions auswerten
384 if( nFmt
== SOT_FORMATSTR_ID_SYLK
)
386 if( Sylk2Doc( rStrm
) )
389 if( nFmt
== SOT_FORMATSTR_ID_DIF
)
391 if( Dif2Doc( rStrm
) )
394 if( nFmt
== FORMAT_RTF
)
396 if( RTF2Doc( rStrm
, rBaseURL
) )
399 if( nFmt
== SOT_FORMATSTR_ID_LINK
)
400 return true; // Link-Import?
401 if ( nFmt
== SOT_FORMATSTR_ID_HTML
)
403 if( HTML2Doc( rStrm
, rBaseURL
) )
406 if ( nFmt
== SOT_FORMATSTR_ID_HTML_SIMPLE
)
408 MSE40HTMLClipFormatObj aMSE40ClpObj
; // needed to skip the header data
409 SvStream
* pHTML
= aMSE40ClpObj
.IsValid( rStrm
);
410 if ( pHTML
&& HTML2Doc( *pHTML
, rBaseURL
) )
418 bool ScImportExport::ExportStream( SvStream
& rStrm
, const String
& rBaseURL
, sal_uLong nFmt
)
420 if( nFmt
== FORMAT_STRING
)
422 if( Doc2Text( rStrm
) )
425 if( nFmt
== SOT_FORMATSTR_ID_SYLK
)
427 if( Doc2Sylk( rStrm
) )
430 if( nFmt
== SOT_FORMATSTR_ID_DIF
)
432 if( Doc2Dif( rStrm
) )
435 if( nFmt
== SOT_FORMATSTR_ID_LINK
&& !bAll
)
438 if ( pDoc
->IsClipboard() )
439 aDocName
= ScGlobal::GetClipDocName();
442 SfxObjectShell
* pShell
= pDoc
->GetDocumentShell();
444 aDocName
= pShell
->GetTitle( SFX_TITLE_FULLNAME
);
447 OSL_ENSURE( aDocName
.Len(), "ClipBoard document has no name! :-/" );
450 // Always use Calc A1 syntax for paste link.
452 sal_uInt16 nFlags
= SCA_VALID
| SCA_TAB_3D
;
454 aRange
.aStart
.Format( aRefName
, nFlags
, pDoc
, formula::FormulaGrammar::CONV_OOO
);
457 if( aRange
.aStart
.Tab() != aRange
.aEnd
.Tab() )
458 nFlags
|= SCA_TAB2_3D
;
459 aRange
.Format( aRefName
, nFlags
, pDoc
, formula::FormulaGrammar::CONV_OOO
);
461 String aAppName
= Application::GetAppName();
463 // extra bits are used to tell the client to prefer external
465 OUString
aExtraBits("calc:extref");
467 WriteUnicodeOrByteString( rStrm
, aAppName
, true );
468 WriteUnicodeOrByteString( rStrm
, aDocName
, true );
469 WriteUnicodeOrByteString( rStrm
, aRefName
, true );
470 WriteUnicodeOrByteString( rStrm
, aExtraBits
, true );
471 if ( rStrm
.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE
)
472 rStrm
<< sal_Unicode(0);
474 rStrm
<< sal_Char(0);
475 return rStrm
.GetError() == SVSTREAM_OK
;
478 if( nFmt
== SOT_FORMATSTR_ID_HTML
)
480 if( Doc2HTML( rStrm
, rBaseURL
) )
483 if( nFmt
== FORMAT_RTF
)
485 if( Doc2RTF( rStrm
) )
493 void ScImportExport::WriteUnicodeOrByteString( SvStream
& rStrm
, const String
& rString
, bool bZero
)
495 rtl_TextEncoding eEnc
= rStrm
.GetStreamCharSet();
496 if ( eEnc
== RTL_TEXTENCODING_UNICODE
)
498 if ( !IsEndianSwap( rStrm
) )
499 rStrm
.Write( rString
.GetBuffer(), rString
.Len() * sizeof(sal_Unicode
) );
502 const sal_Unicode
* p
= rString
.GetBuffer();
503 const sal_Unicode
* const pStop
= p
+ rString
.Len();
510 rStrm
<< sal_Unicode(0);
514 OString
aByteStr(OUStringToOString(rString
, eEnc
));
515 rStrm
<< aByteStr
.getStr();
517 rStrm
<< sal_Char(0);
522 // This function could be replaced by endlub()
523 void ScImportExport::WriteUnicodeOrByteEndl( SvStream
& rStrm
)
525 if ( rStrm
.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE
)
526 { // same as endl() but unicode
527 switch ( rStrm
.GetLineDelimiter() )
530 rStrm
<< sal_Unicode('\r');
533 rStrm
<< sal_Unicode('\n');
536 rStrm
<< sal_Unicode('\r') << sal_Unicode('\n');
554 /** Determine if *p is a quote that ends a quoted field.
556 Precondition: we are parsing a quoted field already and *p is a quote.
559 FIELDEND_QUOTE if end of field quote
560 DONTKNOW_QUOTE anything else
562 static QuoteType
lcl_isFieldEndQuote( const sal_Unicode
* p
, const sal_Unicode
* pSeps
)
564 // Due to broken CSV generators that don't double embedded quotes check if
565 // a field separator immediately or with trailing spaces follows the quote,
566 // only then end the field, or at end of string.
567 const sal_Unicode cBlank
= ' ';
568 if (p
[1] == cBlank
&& ScGlobal::UnicodeStrChr( pSeps
, cBlank
))
569 return FIELDEND_QUOTE
;
570 while (p
[1] == cBlank
)
572 if (!p
[1] || ScGlobal::UnicodeStrChr( pSeps
, p
[1]))
573 return FIELDEND_QUOTE
;
574 return DONTKNOW_QUOTE
;
578 /** Determine if *p is a quote that is escaped by being doubled or ends a
581 Precondition: *p is a quote.
584 Quote characters encountered so far.
585 Odd (after opening quote) means either no embedded quotes or only quote
587 Even means either not in a quoted field or already one quote
588 encountered, the first of a pair.
591 FIELDSTART_QUOTE if first quote in a field, either starting content or
592 embedded so caller should check beforehand.
593 FIRST_QUOTE if first of a doubled quote
594 SECOND_QUOTE if second of a doubled quote
595 FIELDEND_QUOTE if end of field quote
596 DONTKNOW_QUOTE if an unescaped quote we don't consider as end of field,
597 do not increment nQuotes in caller then!
599 static QuoteType
lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes
, const sal_Unicode
* p
,
600 const sal_Unicode
* pSeps
, sal_Unicode cStr
)
602 if ((nQuotes
% 2) == 0)
608 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
609 return FIELDSTART_QUOTE
;
614 return lcl_isFieldEndQuote( p
, pSeps
);
618 /** Append characters of [p1,p2) to rField.
620 @returns TRUE if ok; FALSE if data overflow, truncated
622 static bool lcl_appendLineData( String
& rField
, const sal_Unicode
* p1
, const sal_Unicode
* p2
)
624 OSL_ENSURE( rField
.Len() + (p2
- p1
) <= STRING_MAXLEN
, "lcl_appendLineData: data overflow");
625 if (rField
.Len() + (p2
- p1
) <= STRING_MAXLEN
)
627 rField
.Append( p1
, sal::static_int_cast
<xub_StrLen
>( p2
- p1
) );
632 // If STRING_MAXLEN is passed as length, then String attempts to
633 // determine the length of the string and comes up with an overflow
634 // casted to xub_StrLen again ... so pass max-1, data will be truncated
636 rField
.Append( p1
, (rField
.Len() ? STRING_MAXLEN
- rField
.Len() : STRING_MAXLEN
- 1) );
642 enum DoubledQuoteMode
644 DQM_KEEP_ALL
, // both are taken, additionally start and end quote are included in string
645 DQM_KEEP
, // both are taken
646 DQM_ESCAPE
, // escaped quote, one is taken, one ignored
647 DQM_CONCAT
, // first is end, next is start, both ignored => strings combined
648 DQM_SEPARATE
// end one string and begin next
651 static const sal_Unicode
* lcl_ScanString( const sal_Unicode
* p
, String
& rString
,
652 const sal_Unicode
* pSeps
, sal_Unicode cStr
, DoubledQuoteMode eMode
, bool& rbOverflowCell
)
654 if (eMode
!= DQM_KEEP_ALL
)
655 p
++; //! jump over opening quote
660 const sal_Unicode
* p0
= p
;
669 // break or continue for loop
670 if (eMode
== DQM_ESCAPE
)
672 if (lcl_isFieldEndQuote( p
-1, pSeps
) == FIELDEND_QUOTE
)
680 // doubled quote char
685 p
++; // both for us (not breaking for-loop)
688 p
++; // one for us (breaking for-loop)
689 bCont
= true; // and more
695 if (!lcl_appendLineData( rString
, p0
, p
-1))
696 rbOverflowCell
= true;
698 p0
= ++p
; // text of next part starts here
701 // positioned on next opening quote
704 if ( eMode
== DQM_ESCAPE
|| eMode
== DQM_SEPARATE
)
712 if (!lcl_appendLineData( rString
, p0
, ((eMode
!= DQM_KEEP_ALL
&& (*p
|| *(p
-1) == cStr
)) ? p
-1 : p
)))
713 rbOverflowCell
= true;
719 static void lcl_UnescapeSylk( String
& rString
, SylkVersion eVersion
)
721 // Older versions didn't escape the semicolon.
722 // Older versions quoted the string and doubled embedded quotes, but not
723 // the semicolons, which was plain wrong.
724 if (eVersion
>= SYLK_OOO32
)
725 rString
.SearchAndReplaceAll( OUString(DOUBLE_SEMICOLON
), OUString(';') );
727 rString
.SearchAndReplaceAll( OUString(DOUBLE_DOUBLEQUOTE
), OUString('"') );
729 rString
.SearchAndReplaceAll( OUString(SYLK_LF
), OUString('\n') );
732 static const sal_Unicode
* lcl_ScanSylkString( const sal_Unicode
* p
,
733 String
& rString
, SylkVersion eVersion
)
735 const sal_Unicode
* pStartQuote
= p
;
736 const sal_Unicode
* pEndQuote
= 0;
742 if (eVersion
>= SYLK_OOO32
)
748 p
+= 2; // escaped ';'
762 else if (*(p
+1) == ';')
768 pEndQuote
= p
; // Take all data as string.
769 rString
.Append( pStartQuote
+ 1, sal::static_int_cast
<xub_StrLen
>( pEndQuote
- pStartQuote
- 1 ) );
770 lcl_UnescapeSylk( rString
, eVersion
);
774 static const sal_Unicode
* lcl_ScanSylkFormula( const sal_Unicode
* p
,
775 String
& rString
, SylkVersion eVersion
)
777 const sal_Unicode
* pStart
= p
;
778 if (eVersion
>= SYLK_OOO32
)
791 rString
.Append( pStart
, sal::static_int_cast
<xub_StrLen
>( p
- pStart
));
792 lcl_UnescapeSylk( rString
, eVersion
);
796 // Nasty. If in old versions the formula contained a semicolon, it was
797 // quoted and embedded quotes were doubled, but semicolons were not. If
798 // there was no semicolon, it could still contain quotes and doubled
799 // embedded quotes if it was something like ="a""b", which was saved as
800 // E"a""b" as is and has to be preserved, even if older versions
801 // couldn't even load it correctly. However, theoretically another
802 // field might follow and thus the line contain a semicolon again, such
803 // as ...;E"a""b";...
804 bool bQuoted
= false;
807 // May be a quoted expression or just a string constant expression
816 break; // closing '"', had no ';' yet
820 bQuoted
= true; // ';' within quoted expression
827 p
= lcl_ScanSylkString( p
, rString
, eVersion
);
830 while (*p
&& *p
!= ';')
832 rString
.Append( pStart
, sal::static_int_cast
<xub_StrLen
>( p
- pStart
));
838 static void lcl_DoubleEscapeChar( String
& rString
, sal_Unicode cStr
)
841 while( ( n
= rString
.Search( cStr
, n
) ) != STRING_NOTFOUND
)
843 rString
.Insert( cStr
, n
);
848 static void lcl_WriteString( SvStream
& rStrm
, String
& rString
, sal_Unicode cQuote
, sal_Unicode cEsc
)
851 lcl_DoubleEscapeChar( rString
, cEsc
);
855 rString
.Insert( cQuote
, 0 );
856 rString
.Append( cQuote
);
859 ScImportExport::WriteUnicodeOrByteString( rStrm
, rString
);
862 static inline void lcl_WriteSimpleString( SvStream
& rStrm
, const String
& rString
)
864 ScImportExport::WriteUnicodeOrByteString( rStrm
, rString
);
867 //////////////////////////////////////////////////////////////////////////////
870 bool ScImportExport::Text2Doc( SvStream
& rStrm
)
874 sal_Unicode pSeps
[2];
878 SCCOL nStartCol
= aRange
.aStart
.Col();
879 SCROW nStartRow
= aRange
.aStart
.Row();
880 SCCOL nEndCol
= aRange
.aEnd
.Col();
881 SCROW nEndRow
= aRange
.aEnd
.Row();
882 sal_uLong nOldPos
= rStrm
.Tell();
883 rStrm
.StartReadingUnicodeText( rStrm
.GetStreamCharSet() );
884 bool bData
= !bSingle
;
892 SCROW nRow
= nStartRow
;
893 rStrm
.Seek( nOldPos
);
896 rStrm
.ReadUniOrByteStringLine( aLine
, rStrm
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
899 SCCOL nCol
= nStartCol
;
900 const sal_Unicode
* p
= aLine
.getStr();
904 const sal_Unicode
* q
= p
;
905 while (*p
&& *p
!= cSep
)
907 // Always look for a pairing quote and ignore separator in between.
908 while (*p
&& *p
== cStr
)
909 q
= p
= lcl_ScanString( p
, aCell
, pSeps
, cStr
, DQM_KEEP_ALL
, bOverflowCell
);
910 // All until next separator or quote.
911 while (*p
&& *p
!= cSep
&& *p
!= cStr
)
913 if (!lcl_appendLineData( aCell
, q
, p
))
914 bOverflowCell
= true; // display warning on import
919 if (ValidCol(nCol
) && ValidRow(nRow
) )
923 if (nCol
>nEndCol
) nEndCol
= nCol
;
924 if (nRow
>nEndRow
) nEndRow
= nRow
;
926 if( bData
&& nCol
<= nEndCol
&& nRow
<= nEndRow
)
927 pDoc
->SetString( nCol
, nRow
, aRange
.aStart
.Tab(), aCell
);
929 else // zuviele Spalten/Zeilen
932 bOverflowRow
= true; // display warning on import
934 bOverflowCol
= true; // display warning on import
943 aRange
.aEnd
.SetCol( nEndCol
);
944 aRange
.aEnd
.SetRow( nEndRow
);
957 // erweiterter Ascii-Import
961 static bool lcl_PutString(
962 ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const String
& rStr
, sal_uInt8 nColFormat
,
963 SvNumberFormatter
* pFormatter
, bool bDetectNumFormat
,
964 ::utl::TransliterationWrapper
& rTransliteration
, CalendarWrapper
& rCalendar
,
965 ::utl::TransliterationWrapper
* pSecondTransliteration
, CalendarWrapper
* pSecondCalendar
)
967 bool bMultiLine
= false;
968 if ( nColFormat
== SC_COL_SKIP
|| !rStr
.Len() || !ValidCol(nCol
) || !ValidRow(nRow
) )
971 if ( nColFormat
== SC_COL_TEXT
)
974 sal_uInt32 nIndex
= 0;
975 if (pFormatter
->IsNumberFormat(rStr
, nIndex
, fDummy
))
977 // Set the format of this cell to Text.
978 sal_uInt32 nFormat
= pFormatter
->GetStandardFormat(NUMBERFORMAT_TEXT
);
979 ScPatternAttr
aNewAttrs(pDoc
->GetPool());
980 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
981 rSet
.Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
) );
982 pDoc
->ApplyPattern(nCol
, nRow
, nTab
, aNewAttrs
);
985 pDoc
->SetTextCell(ScAddress(nCol
,nRow
,nTab
), rStr
);
989 if ( nColFormat
== SC_COL_ENGLISH
)
991 //! SetString mit Extra-Flag ???
993 SvNumberFormatter
* pDocFormatter
= pDoc
->GetFormatTable();
994 sal_uInt32 nEnglish
= pDocFormatter
->GetStandardIndex(LANGUAGE_ENGLISH_US
);
996 if ( pDocFormatter
->IsNumberFormat( rStr
, nEnglish
, fVal
) )
998 // Zahlformat wird nicht auf englisch gesetzt
999 pDoc
->SetValue( nCol
, nRow
, nTab
, fVal
);
1002 // sonst weiter mit SetString
1004 else if ( nColFormat
!= SC_COL_STANDARD
) // Datumsformate
1006 const sal_uInt16 nMaxNumberParts
= 7; // Y-M-D h:m:s.t
1007 xub_StrLen nLen
= rStr
.Len();
1008 xub_StrLen nStart
[nMaxNumberParts
];
1009 xub_StrLen nEnd
[nMaxNumberParts
];
1011 sal_uInt16 nDP
, nMP
, nYP
;
1012 switch ( nColFormat
)
1014 case SC_COL_YMD
: nDP
= 2; nMP
= 1; nYP
= 0; break;
1015 case SC_COL_MDY
: nDP
= 1; nMP
= 0; nYP
= 2; break;
1017 default: nDP
= 0; nMP
= 1; nYP
= 2; break;
1020 sal_uInt16 nFound
= 0;
1021 bool bInNum
= false;
1022 for ( xub_StrLen nPos
=0; nPos
<nLen
&& (bInNum
||
1023 nFound
<nMaxNumberParts
); nPos
++ )
1025 if (bInNum
&& nFound
== 3 && nColFormat
== SC_COL_YMD
&&
1026 nPos
<= nStart
[nFound
]+2 && rStr
.GetChar(nPos
) == 'T')
1027 bInNum
= false; // ISO-8601: YYYY-MM-DDThh:mm...
1028 else if ((((!bInNum
&& nFound
==nMP
) || (bInNum
&& nFound
==nMP
+1))
1029 && ScGlobal::pCharClass
->isLetterNumeric( rStr
, nPos
))
1030 || ScGlobal::pCharClass
->isDigit( rStr
, nPos
))
1035 nStart
[nFound
] = nPos
;
1038 nEnd
[nFound
-1] = nPos
;
1046 // try to break one number (without separators) into date fields
1048 xub_StrLen nDateStart
= nStart
[0];
1049 xub_StrLen nDateLen
= nEnd
[0] + 1 - nDateStart
;
1051 if ( nDateLen
>= 5 && nDateLen
<= 8 &&
1052 ScGlobal::pCharClass
->isNumeric( rStr
.Copy( nDateStart
, nDateLen
) ) )
1054 // 6 digits: 2 each for day, month, year
1055 // 8 digits: 4 for year, 2 each for day and month
1056 // 5 or 7 digits: first field is shortened by 1
1058 bool bLongYear
= ( nDateLen
>= 7 );
1059 bool bShortFirst
= ( nDateLen
== 5 || nDateLen
== 7 );
1061 sal_uInt16 nFieldStart
= nDateStart
;
1062 for (sal_uInt16 nPos
=0; nPos
<3; nPos
++)
1064 sal_uInt16 nFieldEnd
= nFieldStart
+ 1; // default: 2 digits
1065 if ( bLongYear
&& nPos
== nYP
)
1066 nFieldEnd
+= 2; // 2 extra digits for long year
1067 if ( bShortFirst
&& nPos
== 0 )
1068 --nFieldEnd
; // first field shortened?
1070 nStart
[nPos
] = nFieldStart
;
1071 nEnd
[nPos
] = nFieldEnd
;
1072 nFieldStart
= nFieldEnd
+ 1;
1080 using namespace ::com::sun::star
;
1081 bool bSecondCal
= false;
1082 sal_uInt16 nDay
= (sal_uInt16
) rStr
.Copy( nStart
[nDP
], nEnd
[nDP
]+1-nStart
[nDP
] ).ToInt32();
1083 sal_uInt16 nYear
= (sal_uInt16
) rStr
.Copy( nStart
[nYP
], nEnd
[nYP
]+1-nStart
[nYP
] ).ToInt32();
1084 String aMStr
= rStr
.Copy( nStart
[nMP
], nEnd
[nMP
]+1-nStart
[nMP
] );
1085 sal_Int16 nMonth
= (sal_Int16
) aMStr
.ToInt32();
1088 static const String
aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
1089 static const String
aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
1090 uno::Sequence
< i18n::CalendarItem2
> xMonths
;
1091 sal_Int32 i
, nMonthCount
;
1092 // first test all month names from local international
1093 xMonths
= rCalendar
.getMonths();
1094 nMonthCount
= xMonths
.getLength();
1095 for (i
=0; i
<nMonthCount
&& !nMonth
; i
++)
1097 if ( rTransliteration
.isEqual( aMStr
, xMonths
[i
].FullName
) ||
1098 rTransliteration
.isEqual( aMStr
, xMonths
[i
].AbbrevName
) )
1099 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1100 else if ( i
== 8 && rTransliteration
.isEqual( aSeptCorrect
,
1101 xMonths
[i
].AbbrevName
) &&
1102 rTransliteration
.isEqual( aMStr
, aSepShortened
) )
1103 { // correct English abbreviation is SEPT,
1104 // but data mostly contains SEP only
1105 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1108 // if none found, then test english month names
1109 if ( !nMonth
&& pSecondCalendar
&& pSecondTransliteration
)
1111 xMonths
= pSecondCalendar
->getMonths();
1112 nMonthCount
= xMonths
.getLength();
1113 for (i
=0; i
<nMonthCount
&& !nMonth
; i
++)
1115 if ( pSecondTransliteration
->isEqual( aMStr
, xMonths
[i
].FullName
) ||
1116 pSecondTransliteration
->isEqual( aMStr
, xMonths
[i
].AbbrevName
) )
1118 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1121 else if ( i
== 8 && pSecondTransliteration
->isEqual(
1122 aMStr
, aSepShortened
) )
1123 { // correct English abbreviation is SEPT,
1124 // but data mostly contains SEP only
1125 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1132 SvNumberFormatter
* pDocFormatter
= pDoc
->GetFormatTable();
1134 nYear
= pDocFormatter
->ExpandTwoDigitYear( nYear
);
1136 CalendarWrapper
* pCalendar
= (bSecondCal
? pSecondCalendar
: &rCalendar
);
1137 sal_Int16 nNumMonths
= pCalendar
->getNumberOfMonthsInYear();
1138 if ( nDay
&& nMonth
&& nDay
<=31 && nMonth
<=nNumMonths
)
1141 pCalendar
->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH
, nDay
);
1142 pCalendar
->setValue( i18n::CalendarFieldIndex::MONTH
, nMonth
);
1143 pCalendar
->setValue( i18n::CalendarFieldIndex::YEAR
, nYear
);
1144 sal_Int16 nHour
, nMinute
, nSecond
, nMilli
;
1145 // #i14974# The imported value should have no fractional value, so set the
1146 // time fields to zero (ICU calendar instance defaults to current date/time)
1147 nHour
= nMinute
= nSecond
= nMilli
= 0;
1149 nHour
= (sal_Int16
) rStr
.Copy( nStart
[3], nEnd
[3]+1-nStart
[3]).ToInt32();
1151 nMinute
= (sal_Int16
) rStr
.Copy( nStart
[4], nEnd
[4]+1-nStart
[4]).ToInt32();
1153 nSecond
= (sal_Int16
) rStr
.Copy( nStart
[5], nEnd
[5]+1-nStart
[5]).ToInt32();
1156 sal_Unicode cDec
= '.';
1157 OUString
aT( &cDec
, 1);
1158 aT
+= rStr
.Copy( nStart
[6], nEnd
[6]+1-nStart
[6]);
1159 rtl_math_ConversionStatus eStatus
;
1160 double fV
= rtl::math::stringToDouble( aT
, cDec
, 0, &eStatus
, 0);
1161 if (eStatus
== rtl_math_ConversionStatus_Ok
)
1162 nMilli
= (sal_Int16
) (1000.0 * fV
+ 0.5);
1164 pCalendar
->setValue( i18n::CalendarFieldIndex::HOUR
, nHour
);
1165 pCalendar
->setValue( i18n::CalendarFieldIndex::MINUTE
, nMinute
);
1166 pCalendar
->setValue( i18n::CalendarFieldIndex::SECOND
, nSecond
);
1167 pCalendar
->setValue( i18n::CalendarFieldIndex::MILLISECOND
, nMilli
);
1168 if ( pCalendar
->isValid() )
1170 double fDiff
= DateTime(*pDocFormatter
->GetNullDate()) -
1171 pCalendar
->getEpochStart();
1172 // #i14974# must use getLocalDateTime to get the same
1173 // date values as set above
1174 double fDays
= pCalendar
->getLocalDateTime();
1177 LanguageType eLatin
, eCjk
, eCtl
;
1178 pDoc
->GetLanguage( eLatin
, eCjk
, eCtl
);
1179 LanguageType eDocLang
= eLatin
; //! which language for date formats?
1181 short nType
= (nFound
> 3 ? NUMBERFORMAT_DATETIME
: NUMBERFORMAT_DATE
);
1182 sal_uLong nFormat
= pDocFormatter
->GetStandardFormat( nType
, eDocLang
);
1183 // maybe there is a special format including seconds or milliseconds
1185 nFormat
= pDocFormatter
->GetStandardFormat( fDays
, nFormat
, nType
, eDocLang
);
1187 ScAddress
aPos(nCol
,nRow
,nTab
);
1188 pDoc
->SetValue(aPos
, fDays
);
1189 pDoc
->SetNumberFormat(aPos
, nFormat
);
1191 return bMultiLine
; // success
1197 // Standard or date not determined -> SetString / EditCell
1198 if( rStr
.Search( '\n' ) == STRING_NOTFOUND
)
1200 ScSetStringParam aParam
;
1201 aParam
.mpNumFormatter
= pFormatter
;
1202 aParam
.mbDetectNumberFormat
= bDetectNumFormat
;
1203 aParam
.meSetTextNumFormat
= ScSetStringParam::SpecialNumberOnly
;
1204 aParam
.mbHandleApostrophe
= false;
1205 pDoc
->SetString( nCol
, nRow
, nTab
, rStr
, &aParam
);
1210 ScFieldEditEngine
& rEngine
= pDoc
->GetEditEngine();
1211 rEngine
.SetText(rStr
);
1212 pDoc
->SetEditText(ScAddress(nCol
,nRow
,nTab
), rEngine
.CreateTextObject());
1218 static String
lcl_GetFixed( const OUString
& rLine
, sal_Int32 nStart
, sal_Int32 nNext
,
1219 bool& rbIsQuoted
, bool& rbOverflowCell
)
1221 sal_Int32 nLen
= rLine
.getLength();
1224 if ( nNext
<= nStart
)
1225 return EMPTY_STRING
;
1227 const sal_Unicode
* pStr
= rLine
.getStr();
1229 sal_Int32 nSpace
= nNext
;
1230 while ( nSpace
> nStart
&& pStr
[nSpace
-1] == ' ' )
1233 rbIsQuoted
= (pStr
[nStart
] == sal_Unicode('"') && pStr
[nSpace
-1] == sal_Unicode('"'));
1236 bool bFits
= (nSpace
- nStart
- 3 <= STRING_MAXLEN
);
1237 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1239 return rLine
.copy(nStart
+1, nSpace
-nStart
-2);
1242 rbOverflowCell
= true;
1243 return rLine
.copy(nStart
+1, STRING_MAXLEN
);
1248 bool bFits
= (nSpace
- nStart
<= STRING_MAXLEN
);
1249 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1251 return rLine
.copy(nStart
, nSpace
-nStart
);
1254 rbOverflowCell
= true;
1255 return rLine
.copy(nStart
, STRING_MAXLEN
);
1260 bool ScImportExport::ExtText2Doc( SvStream
& rStrm
)
1263 return Text2Doc( rStrm
);
1265 sal_uLong nOldPos
= rStrm
.Tell();
1266 rStrm
.Seek( STREAM_SEEK_TO_END
);
1267 ::std::auto_ptr
<ScProgress
> xProgress( new ScProgress( pDocSh
,
1268 ScGlobal::GetRscString( STR_LOAD_DOC
), rStrm
.Tell() - nOldPos
));
1269 rStrm
.Seek( nOldPos
);
1270 rStrm
.StartReadingUnicodeText( rStrm
.GetStreamCharSet() );
1272 SCCOL nStartCol
= aRange
.aStart
.Col();
1273 SCCOL nEndCol
= aRange
.aEnd
.Col();
1274 SCROW nStartRow
= aRange
.aStart
.Row();
1275 SCTAB nTab
= aRange
.aStart
.Tab();
1277 bool bFixed
= pExtOptions
->IsFixedLen();
1278 const String
& rSeps
= pExtOptions
->GetFieldSeps();
1279 const sal_Unicode
* pSeps
= rSeps
.GetBuffer();
1280 bool bMerge
= pExtOptions
->IsMergeSeps();
1281 sal_uInt16 nInfoCount
= pExtOptions
->GetInfoCount();
1282 const sal_Int32
* pColStart
= pExtOptions
->GetColStart();
1283 const sal_uInt8
* pColFormat
= pExtOptions
->GetColFormat();
1284 long nSkipLines
= pExtOptions
->GetStartRow();
1286 LanguageType eDocLang
= pExtOptions
->GetLanguage();
1287 SvNumberFormatter
aNumFormatter( comphelper::getComponentContext(pDoc
->GetServiceManager()), eDocLang
);
1288 bool bDetectNumFormat
= pExtOptions
->IsDetectSpecialNumber();
1290 // For date recognition
1291 ::utl::TransliterationWrapper
aTransliteration(
1292 comphelper::getComponentContext(pDoc
->GetServiceManager()), SC_TRANSLITERATION_IGNORECASE
);
1293 aTransliteration
.loadModuleIfNeeded( eDocLang
);
1294 CalendarWrapper
aCalendar( comphelper::getComponentContext(pDoc
->GetServiceManager()) );
1295 aCalendar
.loadDefaultCalendar(
1296 LanguageTag( eDocLang
).getLocale() );
1297 boost::scoped_ptr
< ::utl::TransliterationWrapper
> pEnglishTransliteration
;
1298 boost::scoped_ptr
< CalendarWrapper
> pEnglishCalendar
;
1299 if ( eDocLang
!= LANGUAGE_ENGLISH_US
)
1301 pEnglishTransliteration
.reset(new ::utl::TransliterationWrapper (
1302 comphelper::getComponentContext(pDoc
->GetServiceManager()), SC_TRANSLITERATION_IGNORECASE
));
1303 aTransliteration
.loadModuleIfNeeded( LANGUAGE_ENGLISH_US
);
1304 pEnglishCalendar
.reset(new CalendarWrapper ( comphelper::getComponentContext(pDoc
->GetServiceManager()) ));
1305 pEnglishCalendar
->loadDefaultCalendar(
1306 LanguageTag( LANGUAGE_ENGLISH_US
).getLocale() );
1312 SCROW nRow
= nStartRow
;
1314 while(--nSkipLines
>0)
1316 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
); // content is ignored
1317 if ( rStrm
.IsEof() )
1321 // Determine range for Undo.
1322 // TODO: we don't need this during import of a file to a new sheet or
1323 // document, could set bDetermineRange=false then.
1324 bool bDetermineRange
= true;
1326 // Row heights don't need to be adjusted on the fly if EndPaste() is called
1327 // afterwards, which happens only if bDetermineRange. This variable also
1328 // survives the toggle of bDetermineRange down at the end of the do{} loop.
1329 bool bRangeIsDetermined
= bDetermineRange
;
1331 bool bQuotedAsText
= pExtOptions
&& pExtOptions
->IsQuotedAsText();
1333 sal_uLong nOriginalStreamPos
= rStrm
.Tell();
1339 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
);
1340 if ( rStrm
.IsEof() && aLine
.isEmpty() )
1343 EmbeddedNullTreatment( aLine
);
1345 sal_Int32 nLineLen
= aLine
.getLength();
1346 SCCOL nCol
= nStartCol
;
1347 bool bMultiLine
= false;
1348 if ( bFixed
) // Feste Satzlaenge
1350 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1351 // overflow if there is really data following to be put behind
1352 // the last column, which doesn't happen if info is
1354 for ( i
=0; i
<nInfoCount
&& nCol
<= MAXCOL
+1; i
++ )
1356 sal_uInt8 nFmt
= pColFormat
[i
];
1357 if (nFmt
!= SC_COL_SKIP
) // sonst auch nCol nicht hochzaehlen
1360 bOverflowCol
= true; // display warning on import
1361 else if (!bDetermineRange
)
1363 sal_Int32 nStart
= pColStart
[i
];
1364 sal_Int32 nNext
= ( i
+1 < nInfoCount
) ? pColStart
[i
+1] : nLineLen
;
1365 bool bIsQuoted
= false;
1366 aCell
= lcl_GetFixed( aLine
, nStart
, nNext
, bIsQuoted
, bOverflowCell
);
1367 if (bIsQuoted
&& bQuotedAsText
)
1370 bMultiLine
|= lcl_PutString(
1371 pDoc
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1372 &aNumFormatter
, bDetectNumFormat
, aTransliteration
, aCalendar
,
1373 pEnglishTransliteration
.get(), pEnglishCalendar
.get());
1379 else // Nach Trennzeichen suchen
1381 SCCOL nSourceCol
= 0;
1382 sal_uInt16 nInfoStart
= 0;
1383 const sal_Unicode
* p
= aLine
.getStr();
1384 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1385 // overflow if there is really data following to be put behind
1386 // the last column, which doesn't happen if info is
1388 while (*p
&& nCol
<= MAXCOL
+1)
1390 bool bIsQuoted
= false;
1391 p
= ScImportExport::ScanNextFieldFromString( p
, aCell
,
1392 cStr
, pSeps
, bMerge
, bIsQuoted
, bOverflowCell
);
1394 sal_uInt8 nFmt
= SC_COL_STANDARD
;
1395 for ( i
=nInfoStart
; i
<nInfoCount
; i
++ )
1397 if ( pColStart
[i
] == nSourceCol
+ 1 ) // pColStart ist 1-basiert
1399 nFmt
= pColFormat
[i
];
1400 nInfoStart
= i
+ 1; // ColInfos sind in Reihenfolge
1404 if ( nFmt
!= SC_COL_SKIP
)
1407 bOverflowCol
= true; // display warning on import
1408 else if (!bDetermineRange
)
1410 if (bIsQuoted
&& bQuotedAsText
)
1413 bMultiLine
|= lcl_PutString(
1414 pDoc
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1415 &aNumFormatter
, bDetectNumFormat
, aTransliteration
,
1416 aCalendar
, pEnglishTransliteration
.get(), pEnglishCalendar
.get());
1425 nEndCol
= nCol
; //! points to the next free or even MAXCOL+2
1427 if (!bDetermineRange
)
1429 if (bMultiLine
&& !bRangeIsDetermined
&& pDocSh
)
1430 pDocSh
->AdjustRowHeight( nRow
, nRow
, nTab
);
1431 xProgress
->SetStateOnPercent( rStrm
.Tell() - nOldPos
);
1434 if ( nRow
> MAXROW
)
1436 bOverflowRow
= true; // display warning on import
1440 // so far nRow/nEndCol pointed to the next free
1441 if (nRow
> nStartRow
)
1443 if (nEndCol
> nStartCol
)
1444 nEndCol
= ::std::min( static_cast<SCCOL
>(nEndCol
- 1), MAXCOL
);
1446 if (bDetermineRange
)
1448 aRange
.aEnd
.SetCol( nEndCol
);
1449 aRange
.aEnd
.SetRow( nRow
);
1451 if ( !mbApi
&& nStartCol
!= nEndCol
&&
1452 !pDoc
->IsBlockEmpty( nTab
, nStartCol
+ 1, nStartRow
, nEndCol
, nRow
) )
1454 ScReplaceWarnBox
aBox( pDocSh
->GetActiveDialogParent() );
1455 if ( aBox
.Execute() != RET_YES
)
1461 rStrm
.Seek( nOriginalStreamPos
);
1470 bDetermineRange
= !bDetermineRange
; // toggle
1471 } while (!bDetermineRange
);
1473 pDoc
->DoColResize( nTab
, nStartCol
, nEndCol
, 0 );
1475 xProgress
.reset(); // make room for AdjustRowHeight progress
1476 if (bRangeIsDetermined
)
1483 void ScImportExport::EmbeddedNullTreatment( OUString
& rStr
)
1485 // A nasty workaround for data with embedded NULL characters. As long as we
1486 // can't handle them properly as cell content (things assume 0-terminated
1487 // strings at too many places) simply strip all NULL characters from raw
1488 // data. Excel does the same. See fdo#57841 for sample data.
1490 // The normal case is no embedded NULL, check first before de-/allocating
1492 sal_Unicode cNull
= 0;
1493 if (rStr
.indexOf( cNull
) >= 0)
1495 rStr
= rStr
.replaceAll( OUString( &cNull
, 1), OUString());
1500 const sal_Unicode
* ScImportExport::ScanNextFieldFromString( const sal_Unicode
* p
,
1501 String
& rField
, sal_Unicode cStr
, const sal_Unicode
* pSeps
, bool bMergeSeps
, bool& rbIsQuoted
,
1502 bool& rbOverflowCell
)
1506 const sal_Unicode cBlank
= ' ';
1507 if (!ScGlobal::UnicodeStrChr( pSeps
, cBlank
))
1509 // Cope with broken generators that put leading blanks before a quoted
1510 // field, like "field1", "field2", "..."
1511 // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1512 const sal_Unicode
* pb
= p
;
1513 while (*pb
== cBlank
)
1518 if ( *p
== cStr
) // String in quotes
1521 const sal_Unicode
* p1
;
1522 p1
= p
= lcl_ScanString( p
, rField
, pSeps
, cStr
, DQM_ESCAPE
, rbOverflowCell
);
1523 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1525 // Append remaining unquoted and undelimited data (dirty, dirty) to
1529 if (!lcl_appendLineData( rField
, p1
, p
))
1530 rbOverflowCell
= true;
1535 else // up to delimiter
1537 const sal_Unicode
* p0
= p
;
1538 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1540 if (!lcl_appendLineData( rField
, p0
, p
))
1541 rbOverflowCell
= true;
1545 if ( bMergeSeps
) // skip following delimiters
1547 while ( *p
&& ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1556 * Check if a given string has any line break characters or separators.
1558 * @param rStr string to inspect.
1559 * @param cSep separator character.
1561 bool hasLineBreaksOrSeps( const String
& rStr
, sal_Unicode cSep
)
1563 const sal_Unicode
* p
= rStr
.GetBuffer();
1564 for (xub_StrLen i
= 0, n
= rStr
.Len(); i
< n
; ++i
, ++p
)
1575 // line break found.
1586 bool ScImportExport::Doc2Text( SvStream
& rStrm
)
1590 SCCOL nStartCol
= aRange
.aStart
.Col();
1591 SCROW nStartRow
= aRange
.aStart
.Row();
1592 SCTAB nStartTab
= aRange
.aStart
.Tab();
1593 SCCOL nEndCol
= aRange
.aEnd
.Col();
1594 SCROW nEndRow
= aRange
.aEnd
.Row();
1595 SCTAB nEndTab
= aRange
.aEnd
.Tab();
1597 if (!pDoc
->GetClipParam().isMultiRange() && nStartTab
== nEndTab
)
1598 pDoc
->ShrinkToDataArea( nStartTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
1602 bool bConvertLF
= (GetSystemLineEnd() != LINEEND_LF
);
1604 for (nRow
= nStartRow
; nRow
<= nEndRow
; nRow
++)
1606 if (bIncludeFiltered
|| !pDoc
->RowFiltered( nRow
, nStartTab
))
1608 for (nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
1611 pDoc
->GetCellType( nCol
, nRow
, nStartTab
, eType
);
1614 case CELLTYPE_FORMULA
:
1618 pDoc
->GetFormula( nCol
, nRow
, nStartTab
, aCell
);
1619 if( aCell
.Search( cSep
) != STRING_NOTFOUND
)
1620 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1622 lcl_WriteSimpleString( rStrm
, aCell
);
1626 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1628 bool bMultiLineText
= ( aCell
.Search( '\n' ) != STRING_NOTFOUND
);
1629 if( bMultiLineText
)
1631 if( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSpace
)
1632 aCell
.SearchAndReplaceAll( '\n', ' ' );
1633 else if ( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSystem
&& bConvertLF
)
1634 aCell
= convertLineEnd(aCell
, GetSystemLineEnd());
1637 if( mExportTextOptions
.mcSeparatorConvertTo
&& cSep
)
1638 aCell
.SearchAndReplaceAll( cSep
, mExportTextOptions
.mcSeparatorConvertTo
);
1640 if( mExportTextOptions
.mbAddQuotes
&& ( aCell
.Search( cSep
) != STRING_NOTFOUND
) )
1641 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1643 lcl_WriteSimpleString( rStrm
, aCell
);
1647 case CELLTYPE_VALUE
:
1649 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1650 lcl_WriteSimpleString( rStrm
, aCell
);
1657 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1659 bool bMultiLineText
= ( aCell
.Search( '\n' ) != STRING_NOTFOUND
);
1660 if( bMultiLineText
)
1662 if( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSpace
)
1663 aCell
.SearchAndReplaceAll( '\n', ' ' );
1664 else if ( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSystem
&& bConvertLF
)
1665 aCell
= convertLineEnd(aCell
, GetSystemLineEnd());
1668 if( mExportTextOptions
.mcSeparatorConvertTo
&& cSep
)
1669 aCell
.SearchAndReplaceAll( cSep
, mExportTextOptions
.mcSeparatorConvertTo
);
1671 if( mExportTextOptions
.mbAddQuotes
&& hasLineBreaksOrSeps(aCell
, cSep
) )
1672 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1674 lcl_WriteSimpleString( rStrm
, aCell
);
1677 if( nCol
< nEndCol
)
1678 lcl_WriteSimpleString( rStrm
, OUString(cSep
) );
1680 WriteUnicodeOrByteEndl( rStrm
);
1681 if( rStrm
.GetError() != SVSTREAM_OK
)
1683 if( nSizeLimit
&& rStrm
.Tell() > nSizeLimit
)
1688 return rStrm
.GetError() == SVSTREAM_OK
;
1692 bool ScImportExport::Sylk2Doc( SvStream
& rStrm
)
1695 bool bMyDoc
= false;
1696 SylkVersion eVersion
= SYLK_OTHER
;
1698 // US-English separators for StringToDouble
1699 sal_Unicode cDecSep
= '.';
1700 sal_Unicode cGrpSep
= ',';
1702 SCCOL nStartCol
= aRange
.aStart
.Col();
1703 SCROW nStartRow
= aRange
.aStart
.Row();
1704 SCCOL nEndCol
= aRange
.aEnd
.Col();
1705 SCROW nEndRow
= aRange
.aEnd
.Row();
1706 sal_uLong nOldPos
= rStrm
.Tell();
1707 bool bData
= !bSingle
;
1708 ::std::vector
< sal_uInt32
> aFormats
;
1718 SCCOL nCol
= nStartCol
;
1719 SCROW nRow
= nStartRow
;
1722 rStrm
.Seek( nOldPos
);
1726 rStrm
.ReadLine( aByteLine
);
1727 aLine
= OStringToOUString(aByteLine
, rStrm
.GetStreamCharSet());
1730 const sal_Unicode
* p
= aLine
.GetBuffer();
1731 sal_Unicode cTag
= *p
++;
1732 if( cTag
== 'C' ) // Content
1738 sal_Unicode ch
= *p
++;
1739 ch
= ScGlobal::ToUpperAlpha( ch
);
1743 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1746 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
1749 nRefCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1752 nRefRow
= OUString(p
).toInt32() + nStartRow
- 1;
1757 ( nCol
< nStartCol
|| nCol
> nEndCol
1758 || nRow
< nStartRow
|| nRow
> nEndRow
1759 || nCol
> MAXCOL
|| nRow
> MAXROW
) )
1763 if( nRow
> nEndRow
)
1765 if( nCol
> nEndCol
)
1774 p
= lcl_ScanSylkString( p
, aText
, eVersion
);
1778 const sal_Unicode
* q
= p
;
1779 while( *q
&& *q
!= ';' )
1781 if ( !(*q
== ';' && *(q
+1) == 'I') )
1782 { // don't ignore value
1785 pDoc
->EnsureTable(aRange
.aStart
.Tab());
1787 ScAddress(nCol
, nRow
, aRange
.aStart
.Tab()), aText
);
1791 double fVal
= rtl_math_uStringToDouble( p
,
1792 aLine
.GetBuffer() + aLine
.Len(),
1793 cDecSep
, cGrpSep
, NULL
, NULL
);
1794 pDoc
->SetValue( nCol
, nRow
, aRange
.aStart
.Tab(), fVal
);
1804 if ( nRefCol
< nCol
)
1806 if ( nRefRow
< nRow
)
1810 if( nRefRow
> nEndRow
)
1812 if( nRefCol
> nEndCol
)
1816 if( !bMyDoc
|| !bData
)
1819 p
= lcl_ScanSylkFormula( p
, aText
, eVersion
);
1820 ScAddress
aPos( nCol
, nRow
, aRange
.aStart
.Tab() );
1821 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1822 * end it probably should be GRAM_ODFF_R1C1, since
1823 * R1C1 is what Excel writes in SYLK. */
1824 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_PODF_A1
;
1825 ScCompiler
aComp( pDoc
, aPos
);
1826 aComp
.SetGrammar(eGrammar
);
1827 ScTokenArray
* pCode
= aComp
.CompileString( aText
);
1831 aMark
.SelectTable( aPos
.Tab(), true );
1832 pDoc
->InsertMatrixFormula( nCol
, nRow
, nRefCol
,
1833 nRefRow
, aMark
, EMPTY_STRING
, pCode
);
1837 ScFormulaCell
* pFCell
= new ScFormulaCell(
1838 pDoc
, aPos
, pCode
, eGrammar
, MM_NONE
);
1839 pDoc
->SetFormulaCell(aPos
, pFCell
);
1841 delete pCode
; // ctor/InsertMatrixFormula did copy TokenArray
1845 while( *p
&& *p
!= ';' )
1851 else if( cTag
== 'F' ) // Format
1855 sal_Int32 nFormat
= -1;
1858 sal_Unicode ch
= *p
++;
1859 ch
= ScGlobal::ToUpperAlpha( ch
);
1863 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1866 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
1871 // F;P<n> sets format code of P;P<code> at
1872 // current position, or at ;X;Y if specified.
1873 // Note that ;X;Y may appear after ;P
1874 const sal_Unicode
* p0
= p
;
1875 while( *p
&& *p
!= ';' )
1877 OUString
aNumber(p0
, p
- p0
);
1878 nFormat
= aNumber
.toInt32();
1882 while( *p
&& *p
!= ';' )
1889 if( nRow
> nEndRow
)
1891 if( nCol
> nEndCol
)
1894 if ( 0 <= nFormat
&& nFormat
< (sal_Int32
)aFormats
.size() )
1896 sal_uInt32 nKey
= aFormats
[nFormat
];
1897 pDoc
->ApplyAttr( nCol
, nRow
, aRange
.aStart
.Tab(),
1898 SfxUInt32Item( ATTR_VALUE_FORMAT
, nKey
) );
1901 else if( cTag
== 'P' )
1903 if ( bData
&& *p
== ';' && *(p
+1) == 'P' )
1905 OUString
aCode( p
+2 );
1906 // unescape doubled semicolons
1907 aCode
= aCode
.replaceAll(";;", ";");
1908 // get rid of Xcl escape characters
1909 aCode
= aCode
.replaceAll(OUString(static_cast<sal_Unicode
>(0x1b)), OUString());
1910 sal_Int32 nCheckPos
;
1913 pDoc
->GetFormatTable()->PutandConvertEntry( aCode
, nCheckPos
, nType
, nKey
,
1914 LANGUAGE_ENGLISH_US
, ScGlobal::eLnge
);
1917 aFormats
.push_back( nKey
);
1920 else if( cTag
== 'I' && *p
== 'D' )
1922 aLine
.Erase( 0, 4 );
1923 if (aLine
.EqualsAscii( "CALCOOO32" ))
1924 eVersion
= SYLK_OOO32
;
1925 else if (aLine
.EqualsAscii( "SCALC3" ))
1926 eVersion
= SYLK_SCALC3
;
1927 bMyDoc
= (eVersion
<= SYLK_OWN
);
1929 else if( cTag
== 'E' ) // Ende
1934 aRange
.aEnd
.SetCol( nEndCol
);
1935 aRange
.aEnd
.SetRow( nEndRow
);
1948 bool ScImportExport::Doc2Sylk( SvStream
& rStrm
)
1952 SCCOL nStartCol
= aRange
.aStart
.Col();
1953 SCROW nStartRow
= aRange
.aStart
.Row();
1954 SCCOL nEndCol
= aRange
.aEnd
.Col();
1955 SCROW nEndRow
= aRange
.aEnd
.Row();
1958 lcl_WriteSimpleString( rStrm
,
1959 String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
1960 WriteUnicodeOrByteEndl( rStrm
);
1962 for (nRow
= nStartRow
; nRow
<= nEndRow
; nRow
++)
1964 for (nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
1969 SCROW r
= nRow
- nStartRow
+ 1;
1970 SCCOL c
= nCol
- nStartCol
+ 1;
1971 ScRefCellValue aCell
;
1972 aCell
.assign(*pDoc
, ScAddress(nCol
, nRow
, aRange
.aStart
.Tab()));
1973 CellType eType
= aCell
.meType
;
1976 case CELLTYPE_FORMULA
:
1978 if( pDoc
->HasValueData( nCol
, nRow
, aRange
.aStart
.Tab()) )
1983 case CELLTYPE_VALUE
:
1985 pDoc
->GetValue( nCol
, nRow
, aRange
.aStart
.Tab(), nVal
);
1987 aValStr
= ::rtl::math::doubleToUString( nVal
,
1988 rtl_math_StringFormat_Automatic
,
1989 rtl_math_DecimalPlaces_Max
, '.', true );
1991 aBufStr
.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1992 aBufStr
+= OUString::number( c
);
1993 aBufStr
.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1994 aBufStr
+= OUString::number( r
);
1995 aBufStr
.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1997 lcl_WriteSimpleString( rStrm
, aBufStr
);
2000 case CELLTYPE_STRING
:
2003 aCellStr
= pDoc
->GetString(nCol
, nRow
, aRange
.aStart
.Tab());
2004 aCellStr
.SearchAndReplaceAll( OUString('\n'), OUString(SYLK_LF
) );
2006 aBufStr
.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
2007 aBufStr
+= OUString::number( c
);
2008 aBufStr
.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
2009 aBufStr
+= OUString::number( r
);
2010 aBufStr
.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
2011 lcl_WriteSimpleString( rStrm
, aBufStr
);
2012 lcl_WriteString( rStrm
, aCellStr
, '"', ';' );
2017 const ScFormulaCell
* pFCell
= aCell
.mpFormula
;
2018 switch ( pFCell
->GetMatrixFlag() )
2024 OUString aOUCellStr
;
2025 pFCell
->GetFormula( aOUCellStr
,formula::FormulaGrammar::GRAM_PODF_A1
);
2026 aCellStr
= aOUCellStr
;
2027 /* FIXME: do we want GRAM_ODFF_A1 instead? At
2028 * the end it probably should be
2029 * GRAM_ODFF_R1C1, since R1C1 is what Excel
2030 * writes in SYLK. */
2032 if ( pFCell
->GetMatrixFlag() != MM_NONE
&&
2033 aCellStr
.Len() > 2 &&
2034 aCellStr
.GetChar(0) == '{' &&
2035 aCellStr
.GetChar(aCellStr
.Len()-1) == '}' )
2036 { // cut off matrix {} characters
2037 aCellStr
.Erase(aCellStr
.Len()-1,1);
2038 aCellStr
.Erase(0,1);
2040 if ( aCellStr
.GetChar(0) == '=' )
2041 aCellStr
.Erase(0,1);
2043 switch ( pFCell
->GetMatrixFlag() )
2046 { // diff expression with 'M' M$-extension
2049 pFCell
->GetMatColsRows( nC
, nR
);
2052 aPrefix
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
2053 aPrefix
+= OUString::number( nR
);
2054 aPrefix
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
2055 aPrefix
+= OUString::number( nC
);
2056 aPrefix
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
2060 { // diff expression with 'I' M$-extension
2062 pFCell
->GetMatrixOrigin( aPos
);
2063 aPrefix
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
2064 aPrefix
+= OUString::number( aPos
.Row() - nStartRow
+ 1 );
2065 aPrefix
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
2066 aPrefix
+= OUString::number( aPos
.Col() - nStartCol
+ 1 );
2070 // formula Expression
2071 aPrefix
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
2073 lcl_WriteSimpleString( rStrm
, aPrefix
);
2074 if ( aCellStr
.Len() )
2075 lcl_WriteString( rStrm
, aCellStr
, 0, ';' );
2077 WriteUnicodeOrByteEndl( rStrm
);
2082 // added to avoid warnings
2087 lcl_WriteSimpleString( rStrm
, OUString( 'E' ) );
2088 WriteUnicodeOrByteEndl( rStrm
);
2089 return rStrm
.GetError() == SVSTREAM_OK
;
2093 bool ScImportExport::Doc2HTML( SvStream
& rStrm
, const String
& rBaseURL
)
2095 // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
2096 ScFormatFilter::Get().ScExportHTML( rStrm
, rBaseURL
, pDoc
, aRange
, RTL_TEXTENCODING_DONTKNOW
, bAll
,
2097 aStreamPath
, aNonConvertibleChars
);
2098 return rStrm
.GetError() == SVSTREAM_OK
;
2101 bool ScImportExport::Doc2RTF( SvStream
& rStrm
)
2103 // CharSet is ignored in ScExportRTF
2104 ScFormatFilter::Get().ScExportRTF( rStrm
, pDoc
, aRange
, RTL_TEXTENCODING_DONTKNOW
);
2105 return rStrm
.GetError() == SVSTREAM_OK
;
2109 bool ScImportExport::Doc2Dif( SvStream
& rStrm
)
2111 // for DIF in the clipboard, IBM_850 is always used
2112 ScFormatFilter::Get().ScExportDif( rStrm
, pDoc
, aRange
, RTL_TEXTENCODING_IBM_850
);
2117 bool ScImportExport::Dif2Doc( SvStream
& rStrm
)
2119 SCTAB nTab
= aRange
.aStart
.Tab();
2120 ScDocument
* pImportDoc
= new ScDocument( SCDOCMODE_UNDO
);
2121 pImportDoc
->InitUndo( pDoc
, nTab
, nTab
);
2123 // for DIF in the clipboard, IBM_850 is always used
2124 ScFormatFilter::Get().ScImportDif( rStrm
, pImportDoc
, aRange
.aStart
, RTL_TEXTENCODING_IBM_850
);
2128 pImportDoc
->GetCellArea( nTab
, nEndCol
, nEndRow
);
2129 // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2130 if ( nEndCol
< aRange
.aStart
.Col() )
2131 nEndCol
= aRange
.aStart
.Col();
2132 if ( nEndRow
< aRange
.aStart
.Row() )
2133 nEndRow
= aRange
.aStart
.Row();
2134 aRange
.aEnd
= ScAddress( nEndCol
, nEndRow
, nTab
);
2136 bool bOk
= StartPaste();
2139 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2140 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2141 pImportDoc
->CopyToDocument( aRange
, nFlags
, false, pDoc
);
2151 bool ScImportExport::RTF2Doc( SvStream
& rStrm
, const String
& rBaseURL
)
2153 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateRTFImport( pDoc
, aRange
);
2156 pImp
->Read( rStrm
, rBaseURL
);
2157 aRange
= pImp
->GetRange();
2159 bool bOk
= StartPaste();
2162 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2163 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2164 pImp
->WriteToDocument();
2172 bool ScImportExport::HTML2Doc( SvStream
& rStrm
, const String
& rBaseURL
)
2174 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateHTMLImport( pDoc
, rBaseURL
, aRange
, true);
2177 pImp
->Read( rStrm
, rBaseURL
);
2178 aRange
= pImp
->GetRange();
2180 bool bOk
= StartPaste();
2183 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2184 // a Draw Layer but no Draw View -> create Draw Layer and View here
2186 pDocSh
->MakeDrawLayer();
2188 sal_uInt16 nFlags
= IDF_ALL
& ~IDF_STYLES
;
2189 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2193 // Pick up import options if available.
2194 LanguageType eLang
= pExtOptions
->GetLanguage();
2195 SvNumberFormatter
aNumFormatter( comphelper::getComponentContext(pDoc
->GetServiceManager()), eLang
);
2196 bool bSpecialNumber
= pExtOptions
->IsDetectSpecialNumber();
2197 pImp
->WriteToDocument(false, 1.0, &aNumFormatter
, bSpecialNumber
);
2200 // Regular import, with no options.
2201 pImp
->WriteToDocument();
2209 #ifndef DISABLE_DYNLOADING
2211 #define RETURN_ERROR { return eERR_INTERN; }
2212 class ScFormatFilterMissing
: public ScFormatFilterPlugin
{
2214 ScFormatFilterMissing()
2216 OSL_FAIL("Missing file filters");
2218 virtual ~ScFormatFilterMissing() {}
2219 virtual FltError
ScImportLotus123( SfxMedium
&, ScDocument
*, CharSet
) RETURN_ERROR
2220 virtual FltError
ScImportQuattroPro( SfxMedium
&, ScDocument
* ) RETURN_ERROR
2221 virtual FltError
ScImportExcel( SfxMedium
&, ScDocument
*, const EXCIMPFORMAT
) RETURN_ERROR
2222 virtual FltError
ScImportStarCalc10( SvStream
&, ScDocument
* ) RETURN_ERROR
2223 virtual FltError
ScImportDif( SvStream
&, ScDocument
*, const ScAddress
&,
2224 const CharSet
, sal_uInt32
) RETURN_ERROR
2225 virtual FltError
ScImportRTF( SvStream
&, const String
&, ScDocument
*, ScRange
& ) RETURN_ERROR
2226 virtual FltError
ScImportHTML( SvStream
&, const String
&, ScDocument
*, ScRange
&, double, bool, SvNumberFormatter
*, bool ) RETURN_ERROR
2228 virtual ScEEAbsImport
*CreateRTFImport( ScDocument
*, const ScRange
& ) { return NULL
; }
2229 virtual ScEEAbsImport
*CreateHTMLImport( ScDocument
*, const String
&, const ScRange
&, bool ) { return NULL
; }
2230 virtual String
GetHTMLRangeNameList( ScDocument
*, const String
& ) { return String(); }
2232 virtual FltError
ScExportExcel5( SfxMedium
&, ScDocument
*, ExportFormatExcel
, CharSet
) RETURN_ERROR
2233 virtual FltError
ScExportDif( SvStream
&, ScDocument
*, const ScAddress
&, const CharSet
, sal_uInt32
) RETURN_ERROR
2234 virtual FltError
ScExportDif( SvStream
&, ScDocument
*, const ScRange
&, const CharSet
, sal_uInt32
) RETURN_ERROR
2235 virtual FltError
ScExportHTML( SvStream
&, const String
&, ScDocument
*, const ScRange
&, const CharSet
, bool,
2236 const String
&, String
& ) RETURN_ERROR
2237 virtual FltError
ScExportRTF( SvStream
&, ScDocument
*, const ScRange
&, const CharSet
) RETURN_ERROR
2239 virtual ScOrcusFilters
* GetOrcusFilters() { return NULL
; }
2242 extern "C" { static void SAL_CALL
thisModule() {} }
2247 ScFormatFilterPlugin
* ScFilterCreate();
2252 typedef ScFormatFilterPlugin
* (*FilterFn
)(void);
2253 ScFormatFilterPlugin
&ScFormatFilter::Get()
2255 static ScFormatFilterPlugin
*plugin
;
2260 #ifndef DISABLE_DYNLOADING
2261 OUString
sFilterLib(SVLIBRARY("scfilt"));
2262 static ::osl::Module aModule
;
2263 bool bLoaded
= aModule
.loadRelative(&thisModule
, sFilterLib
);
2265 bLoaded
= aModule
.load(sFilterLib
);
2268 oslGenericFunction fn
= aModule
.getFunctionSymbol( OUString( "ScFilterCreate" ) );
2270 plugin
= reinterpret_cast<FilterFn
>(fn
)();
2273 plugin
= new ScFormatFilterMissing();
2275 plugin
= ScFilterCreate();
2281 // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2283 static inline const sal_Unicode
* lcl_UnicodeStrChr( const sal_Unicode
* pStr
,
2295 OUString
ReadCsvLine( SvStream
&rStream
, bool bEmbeddedLineBreak
,
2296 const String
& rFieldSeparators
, sal_Unicode cFieldQuote
)
2299 rStream
.ReadUniOrByteStringLine(aStr
, rStream
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
2301 if (bEmbeddedLineBreak
)
2303 const sal_Unicode
* pSeps
= rFieldSeparators
.GetBuffer();
2305 QuoteType eQuoteState
= FIELDEND_QUOTE
;
2306 bool bFieldStart
= true;
2308 sal_Int32 nLastOffset
= 0;
2309 sal_Int32 nQuotes
= 0;
2310 while (!rStream
.IsEof() && aStr
.getLength() < nArbitraryLineLengthLimit
)
2312 const sal_Unicode
*p
, *pStart
;
2313 p
= pStart
= aStr
.getStr();
2319 if (*p
== cFieldQuote
)
2324 bFieldStart
= false;
2325 eQuoteState
= FIELDSTART_QUOTE
;
2327 // Do not detect a FIELDSTART_QUOTE if not in
2328 // bFieldStart mode, in which case for unquoted content
2329 // we are in FIELDEND_QUOTE state.
2330 else if (eQuoteState
!= FIELDEND_QUOTE
)
2332 eQuoteState
= lcl_isEscapedOrFieldEndQuote( nQuotes
, p
, pSeps
, cFieldQuote
);
2333 // DONTKNOW_QUOTE is an embedded unescaped quote we
2334 // don't count for pairing.
2335 if (eQuoteState
!= DONTKNOW_QUOTE
)
2339 else if (eQuoteState
== FIELDEND_QUOTE
)
2342 // If blank is a separator it starts a field, if it
2343 // is not and thus maybe leading before quote we
2344 // are still at start of field regarding quotes.
2345 bFieldStart
= (*p
== ' ' || lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2347 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2352 if (*p
== cFieldQuote
&& bFieldStart
)
2355 eQuoteState
= FIELDSTART_QUOTE
;
2356 bFieldStart
= false;
2358 else if (eQuoteState
== FIELDEND_QUOTE
)
2360 // This also skips leading blanks at beginning of line
2361 // if followed by a quote. It's debatable whether we
2362 // actually want that or not, but congruent with what
2363 // ScanNextFieldFromString() does.
2365 bFieldStart
= (*p
== ' ' || lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2367 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2370 // A quote character inside a field content does not start
2375 if (nQuotes
% 2 == 0)
2376 // We still have a (theoretical?) problem here if due to
2377 // nArbitraryLineLengthLimit we split a string right between a
2378 // doubled quote pair.
2382 nLastOffset
= aStr
.getLength();
2384 rStream
.ReadUniOrByteStringLine(aNext
, rStream
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
2385 aStr
+= OUString( sal_Unicode('\n'));
2393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */