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 #include <boost/scoped_ptr.hpp>
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
* 65536;
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.
81 // Whole document without Undo
82 ScImportExport::ScImportExport( ScDocument
* p
)
83 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
84 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
85 bFormulas( false ), bIncludeFiltered( true ),
86 bAll( true ), bSingle( true ), bUndo( false ),
87 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
88 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
95 // Insert am current cell without range(es)
96 ScImportExport::ScImportExport( ScDocument
* p
, const ScAddress
& rPt
)
97 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
99 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
100 bFormulas( false ), bIncludeFiltered( true ),
101 bAll( false ), bSingle( true ), bUndo( pDocSh
!= NULL
),
102 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
103 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
110 // ctor with a range is only used for export
111 //! ctor with a string (and bSingle=true) is also used for DdeSetData
112 ScImportExport::ScImportExport( ScDocument
* p
, const ScRange
& r
)
113 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
115 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
116 bFormulas( false ), bIncludeFiltered( true ),
117 bAll( false ), bSingle( false ), bUndo( pDocSh
!= NULL
),
118 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
119 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
124 // Only one sheet (table) supported
125 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() );
128 // Evaluate input string - either range, cell or the whole document (when error)
129 // If a View exists, the TabNo of the view will be used.
130 ScImportExport::ScImportExport( ScDocument
* p
, const OUString
& rPos
)
131 : pDocSh( PTR_CAST(ScDocShell
,p
->GetDocumentShell()) ), pDoc( p
),
132 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
133 bFormulas( false ), bIncludeFiltered( true ),
134 bAll( false ), bSingle( true ), bUndo( pDocSh
!= NULL
),
135 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
136 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
142 SCTAB nTab
= ScDocShell::GetCurTab();
143 aRange
.aStart
.SetTab( nTab
);
144 OUString
aPos( rPos
);
146 ScRangeName
* pRange
= pDoc
->GetRangeName();
149 const ScRangeData
* pData
= pRange
->findByUpperName(ScGlobal::pCharClass
->uppercase(aPos
));
152 if( pData
->HasType( RT_REFAREA
)
153 || pData
->HasType( RT_ABSAREA
)
154 || pData
->HasType( RT_ABSPOS
) )
156 pData
->GetSymbol(aPos
);
160 formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
162 if (aRange
.Parse(aPos
, pDoc
, eConv
) & SCA_VALID
)
165 else if (aRange
.aStart
.Parse(aPos
, pDoc
, eConv
) & SCA_VALID
)
166 aRange
.aEnd
= aRange
.aStart
;
171 ScImportExport::~ScImportExport()
177 void ScImportExport::SetExtOptions( const ScAsciiOptions
& rOpt
)
182 pExtOptions
= new ScAsciiOptions( rOpt
);
186 cSep
= ScAsciiOptions::GetWeightedFieldSep( rOpt
.GetFieldSeps(), false);
187 cStr
= rOpt
.GetTextSep();
190 void ScImportExport::SetFilterOptions(const OUString
& rFilterOptions
)
192 maFilterOptions
= rFilterOptions
;
195 bool ScImportExport::IsFormatSupported( SotClipboardFormatId nFormat
)
197 return nFormat
== SotClipboardFormatId::STRING
198 || nFormat
== SotClipboardFormatId::SYLK
199 || nFormat
== SotClipboardFormatId::LINK
200 || nFormat
== SotClipboardFormatId::HTML
201 || nFormat
== SotClipboardFormatId::HTML_SIMPLE
202 || nFormat
== SotClipboardFormatId::DIF
;
206 bool ScImportExport::StartPaste()
210 ScEditableTester
aTester( pDoc
, aRange
);
211 if ( !aTester
.IsEditable() )
213 ScopedVclPtrInstance
<InfoBox
> aInfoBox( Application::GetDefDialogParent(),
214 ScGlobal::GetRscString( aTester
.GetMessageId() ) );
219 if( bUndo
&& pDocSh
&& pDoc
->IsUndoEnabled())
221 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
222 pUndoDoc
->InitUndo( pDoc
, aRange
.aStart
.Tab(), aRange
.aEnd
.Tab() );
223 pDoc
->CopyToDocument( aRange
, IDF_ALL
| IDF_NOCAPTIONS
, false, pUndoDoc
);
228 // Create Undo/Redo actions, Invalidate/Repaint
229 void ScImportExport::EndPaste(bool bAutoRowHeight
)
231 bool bHeight
= bAutoRowHeight
&& pDocSh
&& pDocSh
->AdjustRowHeight(
232 aRange
.aStart
.Row(), aRange
.aEnd
.Row(), aRange
.aStart
.Tab() );
234 if( pUndoDoc
&& pDoc
->IsUndoEnabled() && pDocSh
)
236 ScDocument
* pRedoDoc
= new ScDocument( SCDOCMODE_UNDO
);
237 pRedoDoc
->InitUndo( pDoc
, aRange
.aStart
.Tab(), aRange
.aEnd
.Tab() );
238 pDoc
->CopyToDocument( aRange
, IDF_ALL
| IDF_NOCAPTIONS
, false, pRedoDoc
);
239 ScMarkData aDestMark
;
240 aDestMark
.SetMarkArea(aRange
);
241 pDocSh
->GetUndoManager()->AddUndoAction(
242 new ScUndoPaste(pDocSh
, aRange
, aDestMark
, pUndoDoc
, pRedoDoc
, IDF_ALL
, NULL
));
248 pDocSh
->PostPaint( aRange
, PAINT_GRID
);
249 pDocSh
->SetDocumentModified();
251 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
253 pViewSh
->UpdateInputHandler();
257 bool ScImportExport::ImportData( const OUString
& /* rMimeType */,
258 const ::com::sun::star::uno::Any
& /* rValue */ )
260 OSL_ENSURE( false, "Implementation is missing" );
264 bool ScImportExport::ExportData( const OUString
& rMimeType
,
265 ::com::sun::star::uno::Any
& rValue
)
267 SvMemoryStream aStrm
;
268 // mba: no BaseURL for data exchange
269 if( ExportStream( aStrm
, OUString(),
270 SotExchange::GetFormatIdFromMimeType( rMimeType
) ))
272 aStrm
.WriteUChar( 0 );
273 rValue
<<= ::com::sun::star::uno::Sequence
< sal_Int8
>(
274 static_cast<sal_Int8
const *>(aStrm
.GetData()),
275 aStrm
.Seek( STREAM_SEEK_TO_END
) );
281 bool ScImportExport::ImportString( const OUString
& rText
, SotClipboardFormatId nFmt
)
285 // formats supporting unicode
286 case SotClipboardFormatId::STRING
:
288 ScImportStringStream
aStrm( rText
);
289 return ImportStream( aStrm
, OUString(), nFmt
);
290 // ImportStream must handle RTL_TEXTENCODING_UNICODE
294 rtl_TextEncoding eEnc
= osl_getThreadTextEncoding();
295 OString
aTmp( rText
.getStr(), rText
.getLength(), eEnc
);
296 SvMemoryStream
aStrm( (void*)aTmp
.getStr(), aTmp
.getLength() * sizeof(sal_Char
), StreamMode::READ
);
297 aStrm
.SetStreamCharSet( eEnc
);
298 SetNoEndianSwap( aStrm
); //! no swapping in memory
299 return ImportStream( aStrm
, OUString(), nFmt
);
304 bool ScImportExport::ExportString( OUString
& rText
, SotClipboardFormatId nFmt
)
306 OSL_ENSURE( nFmt
== SotClipboardFormatId::STRING
, "ScImportExport::ExportString: Unicode not supported for other formats than SotClipboardFormatId::STRING" );
307 if ( nFmt
!= SotClipboardFormatId::STRING
)
309 rtl_TextEncoding eEnc
= osl_getThreadTextEncoding();
311 bool bOk
= ExportByteString( aTmp
, eEnc
, nFmt
);
312 rText
= OStringToOUString( aTmp
, eEnc
);
315 // nSizeLimit not needed for OUString
317 SvMemoryStream aStrm
;
318 aStrm
.SetStreamCharSet( RTL_TEXTENCODING_UNICODE
);
319 SetNoEndianSwap( aStrm
); //! no swapping in memory
320 // mba: no BaseURL for data exc
321 if( ExportStream( aStrm
, OUString(), nFmt
) )
323 aStrm
.WriteUInt16( 0 );
324 aStrm
.Seek( STREAM_SEEK_TO_END
);
326 rText
= OUString( static_cast<const sal_Unicode
*>(aStrm
.GetData()) );
332 // ExportStream must handle RTL_TEXTENCODING_UNICODE
335 bool ScImportExport::ExportByteString( OString
& rText
, rtl_TextEncoding eEnc
, SotClipboardFormatId nFmt
)
337 OSL_ENSURE( eEnc
!= RTL_TEXTENCODING_UNICODE
, "ScImportExport::ExportByteString: Unicode not supported" );
338 if ( eEnc
== RTL_TEXTENCODING_UNICODE
)
339 eEnc
= osl_getThreadTextEncoding();
342 nSizeLimit
= SAL_MAX_UINT16
;
344 SvMemoryStream aStrm
;
345 aStrm
.SetStreamCharSet( eEnc
);
346 SetNoEndianSwap( aStrm
); //! no swapping in memory
347 // mba: no BaseURL for data exchange
348 if( ExportStream( aStrm
, OUString(), nFmt
) )
350 aStrm
.WriteChar( 0 );
351 aStrm
.Seek( STREAM_SEEK_TO_END
);
352 if( aStrm
.Tell() <= nSizeLimit
)
354 rText
= static_cast<const sal_Char
*>(aStrm
.GetData());
362 bool ScImportExport::ImportStream( SvStream
& rStrm
, const OUString
& rBaseURL
, SotClipboardFormatId nFmt
)
364 if( nFmt
== SotClipboardFormatId::STRING
)
366 if( ExtText2Doc( rStrm
) ) // evaluate pExtOptions
369 if( nFmt
== SotClipboardFormatId::SYLK
)
371 if( Sylk2Doc( rStrm
) )
374 if( nFmt
== SotClipboardFormatId::DIF
)
376 if( Dif2Doc( rStrm
) )
379 if( nFmt
== SotClipboardFormatId::RTF
)
381 if( RTF2Doc( rStrm
, rBaseURL
) )
384 if( nFmt
== SotClipboardFormatId::LINK
)
385 return true; // Link-Import?
386 if ( nFmt
== SotClipboardFormatId::HTML
)
388 if( HTML2Doc( rStrm
, rBaseURL
) )
391 if ( nFmt
== SotClipboardFormatId::HTML_SIMPLE
)
393 MSE40HTMLClipFormatObj aMSE40ClpObj
; // needed to skip the header data
394 SvStream
* pHTML
= aMSE40ClpObj
.IsValid( rStrm
);
395 if ( pHTML
&& HTML2Doc( *pHTML
, rBaseURL
) )
402 bool ScImportExport::ExportStream( SvStream
& rStrm
, const OUString
& rBaseURL
, SotClipboardFormatId nFmt
)
404 if( nFmt
== SotClipboardFormatId::STRING
)
406 if( Doc2Text( rStrm
) )
409 if( nFmt
== SotClipboardFormatId::SYLK
)
411 if( Doc2Sylk( rStrm
) )
414 if( nFmt
== SotClipboardFormatId::DIF
)
416 if( Doc2Dif( rStrm
) )
419 if( nFmt
== SotClipboardFormatId::LINK
&& !bAll
)
422 if ( pDoc
->IsClipboard() )
423 aDocName
= ScGlobal::GetClipDocName();
426 SfxObjectShell
* pShell
= pDoc
->GetDocumentShell();
428 aDocName
= pShell
->GetTitle( SFX_TITLE_FULLNAME
);
431 OSL_ENSURE( !aDocName
.isEmpty(), "ClipBoard document has no name! :-/" );
432 if( !aDocName
.isEmpty() )
434 // Always use Calc A1 syntax for paste link.
436 sal_uInt16 nFlags
= SCA_VALID
| SCA_TAB_3D
;
438 aRefName
= aRange
.aStart
.Format(nFlags
, pDoc
, formula::FormulaGrammar::CONV_OOO
);
441 if( aRange
.aStart
.Tab() != aRange
.aEnd
.Tab() )
442 nFlags
|= SCA_TAB2_3D
;
443 aRefName
= aRange
.Format(nFlags
, pDoc
, formula::FormulaGrammar::CONV_OOO
);
445 OUString aAppName
= Application::GetAppName();
447 // extra bits are used to tell the client to prefer external
449 OUString
aExtraBits("calc:extref");
451 WriteUnicodeOrByteString( rStrm
, aAppName
, true );
452 WriteUnicodeOrByteString( rStrm
, aDocName
, true );
453 WriteUnicodeOrByteString( rStrm
, aRefName
, true );
454 WriteUnicodeOrByteString( rStrm
, aExtraBits
, true );
455 if ( rStrm
.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE
)
456 rStrm
.WriteUInt16( 0 );
458 rStrm
.WriteChar( 0 );
459 return rStrm
.GetError() == SVSTREAM_OK
;
462 if( nFmt
== SotClipboardFormatId::HTML
)
464 if( Doc2HTML( rStrm
, rBaseURL
) )
467 if( nFmt
== SotClipboardFormatId::RTF
)
469 if( Doc2RTF( rStrm
) )
476 void ScImportExport::WriteUnicodeOrByteString( SvStream
& rStrm
, const OUString
& rString
, bool bZero
)
478 rtl_TextEncoding eEnc
= rStrm
.GetStreamCharSet();
479 if ( eEnc
== RTL_TEXTENCODING_UNICODE
)
481 if ( !IsEndianSwap( rStrm
) )
482 rStrm
.Write( rString
.getStr(), rString
.getLength() * sizeof(sal_Unicode
) );
485 const sal_Unicode
* p
= rString
.getStr();
486 const sal_Unicode
* const pStop
= p
+ rString
.getLength();
489 rStrm
.WriteUInt16( *p
);
493 rStrm
.WriteUInt16( 0 );
497 OString
aByteStr(OUStringToOString(rString
, eEnc
));
498 rStrm
.WriteCharPtr( aByteStr
.getStr() );
500 rStrm
.WriteChar( 0 );
504 // This function could be replaced by endlub()
505 void ScImportExport::WriteUnicodeOrByteEndl( SvStream
& rStrm
)
507 if ( rStrm
.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE
)
508 { // same as endl() but unicode
509 switch ( rStrm
.GetLineDelimiter() )
512 rStrm
.WriteUInt16( '\r' );
515 rStrm
.WriteUInt16( '\n' );
518 rStrm
.WriteUInt16( '\r' ).WriteUInt16( '\n' );
534 /** Determine if *p is a quote that ends a quoted field.
536 Precondition: we are parsing a quoted field already and *p is a quote.
539 FIELDEND_QUOTE if end of field quote
540 DONTKNOW_QUOTE anything else
542 static QuoteType
lcl_isFieldEndQuote( const sal_Unicode
* p
, const sal_Unicode
* pSeps
)
544 // Due to broken CSV generators that don't double embedded quotes check if
545 // a field separator immediately or with trailing spaces follows the quote,
546 // only then end the field, or at end of string.
547 const sal_Unicode cBlank
= ' ';
548 if (p
[1] == cBlank
&& ScGlobal::UnicodeStrChr( pSeps
, cBlank
))
549 return FIELDEND_QUOTE
;
550 while (p
[1] == cBlank
)
552 if (!p
[1] || ScGlobal::UnicodeStrChr( pSeps
, p
[1]))
553 return FIELDEND_QUOTE
;
554 return DONTKNOW_QUOTE
;
557 /** Determine if *p is a quote that is escaped by being doubled or ends a
560 Precondition: *p is a quote.
563 Quote characters encountered so far.
564 Odd (after opening quote) means either no embedded quotes or only quote
566 Even means either not in a quoted field or already one quote
567 encountered, the first of a pair.
570 FIELDSTART_QUOTE if first quote in a field, either starting content or
571 embedded so caller should check beforehand.
572 FIRST_QUOTE if first of a doubled quote
573 SECOND_QUOTE if second of a doubled quote
574 FIELDEND_QUOTE if end of field quote
575 DONTKNOW_QUOTE if an unescaped quote we don't consider as end of field,
576 do not increment nQuotes in caller then!
578 static QuoteType
lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes
, const sal_Unicode
* p
,
579 const sal_Unicode
* pSeps
, sal_Unicode cStr
)
581 if ((nQuotes
% 2) == 0)
587 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
588 return FIELDSTART_QUOTE
;
593 return lcl_isFieldEndQuote( p
, pSeps
);
596 /** Append characters of [p1,p2) to rField.
598 @returns TRUE if ok; FALSE if data overflow, truncated
600 static bool lcl_appendLineData( OUString
& rField
, const sal_Unicode
* p1
, const sal_Unicode
* p2
)
602 OSL_ENSURE( rField
.getLength() + (p2
- p1
) <= SAL_MAX_UINT16
, "lcl_appendLineData: data overflow");
603 if (rField
.getLength() + (p2
- p1
) <= SAL_MAX_UINT16
)
605 rField
+= OUString( p1
, sal::static_int_cast
<sal_Int32
>( p2
- p1
) );
610 rField
+= OUString( p1
, SAL_MAX_UINT16
- rField
.getLength() );
615 enum DoubledQuoteMode
617 DQM_KEEP_ALL
, // both are taken, additionally start and end quote are included in string
618 DQM_KEEP
, // both are taken
619 DQM_ESCAPE
, // escaped quote, one is taken, one ignored
620 DQM_CONCAT
, // first is end, next is start, both ignored => strings combined
621 DQM_SEPARATE
// end one string and begin next
624 static const sal_Unicode
* lcl_ScanString( const sal_Unicode
* p
, OUString
& rString
,
625 const sal_Unicode
* pSeps
, sal_Unicode cStr
, DoubledQuoteMode eMode
, bool& rbOverflowCell
)
627 if (eMode
!= DQM_KEEP_ALL
)
628 p
++; //! jump over opening quote
633 const sal_Unicode
* p0
= p
;
642 // break or continue for loop
643 if (eMode
== DQM_ESCAPE
)
645 if (lcl_isFieldEndQuote( p
-1, pSeps
) == FIELDEND_QUOTE
)
653 // doubled quote char
658 p
++; // both for us (not breaking for-loop)
661 p
++; // one for us (breaking for-loop)
662 bCont
= true; // and more
668 if (!lcl_appendLineData( rString
, p0
, p
-1))
669 rbOverflowCell
= true;
671 p0
= ++p
; // text of next part starts here
674 // positioned on next opening quote
677 if ( eMode
== DQM_ESCAPE
|| eMode
== DQM_SEPARATE
)
685 if (!lcl_appendLineData( rString
, p0
, ((eMode
!= DQM_KEEP_ALL
&& (*p
|| *(p
-1) == cStr
)) ? p
-1 : p
)))
686 rbOverflowCell
= true;
692 static void lcl_UnescapeSylk( OUString
& rString
, SylkVersion eVersion
)
694 // Older versions didn't escape the semicolon.
695 // Older versions quoted the string and doubled embedded quotes, but not
696 // the semicolons, which was plain wrong.
697 if (eVersion
>= SYLK_OOO32
)
698 rString
= rString
.replaceAll( OUString(DOUBLE_SEMICOLON
), OUString(';') );
700 rString
= rString
.replaceAll( OUString(DOUBLE_DOUBLEQUOTE
), OUString('"') );
702 rString
= rString
.replaceAll( OUString(SYLK_LF
), OUString('\n') );
705 static const sal_Unicode
* lcl_ScanSylkString( const sal_Unicode
* p
,
706 OUString
& rString
, SylkVersion eVersion
)
708 const sal_Unicode
* pStartQuote
= p
;
709 const sal_Unicode
* pEndQuote
= 0;
715 if (eVersion
>= SYLK_OOO32
)
721 p
+= 2; // escaped ';'
735 else if (*(p
+1) == ';')
741 pEndQuote
= p
; // Take all data as string.
742 rString
+= OUString(pStartQuote
+ 1, sal::static_int_cast
<sal_Int32
>( pEndQuote
- pStartQuote
- 1 ) );
743 lcl_UnescapeSylk( rString
, eVersion
);
747 static const sal_Unicode
* lcl_ScanSylkFormula( const sal_Unicode
* p
,
748 OUString
& rString
, SylkVersion eVersion
)
750 const sal_Unicode
* pStart
= p
;
751 if (eVersion
>= SYLK_OOO32
)
764 rString
+= OUString( pStart
, sal::static_int_cast
<sal_Int32
>( p
- pStart
));
765 lcl_UnescapeSylk( rString
, eVersion
);
769 // Nasty. If in old versions the formula contained a semicolon, it was
770 // quoted and embedded quotes were doubled, but semicolons were not. If
771 // there was no semicolon, it could still contain quotes and doubled
772 // embedded quotes if it was something like ="a""b", which was saved as
773 // E"a""b" as is and has to be preserved, even if older versions
774 // couldn't even load it correctly. However, theoretically another
775 // field might follow and thus the line contain a semicolon again, such
776 // as ...;E"a""b";...
777 bool bQuoted
= false;
780 // May be a quoted expression or just a string constant expression
789 break; // closing '"', had no ';' yet
793 bQuoted
= true; // ';' within quoted expression
800 p
= lcl_ScanSylkString( p
, rString
, eVersion
);
803 while (*p
&& *p
!= ';')
805 rString
+= OUString( pStart
, sal::static_int_cast
<sal_Int32
>( p
- pStart
));
811 static void lcl_DoubleEscapeChar( OUString
& rString
, sal_Unicode cStr
)
814 while( ( n
= rString
.indexOf( cStr
, n
) ) != -1 )
816 rString
= rString
.replaceAt( n
, 0, OUString(cStr
) );
821 static void lcl_WriteString( SvStream
& rStrm
, OUString
& rString
, sal_Unicode cQuote
, sal_Unicode cEsc
)
824 lcl_DoubleEscapeChar( rString
, cEsc
);
828 rString
= OUString(cQuote
) + rString
+ OUString(cQuote
);
831 ScImportExport::WriteUnicodeOrByteString( rStrm
, rString
);
834 static inline void lcl_WriteSimpleString( SvStream
& rStrm
, const OUString
& rString
)
836 ScImportExport::WriteUnicodeOrByteString( rStrm
, rString
);
839 bool ScImportExport::Text2Doc( SvStream
& rStrm
)
843 sal_Unicode pSeps
[2];
847 SCCOL nStartCol
= aRange
.aStart
.Col();
848 SCROW nStartRow
= aRange
.aStart
.Row();
849 SCCOL nEndCol
= aRange
.aEnd
.Col();
850 SCROW nEndRow
= aRange
.aEnd
.Row();
851 sal_uLong nOldPos
= rStrm
.Tell();
852 rStrm
.StartReadingUnicodeText( rStrm
.GetStreamCharSet() );
853 bool bData
= !bSingle
;
861 SCROW nRow
= nStartRow
;
862 rStrm
.Seek( nOldPos
);
865 rStrm
.ReadUniOrByteStringLine( aLine
, rStrm
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
868 SCCOL nCol
= nStartCol
;
869 const sal_Unicode
* p
= aLine
.getStr();
873 const sal_Unicode
* q
= p
;
874 while (*p
&& *p
!= cSep
)
876 // Always look for a pairing quote and ignore separator in between.
877 while (*p
&& *p
== cStr
)
878 q
= p
= lcl_ScanString( p
, aCell
, pSeps
, cStr
, DQM_KEEP_ALL
, bOverflowCell
);
879 // All until next separator or quote.
880 while (*p
&& *p
!= cSep
&& *p
!= cStr
)
882 if (!lcl_appendLineData( aCell
, q
, p
))
883 bOverflowCell
= true; // display warning on import
888 if (ValidCol(nCol
) && ValidRow(nRow
) )
892 if (nCol
>nEndCol
) nEndCol
= nCol
;
893 if (nRow
>nEndRow
) nEndRow
= nRow
;
895 if( bData
&& nCol
<= nEndCol
&& nRow
<= nEndRow
)
896 pDoc
->SetString( nCol
, nRow
, aRange
.aStart
.Tab(), aCell
);
898 else // zuviele Spalten/Zeilen
901 bOverflowRow
= true; // display warning on import
903 bOverflowCol
= true; // display warning on import
912 aRange
.aEnd
.SetCol( nEndCol
);
913 aRange
.aEnd
.SetRow( nEndRow
);
922 if (bOk
&& mbImportBroadcast
)
924 pDoc
->BroadcastCells(aRange
, SC_HINT_DATACHANGED
);
925 pDocSh
->PostDataChanged();
931 // Extended Ascii-Import
933 static bool lcl_PutString(
934 ScDocumentImport
& rDocImport
, bool bUseDocImport
,
935 SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const OUString
& rStr
, sal_uInt8 nColFormat
,
936 SvNumberFormatter
* pFormatter
, bool bDetectNumFormat
,
937 ::utl::TransliterationWrapper
& rTransliteration
, CalendarWrapper
& rCalendar
,
938 ::utl::TransliterationWrapper
* pSecondTransliteration
, CalendarWrapper
* pSecondCalendar
)
940 ScDocument
* pDoc
= &rDocImport
.getDoc();
941 bool bMultiLine
= false;
942 if ( nColFormat
== SC_COL_SKIP
|| rStr
.isEmpty() || !ValidCol(nCol
) || !ValidRow(nRow
) )
945 if ( nColFormat
== SC_COL_TEXT
)
948 sal_uInt32 nIndex
= 0;
949 if (pFormatter
->IsNumberFormat(rStr
, nIndex
, fDummy
))
951 // Set the format of this cell to Text.
952 sal_uInt32 nFormat
= pFormatter
->GetStandardFormat(css::util::NumberFormat::TEXT
);
953 ScPatternAttr
aNewAttrs(pDoc
->GetPool());
954 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
955 rSet
.Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
) );
956 pDoc
->ApplyPattern(nCol
, nRow
, nTab
, aNewAttrs
);
961 if(ScStringUtil::isMultiline(rStr
))
963 ScFieldEditEngine
& rEngine
= pDoc
->GetEditEngine();
964 rEngine
.SetText(rStr
);
965 rDocImport
.setEditCell(ScAddress(nCol
, nRow
, nTab
), rEngine
.CreateTextObject());
970 rDocImport
.setStringCell(ScAddress(nCol
, nRow
, nTab
), rStr
);
975 pDoc
->SetTextCell(ScAddress(nCol
, nRow
, nTab
), rStr
);
980 if ( nColFormat
== SC_COL_ENGLISH
)
982 //! SetString with Extra-Flag ???
984 SvNumberFormatter
* pDocFormatter
= pDoc
->GetFormatTable();
985 sal_uInt32 nEnglish
= pDocFormatter
->GetStandardIndex(LANGUAGE_ENGLISH_US
);
987 if ( pDocFormatter
->IsNumberFormat( rStr
, nEnglish
, fVal
) )
989 // Numberformat will not be set to English
991 rDocImport
.setNumericCell( ScAddress( nCol
, nRow
, nTab
), fVal
);
993 pDoc
->SetValue( nCol
, nRow
, nTab
, fVal
);
996 // else, continue with SetString
998 else if ( nColFormat
!= SC_COL_STANDARD
) // Datumformats
1000 const sal_uInt16 nMaxNumberParts
= 7; // Y-M-D h:m:s.t
1001 sal_Int32 nLen
= rStr
.getLength();
1002 sal_Int32 nStart
[nMaxNumberParts
];
1003 sal_Int32 nEnd
[nMaxNumberParts
];
1005 sal_uInt16 nDP
, nMP
, nYP
;
1006 switch ( nColFormat
)
1008 case SC_COL_YMD
: nDP
= 2; nMP
= 1; nYP
= 0; break;
1009 case SC_COL_MDY
: nDP
= 1; nMP
= 0; nYP
= 2; break;
1011 default: nDP
= 0; nMP
= 1; nYP
= 2; break;
1014 sal_uInt16 nFound
= 0;
1015 bool bInNum
= false;
1016 for ( sal_Int32 nPos
=0; nPos
<nLen
&& (bInNum
||
1017 nFound
<nMaxNumberParts
); nPos
++ )
1019 if (bInNum
&& nFound
== 3 && nColFormat
== SC_COL_YMD
&&
1020 nPos
<= nStart
[nFound
]+2 && rStr
[nPos
] == 'T')
1021 bInNum
= false; // ISO-8601: YYYY-MM-DDThh:mm...
1022 else if ((((!bInNum
&& nFound
==nMP
) || (bInNum
&& nFound
==nMP
+1))
1023 && ScGlobal::pCharClass
->isLetterNumeric( rStr
, nPos
))
1024 || ScGlobal::pCharClass
->isDigit( rStr
, nPos
))
1029 nStart
[nFound
] = nPos
;
1032 nEnd
[nFound
-1] = nPos
;
1040 // try to break one number (without separators) into date fields
1042 sal_Int32 nDateStart
= nStart
[0];
1043 sal_Int32 nDateLen
= nEnd
[0] + 1 - nDateStart
;
1045 if ( nDateLen
>= 5 && nDateLen
<= 8 &&
1046 ScGlobal::pCharClass
->isNumeric( rStr
.copy( nDateStart
, nDateLen
) ) )
1048 // 6 digits: 2 each for day, month, year
1049 // 8 digits: 4 for year, 2 each for day and month
1050 // 5 or 7 digits: first field is shortened by 1
1052 bool bLongYear
= ( nDateLen
>= 7 );
1053 bool bShortFirst
= ( nDateLen
== 5 || nDateLen
== 7 );
1055 sal_uInt16 nFieldStart
= nDateStart
;
1056 for (sal_uInt16 nPos
=0; nPos
<3; nPos
++)
1058 sal_uInt16 nFieldEnd
= nFieldStart
+ 1; // default: 2 digits
1059 if ( bLongYear
&& nPos
== nYP
)
1060 nFieldEnd
+= 2; // 2 extra digits for long year
1061 if ( bShortFirst
&& nPos
== 0 )
1062 --nFieldEnd
; // first field shortened?
1064 nStart
[nPos
] = nFieldStart
;
1065 nEnd
[nPos
] = nFieldEnd
;
1066 nFieldStart
= nFieldEnd
+ 1;
1074 using namespace ::com::sun::star
;
1075 bool bSecondCal
= false;
1076 sal_uInt16 nDay
= (sal_uInt16
) rStr
.copy( nStart
[nDP
], nEnd
[nDP
]+1-nStart
[nDP
] ).toInt32();
1077 sal_uInt16 nYear
= (sal_uInt16
) rStr
.copy( nStart
[nYP
], nEnd
[nYP
]+1-nStart
[nYP
] ).toInt32();
1078 OUString aMStr
= rStr
.copy( nStart
[nMP
], nEnd
[nMP
]+1-nStart
[nMP
] );
1079 sal_Int16 nMonth
= (sal_Int16
) aMStr
.toInt32();
1082 static const char aSeptCorrect
[] = "SEPT";
1083 static const char aSepShortened
[] = "SEP";
1084 uno::Sequence
< i18n::CalendarItem2
> xMonths
;
1085 sal_Int32 i
, nMonthCount
;
1086 // first test all month names from local international
1087 xMonths
= rCalendar
.getMonths();
1088 nMonthCount
= xMonths
.getLength();
1089 for (i
=0; i
<nMonthCount
&& !nMonth
; i
++)
1091 if ( rTransliteration
.isEqual( aMStr
, xMonths
[i
].FullName
) ||
1092 rTransliteration
.isEqual( aMStr
, xMonths
[i
].AbbrevName
) )
1093 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1094 else if ( i
== 8 && rTransliteration
.isEqual( aSeptCorrect
,
1095 xMonths
[i
].AbbrevName
) &&
1096 rTransliteration
.isEqual( aMStr
, aSepShortened
) )
1097 { // correct English abbreviation is SEPT,
1098 // but data mostly contains SEP only
1099 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1102 // if none found, then test english month names
1103 if ( !nMonth
&& pSecondCalendar
&& pSecondTransliteration
)
1105 xMonths
= pSecondCalendar
->getMonths();
1106 nMonthCount
= xMonths
.getLength();
1107 for (i
=0; i
<nMonthCount
&& !nMonth
; i
++)
1109 if ( pSecondTransliteration
->isEqual( aMStr
, xMonths
[i
].FullName
) ||
1110 pSecondTransliteration
->isEqual( aMStr
, xMonths
[i
].AbbrevName
) )
1112 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1115 else if ( i
== 8 && pSecondTransliteration
->isEqual(
1116 aMStr
, aSepShortened
) )
1117 { // correct English abbreviation is SEPT,
1118 // but data mostly contains SEP only
1119 nMonth
= sal::static_int_cast
<sal_Int16
>( i
+1 );
1126 SvNumberFormatter
* pDocFormatter
= pDoc
->GetFormatTable();
1128 nYear
= pDocFormatter
->ExpandTwoDigitYear( nYear
);
1130 CalendarWrapper
* pCalendar
= (bSecondCal
? pSecondCalendar
: &rCalendar
);
1131 sal_Int16 nNumMonths
= pCalendar
->getNumberOfMonthsInYear();
1132 if ( nDay
&& nMonth
&& nDay
<=31 && nMonth
<=nNumMonths
)
1135 pCalendar
->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH
, nDay
);
1136 pCalendar
->setValue( i18n::CalendarFieldIndex::MONTH
, nMonth
);
1137 pCalendar
->setValue( i18n::CalendarFieldIndex::YEAR
, nYear
);
1138 sal_Int16 nHour
, nMinute
, nSecond
, nMilli
;
1139 // #i14974# The imported value should have no fractional value, so set the
1140 // time fields to zero (ICU calendar instance defaults to current date/time)
1141 nHour
= nMinute
= nSecond
= nMilli
= 0;
1143 nHour
= (sal_Int16
) rStr
.copy( nStart
[3], nEnd
[3]+1-nStart
[3]).toInt32();
1145 nMinute
= (sal_Int16
) rStr
.copy( nStart
[4], nEnd
[4]+1-nStart
[4]).toInt32();
1147 nSecond
= (sal_Int16
) rStr
.copy( nStart
[5], nEnd
[5]+1-nStart
[5]).toInt32();
1150 sal_Unicode cDec
= '.';
1151 OUString
aT( &cDec
, 1);
1152 aT
+= rStr
.copy( nStart
[6], nEnd
[6]+1-nStart
[6]);
1153 rtl_math_ConversionStatus eStatus
;
1154 double fV
= rtl::math::stringToDouble( aT
, cDec
, 0, &eStatus
, 0);
1155 if (eStatus
== rtl_math_ConversionStatus_Ok
)
1156 nMilli
= (sal_Int16
) (1000.0 * fV
+ 0.5);
1158 pCalendar
->setValue( i18n::CalendarFieldIndex::HOUR
, nHour
);
1159 pCalendar
->setValue( i18n::CalendarFieldIndex::MINUTE
, nMinute
);
1160 pCalendar
->setValue( i18n::CalendarFieldIndex::SECOND
, nSecond
);
1161 pCalendar
->setValue( i18n::CalendarFieldIndex::MILLISECOND
, nMilli
);
1162 if ( pCalendar
->isValid() )
1164 double fDiff
= DateTime(*pDocFormatter
->GetNullDate()) -
1165 pCalendar
->getEpochStart();
1166 // #i14974# must use getLocalDateTime to get the same
1167 // date values as set above
1168 double fDays
= pCalendar
->getLocalDateTime();
1171 LanguageType eLatin
, eCjk
, eCtl
;
1172 pDoc
->GetLanguage( eLatin
, eCjk
, eCtl
);
1173 LanguageType eDocLang
= eLatin
; //! which language for date formats?
1175 short nType
= (nFound
> 3 ? css::util::NumberFormat::DATETIME
: css::util::NumberFormat::DATE
);
1176 sal_uLong nFormat
= pDocFormatter
->GetStandardFormat( nType
, eDocLang
);
1177 // maybe there is a special format including seconds or milliseconds
1179 nFormat
= pDocFormatter
->GetStandardFormat( fDays
, nFormat
, nType
, eDocLang
);
1181 ScAddress
aPos(nCol
,nRow
,nTab
);
1182 if ( bUseDocImport
)
1183 rDocImport
.setNumericCell(aPos
, fDays
);
1185 pDoc
->SetValue( aPos
, fDays
);
1186 pDoc
->SetNumberFormat(aPos
, nFormat
);
1188 return bMultiLine
; // success
1194 // Standard or date not determined -> SetString / EditCell
1195 if( rStr
.indexOf( '\n' ) == -1 )
1197 ScSetStringParam aParam
;
1198 aParam
.mpNumFormatter
= pFormatter
;
1199 aParam
.mbDetectNumberFormat
= bDetectNumFormat
;
1200 aParam
.meSetTextNumFormat
= ScSetStringParam::SpecialNumberOnly
;
1201 aParam
.mbHandleApostrophe
= false;
1202 if ( bUseDocImport
)
1203 rDocImport
.setAutoInput(ScAddress(nCol
, nRow
, nTab
), rStr
, &aParam
);
1205 pDoc
->SetString( nCol
, nRow
, nTab
, rStr
, &aParam
);
1210 ScFieldEditEngine
& rEngine
= pDoc
->GetEditEngine();
1211 rEngine
.SetText(rStr
);
1212 if ( bUseDocImport
)
1213 rDocImport
.setEditCell(ScAddress(nCol
, nRow
, nTab
), rEngine
.CreateTextObject());
1215 pDoc
->SetEditText( ScAddress( nCol
, nRow
, nTab
), rEngine
.CreateTextObject() );
1220 static OUString
lcl_GetFixed( const OUString
& rLine
, sal_Int32 nStart
, sal_Int32 nNext
,
1221 bool& rbIsQuoted
, bool& rbOverflowCell
)
1223 sal_Int32 nLen
= rLine
.getLength();
1226 if ( nNext
<= nStart
)
1227 return EMPTY_OUSTRING
;
1229 const sal_Unicode
* pStr
= rLine
.getStr();
1231 sal_Int32 nSpace
= nNext
;
1232 while ( nSpace
> nStart
&& pStr
[nSpace
-1] == ' ' )
1235 rbIsQuoted
= (pStr
[nStart
] == '"' && pStr
[nSpace
-1] == '"');
1238 bool bFits
= (nSpace
- nStart
- 3 <= SAL_MAX_UINT16
);
1239 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1241 return rLine
.copy(nStart
+1, nSpace
-nStart
-2);
1244 rbOverflowCell
= true;
1245 return rLine
.copy(nStart
+1, SAL_MAX_UINT16
);
1250 bool bFits
= (nSpace
- nStart
<= SAL_MAX_UINT16
);
1251 OSL_ENSURE( bFits
, "lcl_GetFixed: line doesn't fit into data");
1253 return rLine
.copy(nStart
, nSpace
-nStart
);
1256 rbOverflowCell
= true;
1257 return rLine
.copy(nStart
, SAL_MAX_UINT16
);
1262 bool ScImportExport::ExtText2Doc( SvStream
& rStrm
)
1265 return Text2Doc( rStrm
);
1267 sal_uInt64
const nOldPos
= rStrm
.Tell();
1268 sal_uInt64
const nRemaining
= rStrm
.remainingSize();
1269 boost::scoped_ptr
<ScProgress
> xProgress( new ScProgress( pDocSh
,
1270 ScGlobal::GetRscString( STR_LOAD_DOC
), nRemaining
));
1271 rStrm
.StartReadingUnicodeText( rStrm
.GetStreamCharSet() );
1273 SCCOL nStartCol
= aRange
.aStart
.Col();
1274 SCCOL nEndCol
= aRange
.aEnd
.Col();
1275 SCROW nStartRow
= aRange
.aStart
.Row();
1276 SCTAB nTab
= aRange
.aStart
.Tab();
1278 bool bFixed
= pExtOptions
->IsFixedLen();
1279 const OUString
& rSeps
= pExtOptions
->GetFieldSeps();
1280 const sal_Unicode
* pSeps
= rSeps
.getStr();
1281 bool bMerge
= pExtOptions
->IsMergeSeps();
1282 sal_uInt16 nInfoCount
= pExtOptions
->GetInfoCount();
1283 const sal_Int32
* pColStart
= pExtOptions
->GetColStart();
1284 const sal_uInt8
* pColFormat
= pExtOptions
->GetColFormat();
1285 long nSkipLines
= pExtOptions
->GetStartRow();
1287 LanguageType eDocLang
= pExtOptions
->GetLanguage();
1288 SvNumberFormatter
aNumFormatter( comphelper::getProcessComponentContext(), eDocLang
);
1289 bool bDetectNumFormat
= pExtOptions
->IsDetectSpecialNumber();
1291 // For date recognition
1292 ::utl::TransliterationWrapper
aTransliteration(
1293 comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE
);
1294 aTransliteration
.loadModuleIfNeeded( eDocLang
);
1295 CalendarWrapper
aCalendar( comphelper::getProcessComponentContext() );
1296 aCalendar
.loadDefaultCalendar(
1297 LanguageTag::convertToLocale( eDocLang
) );
1298 boost::scoped_ptr
< ::utl::TransliterationWrapper
> pEnglishTransliteration
;
1299 boost::scoped_ptr
< CalendarWrapper
> pEnglishCalendar
;
1300 if ( eDocLang
!= LANGUAGE_ENGLISH_US
)
1302 pEnglishTransliteration
.reset(new ::utl::TransliterationWrapper (
1303 comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE
));
1304 aTransliteration
.loadModuleIfNeeded( LANGUAGE_ENGLISH_US
);
1305 pEnglishCalendar
.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
1306 pEnglishCalendar
->loadDefaultCalendar(
1307 LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US
) );
1313 SCROW nRow
= nStartRow
;
1315 while(--nSkipLines
>0)
1317 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
); // content is ignored
1318 if ( rStrm
.IsEof() )
1322 // Determine range for Undo.
1323 // We don't need this during import of a file to a new sheet or document...
1324 bool bDetermineRange
= bUndo
;
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();
1335 ScDocumentImport
aDocImport(*pDoc
);
1340 aLine
= ReadCsvLine(rStrm
, !bFixed
, rSeps
, cStr
);
1341 if ( rStrm
.IsEof() && aLine
.isEmpty() )
1344 EmbeddedNullTreatment( aLine
);
1346 sal_Int32 nLineLen
= aLine
.getLength();
1347 SCCOL nCol
= nStartCol
;
1348 bool bMultiLine
= false;
1349 if ( bFixed
) // Fixed line length
1351 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1352 // overflow if there is really data following to be put behind
1353 // the last column, which doesn't happen if info is
1355 for ( i
=0; i
<nInfoCount
&& nCol
<= MAXCOL
+1; i
++ )
1357 sal_uInt8 nFmt
= pColFormat
[i
];
1358 if (nFmt
!= SC_COL_SKIP
) // sonst auch nCol nicht hochzaehlen
1361 bOverflowCol
= true; // display warning on import
1362 else if (!bDetermineRange
)
1364 sal_Int32 nStart
= pColStart
[i
];
1365 sal_Int32 nNext
= ( i
+1 < nInfoCount
) ? pColStart
[i
+1] : nLineLen
;
1366 bool bIsQuoted
= false;
1367 aCell
= lcl_GetFixed( aLine
, nStart
, nNext
, bIsQuoted
, bOverflowCell
);
1368 if (bIsQuoted
&& bQuotedAsText
)
1371 bMultiLine
|= lcl_PutString(
1372 aDocImport
, !mbOverwriting
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1373 &aNumFormatter
, bDetectNumFormat
, aTransliteration
, aCalendar
,
1374 pEnglishTransliteration
.get(), pEnglishCalendar
.get());
1380 else // Search for the separator
1382 SCCOL nSourceCol
= 0;
1383 sal_uInt16 nInfoStart
= 0;
1384 const sal_Unicode
* p
= aLine
.getStr();
1385 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1386 // overflow if there is really data following to be put behind
1387 // the last column, which doesn't happen if info is
1389 while (*p
&& nCol
<= MAXCOL
+1)
1391 bool bIsQuoted
= false;
1392 p
= ScImportExport::ScanNextFieldFromString( p
, aCell
,
1393 cStr
, pSeps
, bMerge
, bIsQuoted
, bOverflowCell
);
1395 sal_uInt8 nFmt
= SC_COL_STANDARD
;
1396 for ( i
=nInfoStart
; i
<nInfoCount
; i
++ )
1398 if ( pColStart
[i
] == nSourceCol
+ 1 ) // pColStart ist 1-basiert
1400 nFmt
= pColFormat
[i
];
1401 nInfoStart
= i
+ 1; // ColInfos sind in Reihenfolge
1405 if ( nFmt
!= SC_COL_SKIP
)
1408 bOverflowCol
= true; // display warning on import
1409 else if (!bDetermineRange
)
1411 if (bIsQuoted
&& bQuotedAsText
)
1414 bMultiLine
|= lcl_PutString(
1415 aDocImport
, !mbOverwriting
, nCol
, nRow
, nTab
, aCell
, nFmt
,
1416 &aNumFormatter
, bDetectNumFormat
, aTransliteration
,
1417 aCalendar
, pEnglishTransliteration
.get(), pEnglishCalendar
.get());
1426 nEndCol
= nCol
; //! points to the next free or even MAXCOL+2
1428 if (!bDetermineRange
)
1430 if (bMultiLine
&& !bRangeIsDetermined
&& pDocSh
)
1431 pDocSh
->AdjustRowHeight( nRow
, nRow
, nTab
);
1432 xProgress
->SetStateOnPercent( rStrm
.Tell() - nOldPos
);
1435 if ( nRow
> MAXROW
)
1437 bOverflowRow
= true; // display warning on import
1441 // so far nRow/nEndCol pointed to the next free
1442 if (nRow
> nStartRow
)
1444 if (nEndCol
> nStartCol
)
1445 nEndCol
= ::std::min( static_cast<SCCOL
>(nEndCol
- 1), MAXCOL
);
1447 if (bDetermineRange
)
1449 aRange
.aEnd
.SetCol( nEndCol
);
1450 aRange
.aEnd
.SetRow( nRow
);
1452 if ( !mbApi
&& nStartCol
!= nEndCol
&&
1453 !pDoc
->IsBlockEmpty( nTab
, nStartCol
+ 1, nStartRow
, nEndCol
, nRow
) )
1455 ScopedVclPtrInstance
< ScReplaceWarnBox
> aBox( ScDocShell::GetActiveDialogParent() );
1456 if ( aBox
->Execute() != RET_YES
)
1462 rStrm
.Seek( nOriginalStreamPos
);
1471 bDetermineRange
= !bDetermineRange
; // toggle
1472 } while (!bDetermineRange
);
1473 if ( !mbOverwriting
)
1474 aDocImport
.finalize();
1476 xProgress
.reset(); // make room for AdjustRowHeight progress
1477 if (bRangeIsDetermined
)
1480 if (mbImportBroadcast
&& !mbOverwriting
)
1482 pDoc
->BroadcastCells(aRange
, SC_HINT_DATACHANGED
);
1483 pDocSh
->PostDataChanged();
1488 void ScImportExport::EmbeddedNullTreatment( OUString
& rStr
)
1490 // A nasty workaround for data with embedded NULL characters. As long as we
1491 // can't handle them properly as cell content (things assume 0-terminated
1492 // strings at too many places) simply strip all NULL characters from raw
1493 // data. Excel does the same. See fdo#57841 for sample data.
1495 // The normal case is no embedded NULL, check first before de-/allocating
1497 sal_Unicode cNull
= 0;
1498 if (rStr
.indexOf( cNull
) >= 0)
1500 rStr
= rStr
.replaceAll( OUString( &cNull
, 1), OUString());
1504 const sal_Unicode
* ScImportExport::ScanNextFieldFromString( const sal_Unicode
* p
,
1505 OUString
& rField
, sal_Unicode cStr
, const sal_Unicode
* pSeps
, bool bMergeSeps
, bool& rbIsQuoted
,
1506 bool& rbOverflowCell
)
1510 const sal_Unicode cBlank
= ' ';
1511 if (!ScGlobal::UnicodeStrChr( pSeps
, cBlank
))
1513 // Cope with broken generators that put leading blanks before a quoted
1514 // field, like "field1", "field2", "..."
1515 // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1516 const sal_Unicode
* pb
= p
;
1517 while (*pb
== cBlank
)
1522 if ( *p
== cStr
) // String in quotes
1525 const sal_Unicode
* p1
;
1526 p1
= p
= lcl_ScanString( p
, rField
, pSeps
, cStr
, DQM_ESCAPE
, rbOverflowCell
);
1527 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1529 // Append remaining unquoted and undelimited data (dirty, dirty) to
1533 if (!lcl_appendLineData( rField
, p1
, p
))
1534 rbOverflowCell
= true;
1539 else // up to delimiter
1541 const sal_Unicode
* p0
= p
;
1542 while ( *p
&& !ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1544 if (!lcl_appendLineData( rField
, p0
, p
))
1545 rbOverflowCell
= true;
1549 if ( bMergeSeps
) // skip following delimiters
1551 while ( *p
&& ScGlobal::UnicodeStrChr( pSeps
, *p
) )
1560 * Check if a given string has any line break characters or separators.
1562 * @param rStr string to inspect.
1563 * @param cSep separator character.
1565 bool hasLineBreaksOrSeps( const OUString
& rStr
, sal_Unicode cSep
)
1567 const sal_Unicode
* p
= rStr
.getStr();
1568 for (sal_Int32 i
= 0, n
= rStr
.getLength(); i
< n
; ++i
, ++p
)
1579 // line break found.
1590 bool ScImportExport::Doc2Text( SvStream
& rStrm
)
1594 SCCOL nStartCol
= aRange
.aStart
.Col();
1595 SCROW nStartRow
= aRange
.aStart
.Row();
1596 SCTAB nStartTab
= aRange
.aStart
.Tab();
1597 SCCOL nEndCol
= aRange
.aEnd
.Col();
1598 SCROW nEndRow
= aRange
.aEnd
.Row();
1599 SCTAB nEndTab
= aRange
.aEnd
.Tab();
1601 if (!pDoc
->GetClipParam().isMultiRange() && nStartTab
== nEndTab
)
1602 pDoc
->ShrinkToDataArea( nStartTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
1606 bool bConvertLF
= (GetSystemLineEnd() != LINEEND_LF
);
1608 for (nRow
= nStartRow
; nRow
<= nEndRow
; nRow
++)
1610 if (bIncludeFiltered
|| !pDoc
->RowFiltered( nRow
, nStartTab
))
1612 for (nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
1615 pDoc
->GetCellType( nCol
, nRow
, nStartTab
, eType
);
1618 case CELLTYPE_FORMULA
:
1622 pDoc
->GetFormula( nCol
, nRow
, nStartTab
, aCell
);
1623 if( aCell
.indexOf( cSep
) != -1 )
1624 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1626 lcl_WriteSimpleString( rStrm
, aCell
);
1630 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1632 bool bMultiLineText
= ( aCell
.indexOf( '\n' ) != -1 );
1633 if( bMultiLineText
)
1635 if( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSpace
)
1636 aCell
= aCell
.replaceAll( "\n", " " );
1637 else if ( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSystem
&& bConvertLF
)
1638 aCell
= convertLineEnd(aCell
, GetSystemLineEnd());
1641 if( mExportTextOptions
.mcSeparatorConvertTo
&& cSep
)
1642 aCell
= aCell
.replaceAll( OUString(cSep
), OUString(mExportTextOptions
.mcSeparatorConvertTo
) );
1644 if( mExportTextOptions
.mbAddQuotes
&& ( aCell
.indexOf( cSep
) != -1 ) )
1645 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1647 lcl_WriteSimpleString( rStrm
, aCell
);
1651 case CELLTYPE_VALUE
:
1653 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1654 lcl_WriteSimpleString( rStrm
, aCell
);
1661 aCell
= pDoc
->GetString(nCol
, nRow
, nStartTab
);
1663 bool bMultiLineText
= ( aCell
.indexOf( '\n' ) != -1 );
1664 if( bMultiLineText
)
1666 if( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSpace
)
1667 aCell
= aCell
.replaceAll( "\n", " " );
1668 else if ( mExportTextOptions
.meNewlineConversion
== ScExportTextOptions::ToSystem
&& bConvertLF
)
1669 aCell
= convertLineEnd(aCell
, GetSystemLineEnd());
1672 if( mExportTextOptions
.mcSeparatorConvertTo
&& cSep
)
1673 aCell
= aCell
.replaceAll( OUString(cSep
), OUString(mExportTextOptions
.mcSeparatorConvertTo
) );
1675 if( mExportTextOptions
.mbAddQuotes
&& hasLineBreaksOrSeps(aCell
, cSep
) )
1676 lcl_WriteString( rStrm
, aCell
, cStr
, cStr
);
1678 lcl_WriteSimpleString( rStrm
, aCell
);
1681 if( nCol
< nEndCol
)
1682 lcl_WriteSimpleString( rStrm
, OUString(cSep
) );
1684 WriteUnicodeOrByteEndl( rStrm
);
1685 if( rStrm
.GetError() != SVSTREAM_OK
)
1687 if( nSizeLimit
&& rStrm
.Tell() > nSizeLimit
)
1692 return rStrm
.GetError() == SVSTREAM_OK
;
1695 bool ScImportExport::Sylk2Doc( SvStream
& rStrm
)
1698 bool bMyDoc
= false;
1699 SylkVersion eVersion
= SYLK_OTHER
;
1701 // US-English separators for StringToDouble
1702 sal_Unicode cDecSep
= '.';
1703 sal_Unicode cGrpSep
= ',';
1705 SCCOL nStartCol
= aRange
.aStart
.Col();
1706 SCROW nStartRow
= aRange
.aStart
.Row();
1707 SCCOL nEndCol
= aRange
.aEnd
.Col();
1708 SCROW nEndRow
= aRange
.aEnd
.Row();
1709 sal_uLong nOldPos
= rStrm
.Tell();
1710 bool bData
= !bSingle
;
1711 ::std::vector
< sal_uInt32
> aFormats
;
1721 SCCOL nCol
= nStartCol
;
1722 SCROW nRow
= nStartRow
;
1725 rStrm
.Seek( nOldPos
);
1729 rStrm
.ReadLine( aByteLine
);
1730 aLine
= OStringToOUString(aByteLine
, rStrm
.GetStreamCharSet());
1733 const sal_Unicode
* p
= aLine
.getStr();
1734 sal_Unicode cTag
= *p
++;
1735 if( cTag
== 'C' ) // Content
1741 sal_Unicode ch
= *p
++;
1742 ch
= ScGlobal::ToUpperAlpha( ch
);
1746 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1749 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
1752 nRefCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1755 nRefRow
= OUString(p
).toInt32() + nStartRow
- 1;
1760 ( nCol
< nStartCol
|| nCol
> nEndCol
1761 || nRow
< nStartRow
|| nRow
> nEndRow
1762 || nCol
> MAXCOL
|| nRow
> MAXROW
) )
1766 if( nRow
> nEndRow
)
1768 if( nCol
> nEndCol
)
1777 p
= lcl_ScanSylkString( p
, aText
, eVersion
);
1781 const sal_Unicode
* q
= p
;
1782 while( *q
&& *q
!= ';' )
1784 if ( !(*q
== ';' && *(q
+1) == 'I') )
1785 { // don't ignore value
1788 pDoc
->EnsureTable(aRange
.aStart
.Tab());
1790 ScAddress(nCol
, nRow
, aRange
.aStart
.Tab()), aText
);
1794 double fVal
= rtl_math_uStringToDouble( p
,
1795 aLine
.getStr() + aLine
.getLength(),
1796 cDecSep
, cGrpSep
, NULL
, NULL
);
1797 pDoc
->SetValue( nCol
, nRow
, aRange
.aStart
.Tab(), fVal
);
1807 if ( nRefCol
< nCol
)
1809 if ( nRefRow
< nRow
)
1813 if( nRefRow
> nEndRow
)
1815 if( nRefCol
> nEndCol
)
1819 if( !bMyDoc
|| !bData
)
1822 p
= lcl_ScanSylkFormula( p
, aText
, eVersion
);
1823 ScAddress
aPos( nCol
, nRow
, aRange
.aStart
.Tab() );
1824 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1825 * end it probably should be GRAM_ODFF_R1C1, since
1826 * R1C1 is what Excel writes in SYLK. */
1827 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_PODF_A1
;
1828 ScCompiler
aComp( pDoc
, aPos
);
1829 aComp
.SetGrammar(eGrammar
);
1830 ScTokenArray
* pCode
= aComp
.CompileString( aText
);
1834 aMark
.SelectTable( aPos
.Tab(), true );
1835 pDoc
->InsertMatrixFormula( nCol
, nRow
, nRefCol
,
1836 nRefRow
, aMark
, EMPTY_OUSTRING
, pCode
);
1840 ScFormulaCell
* pFCell
= new ScFormulaCell(
1841 pDoc
, aPos
, *pCode
, eGrammar
, MM_NONE
);
1842 pDoc
->SetFormulaCell(aPos
, pFCell
);
1844 delete pCode
; // ctor/InsertMatrixFormula did copy TokenArray
1848 while( *p
&& *p
!= ';' )
1854 else if( cTag
== 'F' ) // Format
1858 sal_Int32 nFormat
= -1;
1861 sal_Unicode ch
= *p
++;
1862 ch
= ScGlobal::ToUpperAlpha( ch
);
1866 nCol
= static_cast<SCCOL
>(OUString(p
).toInt32()) + nStartCol
- 1;
1869 nRow
= OUString(p
).toInt32() + nStartRow
- 1;
1874 // F;P<n> sets format code of P;P<code> at
1875 // current position, or at ;X;Y if specified.
1876 // Note that ;X;Y may appear after ;P
1877 const sal_Unicode
* p0
= p
;
1878 while( *p
&& *p
!= ';' )
1880 OUString
aNumber(p0
, p
- p0
);
1881 nFormat
= aNumber
.toInt32();
1885 while( *p
&& *p
!= ';' )
1892 if( nRow
> nEndRow
)
1894 if( nCol
> nEndCol
)
1897 if ( 0 <= nFormat
&& nFormat
< (sal_Int32
)aFormats
.size() )
1899 sal_uInt32 nKey
= aFormats
[nFormat
];
1900 pDoc
->ApplyAttr( nCol
, nRow
, aRange
.aStart
.Tab(),
1901 SfxUInt32Item( ATTR_VALUE_FORMAT
, nKey
) );
1904 else if( cTag
== 'P' )
1906 if ( bData
&& *p
== ';' && *(p
+1) == 'P' )
1908 OUString
aCode( p
+2 );
1909 // unescape doubled semicolons
1910 aCode
= aCode
.replaceAll(";;", ";");
1911 // get rid of Xcl escape characters
1912 aCode
= aCode
.replaceAll(OUString(static_cast<sal_Unicode
>(0x1b)), OUString());
1913 sal_Int32 nCheckPos
;
1916 pDoc
->GetFormatTable()->PutandConvertEntry( aCode
, nCheckPos
, nType
, nKey
,
1917 LANGUAGE_ENGLISH_US
, ScGlobal::eLnge
);
1920 aFormats
.push_back( nKey
);
1923 else if( cTag
== 'I' && *p
== 'D' )
1925 aLine
= aLine
.copy(4);
1926 if (aLine
== "CALCOOO32")
1927 eVersion
= SYLK_OOO32
;
1928 else if (aLine
== "SCALC3")
1929 eVersion
= SYLK_SCALC3
;
1930 bMyDoc
= (eVersion
<= SYLK_OWN
);
1932 else if( cTag
== 'E' ) // Ende
1937 aRange
.aEnd
.SetCol( nEndCol
);
1938 aRange
.aEnd
.SetRow( nEndRow
);
1950 bool ScImportExport::Doc2Sylk( SvStream
& rStrm
)
1954 SCCOL nStartCol
= aRange
.aStart
.Col();
1955 SCROW nStartRow
= aRange
.aStart
.Row();
1956 SCCOL nEndCol
= aRange
.aEnd
.Col();
1957 SCROW nEndRow
= aRange
.aEnd
.Row();
1960 lcl_WriteSimpleString( rStrm
, OUString("ID;PCALCOOO32") );
1961 WriteUnicodeOrByteEndl( rStrm
);
1963 for (nRow
= nStartRow
; nRow
<= nEndRow
; nRow
++)
1965 for (nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
1970 SCROW r
= nRow
- nStartRow
+ 1;
1971 SCCOL c
= nCol
- nStartCol
+ 1;
1972 ScRefCellValue aCell
;
1973 aCell
.assign(*pDoc
, ScAddress(nCol
, nRow
, aRange
.aStart
.Tab()));
1974 CellType eType
= aCell
.meType
;
1977 case CELLTYPE_FORMULA
:
1979 if( pDoc
->HasValueData( nCol
, nRow
, aRange
.aStart
.Tab()) )
1984 case CELLTYPE_VALUE
:
1986 pDoc
->GetValue( nCol
, nRow
, aRange
.aStart
.Tab(), nVal
);
1988 aValStr
= ::rtl::math::doubleToUString( nVal
,
1989 rtl_math_StringFormat_Automatic
,
1990 rtl_math_DecimalPlaces_Max
, '.', true );
1993 aBufStr
+= OUString::number( c
);
1995 aBufStr
+= OUString::number( r
);
1998 lcl_WriteSimpleString( rStrm
, aBufStr
);
2001 case CELLTYPE_STRING
:
2004 aCellStr
= pDoc
->GetString(nCol
, nRow
, aRange
.aStart
.Tab());
2005 aCellStr
= aCellStr
.replaceAll( OUString('\n'), OUString(SYLK_LF
) );
2008 aBufStr
+= OUString::number( c
);
2010 aBufStr
+= OUString::number( r
);
2012 lcl_WriteSimpleString( rStrm
, aBufStr
);
2013 lcl_WriteString( rStrm
, aCellStr
, '"', ';' );
2018 const ScFormulaCell
* pFCell
= aCell
.mpFormula
;
2019 switch ( pFCell
->GetMatrixFlag() )
2025 OUString aOUCellStr
;
2026 pFCell
->GetFormula( aOUCellStr
,formula::FormulaGrammar::GRAM_PODF_A1
);
2027 aCellStr
= aOUCellStr
;
2028 /* FIXME: do we want GRAM_ODFF_A1 instead? At
2029 * the end it probably should be
2030 * GRAM_ODFF_R1C1, since R1C1 is what Excel
2031 * writes in SYLK. */
2033 if ( pFCell
->GetMatrixFlag() != MM_NONE
&&
2034 aCellStr
.startsWith("{") &&
2035 aCellStr
.endsWith("}") )
2036 { // cut off matrix {} characters
2037 aCellStr
= aCellStr
.copy(1, aCellStr
.getLength()-2);
2039 if ( aCellStr
[0] == '=' )
2040 aCellStr
= aCellStr
.copy(1);
2042 switch ( pFCell
->GetMatrixFlag() )
2045 { // diff expression with 'M' M$-extension
2048 pFCell
->GetMatColsRows( nC
, nR
);
2052 aPrefix
+= OUString::number( nR
);
2054 aPrefix
+= OUString::number( nC
);
2059 { // diff expression with 'I' M$-extension
2061 pFCell
->GetMatrixOrigin( aPos
);
2063 aPrefix
+= OUString::number( aPos
.Row() - nStartRow
+ 1 );
2065 aPrefix
+= OUString::number( aPos
.Col() - nStartCol
+ 1 );
2069 // formula Expression
2072 lcl_WriteSimpleString( rStrm
, aPrefix
);
2073 if ( !aCellStr
.isEmpty() )
2074 lcl_WriteString( rStrm
, aCellStr
, 0, ';' );
2076 WriteUnicodeOrByteEndl( rStrm
);
2081 // added to avoid warnings
2086 lcl_WriteSimpleString( rStrm
, OUString( 'E' ) );
2087 WriteUnicodeOrByteEndl( rStrm
);
2088 return rStrm
.GetError() == SVSTREAM_OK
;
2091 bool ScImportExport::Doc2HTML( SvStream
& rStrm
, const OUString
& rBaseURL
)
2093 // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
2094 ScFormatFilter::Get().ScExportHTML( rStrm
, rBaseURL
, pDoc
, aRange
, RTL_TEXTENCODING_DONTKNOW
, bAll
,
2095 aStreamPath
, aNonConvertibleChars
, maFilterOptions
);
2096 return rStrm
.GetError() == SVSTREAM_OK
;
2099 bool ScImportExport::Doc2RTF( SvStream
& rStrm
)
2101 // rtl_TextEncoding is ignored in ScExportRTF
2102 ScFormatFilter::Get().ScExportRTF( rStrm
, pDoc
, aRange
, RTL_TEXTENCODING_DONTKNOW
);
2103 return rStrm
.GetError() == SVSTREAM_OK
;
2106 bool ScImportExport::Doc2Dif( SvStream
& rStrm
)
2108 // for DIF in the clipboard, IBM_850 is always used
2109 ScFormatFilter::Get().ScExportDif( rStrm
, pDoc
, aRange
, RTL_TEXTENCODING_IBM_850
);
2113 bool ScImportExport::Dif2Doc( SvStream
& rStrm
)
2115 SCTAB nTab
= aRange
.aStart
.Tab();
2116 ScDocument
* pImportDoc
= new ScDocument( SCDOCMODE_UNDO
);
2117 pImportDoc
->InitUndo( pDoc
, nTab
, nTab
);
2119 // for DIF in the clipboard, IBM_850 is always used
2120 ScFormatFilter::Get().ScImportDif( rStrm
, pImportDoc
, aRange
.aStart
, RTL_TEXTENCODING_IBM_850
);
2124 pImportDoc
->GetCellArea( nTab
, nEndCol
, nEndRow
);
2125 // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2126 if ( nEndCol
< aRange
.aStart
.Col() )
2127 nEndCol
= aRange
.aStart
.Col();
2128 if ( nEndRow
< aRange
.aStart
.Row() )
2129 nEndRow
= aRange
.aStart
.Row();
2130 aRange
.aEnd
= ScAddress( nEndCol
, nEndRow
, nTab
);
2132 bool bOk
= StartPaste();
2135 InsertDeleteFlags nFlags
= IDF_ALL
& ~IDF_STYLES
;
2136 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2137 pImportDoc
->CopyToDocument( aRange
, nFlags
, false, pDoc
);
2146 bool ScImportExport::RTF2Doc( SvStream
& rStrm
, const OUString
& rBaseURL
)
2148 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateRTFImport( pDoc
, aRange
);
2151 pImp
->Read( rStrm
, rBaseURL
);
2152 aRange
= pImp
->GetRange();
2154 bool bOk
= StartPaste();
2157 InsertDeleteFlags nFlags
= IDF_ALL
& ~IDF_STYLES
;
2158 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2159 pImp
->WriteToDocument();
2166 bool ScImportExport::HTML2Doc( SvStream
& rStrm
, const OUString
& rBaseURL
)
2168 ScEEAbsImport
*pImp
= ScFormatFilter::Get().CreateHTMLImport( pDoc
, rBaseURL
, aRange
, true);
2171 pImp
->Read( rStrm
, rBaseURL
);
2172 aRange
= pImp
->GetRange();
2174 bool bOk
= StartPaste();
2177 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2178 // a Draw Layer but no Draw View -> create Draw Layer and View here
2180 pDocSh
->MakeDrawLayer();
2182 InsertDeleteFlags nFlags
= IDF_ALL
& ~IDF_STYLES
;
2183 pDoc
->DeleteAreaTab( aRange
, nFlags
);
2187 // Pick up import options if available.
2188 LanguageType eLang
= pExtOptions
->GetLanguage();
2189 SvNumberFormatter
aNumFormatter( comphelper::getProcessComponentContext(), eLang
);
2190 bool bSpecialNumber
= pExtOptions
->IsDetectSpecialNumber();
2191 pImp
->WriteToDocument(false, 1.0, &aNumFormatter
, bSpecialNumber
);
2194 // Regular import, with no options.
2195 pImp
->WriteToDocument();
2203 #ifndef DISABLE_DYNLOADING
2205 class ScFormatFilterMissing
: public ScFormatFilterPlugin
{
2207 ScFormatFilterMissing()
2209 OSL_FAIL("Missing file filters");
2211 virtual ~ScFormatFilterMissing() {}
2212 virtual FltError
ScImportLotus123( SfxMedium
&, ScDocument
*, rtl_TextEncoding
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2213 virtual FltError
ScImportQuattroPro( SfxMedium
&, ScDocument
* ) SAL_OVERRIDE
{ return eERR_INTERN
; }
2214 virtual FltError
ScImportExcel( SfxMedium
&, ScDocument
*, const EXCIMPFORMAT
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2215 virtual FltError
ScImportStarCalc10( SvStream
&, ScDocument
* ) SAL_OVERRIDE
{ return eERR_INTERN
; }
2216 virtual FltError
ScImportDif( SvStream
&, ScDocument
*, const ScAddress
&,
2217 const rtl_TextEncoding
, sal_uInt32
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2218 virtual FltError
ScImportRTF( SvStream
&, const OUString
&, ScDocument
*, ScRange
& ) SAL_OVERRIDE
{ return eERR_INTERN
; }
2219 virtual FltError
ScImportHTML( SvStream
&, const OUString
&, ScDocument
*, ScRange
&, double, bool, SvNumberFormatter
*, bool ) SAL_OVERRIDE
{ return eERR_INTERN
; }
2221 virtual ScEEAbsImport
*CreateRTFImport( ScDocument
*, const ScRange
& ) SAL_OVERRIDE
{ return NULL
; }
2222 virtual ScEEAbsImport
*CreateHTMLImport( ScDocument
*, const OUString
&, const ScRange
&, bool ) SAL_OVERRIDE
{ return NULL
; }
2223 virtual OUString
GetHTMLRangeNameList( ScDocument
*, const OUString
& ) SAL_OVERRIDE
{ return OUString(); }
2225 virtual FltError
ScExportExcel5( SfxMedium
&, ScDocument
*, ExportFormatExcel
, rtl_TextEncoding
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2226 virtual FltError
ScExportDif( SvStream
&, ScDocument
*, const ScAddress
&, const rtl_TextEncoding
, sal_uInt32
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2227 virtual FltError
ScExportDif( SvStream
&, ScDocument
*, const ScRange
&, const rtl_TextEncoding
, sal_uInt32
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2228 virtual FltError
ScExportHTML( SvStream
&, const OUString
&, ScDocument
*, const ScRange
&, const rtl_TextEncoding
, bool,
2229 const OUString
&, OUString
&, const OUString
& ) SAL_OVERRIDE
{ return eERR_INTERN
; }
2230 virtual FltError
ScExportRTF( SvStream
&, ScDocument
*, const ScRange
&, const rtl_TextEncoding
) SAL_OVERRIDE
{ return eERR_INTERN
; }
2232 virtual ScOrcusFilters
* GetOrcusFilters() SAL_OVERRIDE
{ return NULL
; }
2235 extern "C" { static void SAL_CALL
thisModule() {} }
2240 ScFormatFilterPlugin
* ScFilterCreate();
2245 typedef ScFormatFilterPlugin
* (*FilterFn
)(void);
2246 ScFormatFilterPlugin
&ScFormatFilter::Get()
2248 static ScFormatFilterPlugin
*plugin
;
2253 #ifndef DISABLE_DYNLOADING
2254 OUString
sFilterLib(SVLIBRARY("scfilt"));
2255 static ::osl::Module aModule
;
2256 bool bLoaded
= aModule
.loadRelative(&thisModule
, sFilterLib
);
2258 bLoaded
= aModule
.load(sFilterLib
);
2261 oslGenericFunction fn
= aModule
.getFunctionSymbol( OUString( "ScFilterCreate" ) );
2263 plugin
= reinterpret_cast<FilterFn
>(fn
)();
2266 plugin
= new ScFormatFilterMissing();
2268 plugin
= ScFilterCreate();
2274 // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2276 static inline const sal_Unicode
* lcl_UnicodeStrChr( const sal_Unicode
* pStr
,
2288 OUString
ReadCsvLine( SvStream
&rStream
, bool bEmbeddedLineBreak
,
2289 const OUString
& rFieldSeparators
, sal_Unicode cFieldQuote
)
2292 rStream
.ReadUniOrByteStringLine(aStr
, rStream
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
2294 if (bEmbeddedLineBreak
)
2296 const sal_Unicode
* pSeps
= rFieldSeparators
.getStr();
2298 QuoteType eQuoteState
= FIELDEND_QUOTE
;
2299 bool bFieldStart
= true;
2301 sal_Int32 nLastOffset
= 0;
2302 sal_Int32 nQuotes
= 0;
2303 while (!rStream
.IsEof() && aStr
.getLength() < nArbitraryLineLengthLimit
)
2305 const sal_Unicode
*p
, *pStart
;
2306 p
= pStart
= aStr
.getStr();
2312 if (*p
== cFieldQuote
)
2317 bFieldStart
= false;
2318 eQuoteState
= FIELDSTART_QUOTE
;
2320 // Do not detect a FIELDSTART_QUOTE if not in
2321 // bFieldStart mode, in which case for unquoted content
2322 // we are in FIELDEND_QUOTE state.
2323 else if (eQuoteState
!= FIELDEND_QUOTE
)
2325 eQuoteState
= lcl_isEscapedOrFieldEndQuote( nQuotes
, p
, pSeps
, cFieldQuote
);
2326 // DONTKNOW_QUOTE is an embedded unescaped quote we
2327 // don't count for pairing.
2328 if (eQuoteState
!= DONTKNOW_QUOTE
)
2332 else if (eQuoteState
== FIELDEND_QUOTE
)
2335 // If blank is a separator it starts a field, if it
2336 // is not and thus maybe leading before quote we
2337 // are still at start of field regarding quotes.
2338 bFieldStart
= (*p
== ' ' || lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2340 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2345 if (*p
== cFieldQuote
&& bFieldStart
)
2348 eQuoteState
= FIELDSTART_QUOTE
;
2349 bFieldStart
= false;
2351 else if (eQuoteState
== FIELDEND_QUOTE
)
2353 // This also skips leading blanks at beginning of line
2354 // if followed by a quote. It's debatable whether we
2355 // actually want that or not, but congruent with what
2356 // ScanNextFieldFromString() does.
2358 bFieldStart
= (*p
== ' ' || lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2360 bFieldStart
= (lcl_UnicodeStrChr( pSeps
, *p
) != NULL
);
2363 // A quote character inside a field content does not start
2368 if (nQuotes
% 2 == 0)
2369 // We still have a (theoretical?) problem here if due to
2370 // nArbitraryLineLengthLimit we split a string right between a
2371 // doubled quote pair.
2375 nLastOffset
= aStr
.getLength();
2377 rStream
.ReadUniOrByteStringLine(aNext
, rStream
.GetStreamCharSet(), nArbitraryLineLengthLimit
);
2378 aStr
+= OUString('\n');
2386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */