fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / docshell / impex.cxx
blob6e75c9bacc0dea74b572f57b511d413dfb4ea043
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sc.hrc"
22 #include <comphelper/processfactory.hxx>
23 #include <i18nlangtag/languagetag.hxx>
24 #include <sot/formats.hxx>
25 #include <sfx2/mieclip.hxx>
26 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
28 #include "global.hxx"
29 #include "scerrors.hxx"
30 #include "docsh.hxx"
31 #include "undoblk.hxx"
32 #include "rangenam.hxx"
33 #include "viewdata.hxx"
34 #include "tabvwsh.hxx"
35 #include "filter.hxx"
36 #include "asciiopt.hxx"
37 #include "formulacell.hxx"
38 #include "docoptio.hxx"
39 #include "progress.hxx"
40 #include "scitems.hxx"
41 #include "editable.hxx"
42 #include "compiler.hxx"
43 #include "warnbox.hxx"
44 #include "clipparam.hxx"
45 #include "impex.hxx"
46 #include "editutil.hxx"
47 #include "patattr.hxx"
48 #include "docpool.hxx"
49 #include "stringutil.hxx"
50 #include "cellvalue.hxx"
51 #include "tokenarray.hxx"
52 #include "documentimport.hxx"
54 #include "globstr.hrc"
55 #include <vcl/svapp.hxx>
57 #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
63 // anyway.
64 static const sal_Int32 nArbitraryLineLengthLimit = 2 * MAXCOLCOUNT * 65536;
66 namespace
68 const char SYLK_LF[] = "\x1b :";
69 const char DOUBLE_SEMICOLON[] = ";;";
70 const char DOUBLE_DOUBLEQUOTE[] = "\"\"";
73 enum SylkVersion
75 SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
76 SYLK_OOO32, // Correct strings, plus multiline content.
77 SYLK_OWN, // Place our new versions, if any, before this value.
78 SYLK_OTHER // Assume that aliens wrote correct strings.
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 ),
89 mExportTextOptions()
91 pUndoDoc = NULL;
92 pExtOptions = NULL;
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 ),
98 aRange( rPt ),
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 ),
104 mExportTextOptions()
106 pUndoDoc = NULL;
107 pExtOptions = NULL;
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 ),
114 aRange( r ),
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 ),
120 mExportTextOptions()
122 pUndoDoc = NULL;
123 pExtOptions = NULL;
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 ),
137 mExportTextOptions()
139 pUndoDoc = NULL;
140 pExtOptions = NULL;
142 SCTAB nTab = ScDocShell::GetCurTab();
143 aRange.aStart.SetTab( nTab );
144 OUString aPos( rPos );
145 // Named range?
146 ScRangeName* pRange = pDoc->GetRangeName();
147 if (pRange)
149 const ScRangeData* pData = pRange->findByUpperName(ScGlobal::pCharClass->uppercase(aPos));
150 if (pData)
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();
161 // Range?
162 if (aRange.Parse(aPos, pDoc, eConv) & SCA_VALID)
163 bSingle = false;
164 // Cell?
165 else if (aRange.aStart.Parse(aPos, pDoc, eConv) & SCA_VALID)
166 aRange.aEnd = aRange.aStart;
167 else
168 bAll = true;
171 ScImportExport::~ScImportExport()
173 delete pUndoDoc;
174 delete pExtOptions;
177 void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
179 if ( pExtOptions )
180 *pExtOptions = rOpt;
181 else
182 pExtOptions = new ScAsciiOptions( rOpt );
184 // "normal" Options
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;
205 // Prepare for Undo
206 bool ScImportExport::StartPaste()
208 if ( !bAll )
210 ScEditableTester aTester( pDoc, aRange );
211 if ( !aTester.IsEditable() )
213 ScopedVclPtrInstance<InfoBox> aInfoBox( Application::GetDefDialogParent(),
214 ScGlobal::GetRscString( aTester.GetMessageId() ) );
215 aInfoBox->Execute();
216 return false;
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 );
225 return true;
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));
244 pUndoDoc = NULL;
245 if( pDocSh )
247 if (!bHeight)
248 pDocSh->PostPaint( aRange, PAINT_GRID );
249 pDocSh->SetDocumentModified();
251 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
252 if ( pViewSh )
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" );
261 return false;
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 ) );
276 return true;
278 return false;
281 bool ScImportExport::ImportString( const OUString& rText, SotClipboardFormatId nFmt )
283 switch ( 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
292 default:
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();
310 OString aTmp;
311 bool bOk = ExportByteString( aTmp, eEnc, nFmt );
312 rText = OStringToOUString( aTmp, eEnc );
313 return bOk;
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()) );
327 return true;
329 rText.clear();
330 return false;
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();
341 if (!nSizeLimit)
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());
355 return true;
358 rText.clear();
359 return false;
362 bool ScImportExport::ImportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
364 if( nFmt == SotClipboardFormatId::STRING )
366 if( ExtText2Doc( rStrm ) ) // evaluate pExtOptions
367 return true;
369 if( nFmt == SotClipboardFormatId::SYLK )
371 if( Sylk2Doc( rStrm ) )
372 return true;
374 if( nFmt == SotClipboardFormatId::DIF )
376 if( Dif2Doc( rStrm ) )
377 return true;
379 if( nFmt == SotClipboardFormatId::RTF )
381 if( RTF2Doc( rStrm, rBaseURL ) )
382 return true;
384 if( nFmt == SotClipboardFormatId::LINK )
385 return true; // Link-Import?
386 if ( nFmt == SotClipboardFormatId::HTML )
388 if( HTML2Doc( rStrm, rBaseURL ) )
389 return true;
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 ) )
396 return true;
399 return false;
402 bool ScImportExport::ExportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
404 if( nFmt == SotClipboardFormatId::STRING )
406 if( Doc2Text( rStrm ) )
407 return true;
409 if( nFmt == SotClipboardFormatId::SYLK )
411 if( Doc2Sylk( rStrm ) )
412 return true;
414 if( nFmt == SotClipboardFormatId::DIF )
416 if( Doc2Dif( rStrm ) )
417 return true;
419 if( nFmt == SotClipboardFormatId::LINK && !bAll )
421 OUString aDocName;
422 if ( pDoc->IsClipboard() )
423 aDocName = ScGlobal::GetClipDocName();
424 else
426 SfxObjectShell* pShell = pDoc->GetDocumentShell();
427 if (pShell)
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.
435 OUString aRefName;
436 sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
437 if( bSingle )
438 aRefName = aRange.aStart.Format(nFlags, pDoc, formula::FormulaGrammar::CONV_OOO);
439 else
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
448 // reference link.
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 );
457 else
458 rStrm.WriteChar( 0 );
459 return rStrm.GetError() == SVSTREAM_OK;
462 if( nFmt == SotClipboardFormatId::HTML )
464 if( Doc2HTML( rStrm, rBaseURL ) )
465 return true;
467 if( nFmt == SotClipboardFormatId::RTF )
469 if( Doc2RTF( rStrm ) )
470 return true;
473 return false;
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) );
483 else
485 const sal_Unicode* p = rString.getStr();
486 const sal_Unicode* const pStop = p + rString.getLength();
487 while ( p < pStop )
489 rStrm.WriteUInt16( *p );
492 if ( bZero )
493 rStrm.WriteUInt16( 0 );
495 else
497 OString aByteStr(OUStringToOString(rString, eEnc));
498 rStrm.WriteCharPtr( aByteStr.getStr() );
499 if ( bZero )
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() )
511 case LINEEND_CR :
512 rStrm.WriteUInt16( '\r' );
513 break;
514 case LINEEND_LF :
515 rStrm.WriteUInt16( '\n' );
516 break;
517 default:
518 rStrm.WriteUInt16( '\r' ).WriteUInt16( '\n' );
521 else
522 endl( rStrm );
525 enum QuoteType
527 FIELDSTART_QUOTE,
528 FIRST_QUOTE,
529 SECOND_QUOTE,
530 FIELDEND_QUOTE,
531 DONTKNOW_QUOTE
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.
538 @return
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)
551 ++p;
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
558 quoted field.
560 Precondition: *p is a quote.
562 @param nQuotes
563 Quote characters encountered so far.
564 Odd (after opening quote) means either no embedded quotes or only quote
565 pairs so far.
566 Even means either not in a quoted field or already one quote
567 encountered, the first of a pair.
569 @return
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)
583 if (p[-1] == cStr)
584 return SECOND_QUOTE;
585 else
587 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
588 return FIELDSTART_QUOTE;
591 if (p[1] == cStr)
592 return FIRST_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 ) );
606 return true;
608 else
610 rField += OUString( p1, SAL_MAX_UINT16 - rField.getLength() );
611 return false;
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
629 bool bCont;
632 bCont = false;
633 const sal_Unicode* p0 = p;
634 for( ;; )
636 if( !*p )
637 break;
638 if( *p == cStr )
640 if ( *++p != cStr )
642 // break or continue for loop
643 if (eMode == DQM_ESCAPE)
645 if (lcl_isFieldEndQuote( p-1, pSeps) == FIELDEND_QUOTE)
646 break;
647 else
648 continue;
650 else
651 break;
653 // doubled quote char
654 switch ( eMode )
656 case DQM_KEEP_ALL :
657 case DQM_KEEP :
658 p++; // both for us (not breaking for-loop)
659 break;
660 case DQM_ESCAPE :
661 p++; // one for us (breaking for-loop)
662 bCont = true; // and more
663 break;
664 case DQM_CONCAT :
665 if ( p0+1 < p )
667 // first part
668 if (!lcl_appendLineData( rString, p0, p-1))
669 rbOverflowCell = true;
671 p0 = ++p; // text of next part starts here
672 break;
673 case DQM_SEPARATE :
674 // positioned on next opening quote
675 break;
677 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
678 break;
680 else
681 p++;
683 if ( p0 < p )
685 if (!lcl_appendLineData( rString, p0, ((eMode != DQM_KEEP_ALL && (*p || *(p-1) == cStr)) ? p-1 : p)))
686 rbOverflowCell = true;
688 } while ( bCont );
689 return p;
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(';') );
699 else
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;
710 while( *(++p) )
712 if( *p == '"' )
714 pEndQuote = p;
715 if (eVersion >= SYLK_OOO32)
717 if (*(p+1) == ';')
719 if (*(p+2) == ';')
721 p += 2; // escaped ';'
722 pEndQuote = 0;
724 else
725 break; // end field
728 else
730 if (*(p+1) == '"')
732 ++p; // escaped '"'
733 pEndQuote = 0;
735 else if (*(p+1) == ';')
736 break; // end field
740 if (!pEndQuote)
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);
744 return p;
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)
753 while (*p)
755 if (*p == ';')
757 if (*(p+1) == ';')
758 ++p; // escaped ';'
759 else
760 break; // end field
762 ++p;
764 rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
765 lcl_UnescapeSylk( rString, eVersion);
767 else
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;
778 if (*p == '"')
780 // May be a quoted expression or just a string constant expression
781 // with quotes.
782 while (*(++p))
784 if (*p == '"')
786 if (*(p+1) == '"')
787 ++p; // escaped '"'
788 else
789 break; // closing '"', had no ';' yet
791 else if (*p == ';')
793 bQuoted = true; // ';' within quoted expression
794 break;
797 p = pStart;
799 if (bQuoted)
800 p = lcl_ScanSylkString( p, rString, eVersion);
801 else
803 while (*p && *p != ';')
804 ++p;
805 rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
808 return p;
811 static void lcl_DoubleEscapeChar( OUString& rString, sal_Unicode cStr )
813 sal_Int32 n = 0;
814 while( ( n = rString.indexOf( cStr, n ) ) != -1 )
816 rString = rString.replaceAt( n, 0, OUString(cStr) );
817 n += 2;
821 static void lcl_WriteString( SvStream& rStrm, OUString& rString, sal_Unicode cQuote, sal_Unicode cEsc )
823 if (cEsc)
824 lcl_DoubleEscapeChar( rString, cEsc );
826 if (cQuote)
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 )
841 bool bOk = true;
843 sal_Unicode pSeps[2];
844 pSeps[0] = cSep;
845 pSeps[1] = 0;
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;
854 if( !bSingle)
855 bOk = StartPaste();
857 while( bOk )
859 OUString aLine;
860 OUString aCell;
861 SCROW nRow = nStartRow;
862 rStrm.Seek( nOldPos );
863 for( ;; )
865 rStrm.ReadUniOrByteStringLine( aLine, rStrm.GetStreamCharSet(), nArbitraryLineLengthLimit );
866 if( rStrm.IsEof() )
867 break;
868 SCCOL nCol = nStartCol;
869 const sal_Unicode* p = aLine.getStr();
870 while( *p )
872 aCell.clear();
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)
881 ++p;
882 if (!lcl_appendLineData( aCell, q, p))
883 bOverflowCell = true; // display warning on import
884 q = p;
886 if (*p)
887 ++p;
888 if (ValidCol(nCol) && ValidRow(nRow) )
890 if( bSingle )
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
900 if (!ValidRow(nRow))
901 bOverflowRow = true; // display warning on import
902 if (!ValidCol(nCol))
903 bOverflowCol = true; // display warning on import
905 ++nCol;
907 ++nRow;
910 if( !bData )
912 aRange.aEnd.SetCol( nEndCol );
913 aRange.aEnd.SetRow( nEndRow );
914 bOk = StartPaste();
915 bData = true;
917 else
918 break;
921 EndPaste();
922 if (bOk && mbImportBroadcast)
924 pDoc->BroadcastCells(aRange, SC_HINT_DATACHANGED);
925 pDocSh->PostDataChanged();
928 return bOk;
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) )
943 return bMultiLine;
945 if ( nColFormat == SC_COL_TEXT )
947 double fDummy;
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);
959 if ( bUseDocImport )
961 if(ScStringUtil::isMultiline(rStr))
963 ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
964 rEngine.SetText(rStr);
965 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
966 return true;
968 else
970 rDocImport.setStringCell(ScAddress(nCol, nRow, nTab), rStr);
971 return false;
973 } else
975 pDoc->SetTextCell(ScAddress(nCol, nRow, nTab), rStr);
976 return bMultiLine;
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);
986 double fVal;
987 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
989 // Numberformat will not be set to English
990 if ( bUseDocImport )
991 rDocImport.setNumericCell( ScAddress( nCol, nRow, nTab ), fVal );
992 else
993 pDoc->SetValue( nCol, nRow, nTab, fVal );
994 return bMultiLine;
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;
1010 case SC_COL_DMY:
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))
1026 if (!bInNum)
1028 bInNum = true;
1029 nStart[nFound] = nPos;
1030 ++nFound;
1032 nEnd[nFound-1] = nPos;
1034 else
1035 bInNum = false;
1038 if ( nFound == 1 )
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;
1068 nFound = 3;
1072 if ( nFound >= 3 )
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();
1080 if (!nMonth)
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 );
1113 bSecondCal = true;
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 );
1120 bSecondCal = true;
1126 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1127 if ( nYear < 100 )
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 )
1134 --nMonth;
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;
1142 if (nFound > 3)
1143 nHour = (sal_Int16) rStr.copy( nStart[3], nEnd[3]+1-nStart[3]).toInt32();
1144 if (nFound > 4)
1145 nMinute = (sal_Int16) rStr.copy( nStart[4], nEnd[4]+1-nStart[4]).toInt32();
1146 if (nFound > 5)
1147 nSecond = (sal_Int16) rStr.copy( nStart[5], nEnd[5]+1-nStart[5]).toInt32();
1148 if (nFound > 6)
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();
1169 fDays -= fDiff;
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
1178 if (nFound > 5)
1179 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1181 ScAddress aPos(nCol,nRow,nTab);
1182 if ( bUseDocImport )
1183 rDocImport.setNumericCell(aPos, fDays);
1184 else
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);
1204 else
1205 pDoc->SetString( nCol, nRow, nTab, rStr, &aParam );
1207 else
1209 bMultiLine = true;
1210 ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
1211 rEngine.SetText(rStr);
1212 if ( bUseDocImport )
1213 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
1214 else
1215 pDoc->SetEditText( ScAddress( nCol, nRow, nTab ), rEngine.CreateTextObject() );
1217 return bMultiLine;
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();
1224 if (nNext > nLen)
1225 nNext = nLen;
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] == ' ' )
1233 --nSpace;
1235 rbIsQuoted = (pStr[nStart] == '"' && pStr[nSpace-1] == '"');
1236 if (rbIsQuoted)
1238 bool bFits = (nSpace - nStart - 3 <= SAL_MAX_UINT16);
1239 OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1240 if (bFits)
1241 return rLine.copy(nStart+1, nSpace-nStart-2);
1242 else
1244 rbOverflowCell = true;
1245 return rLine.copy(nStart+1, SAL_MAX_UINT16);
1248 else
1250 bool bFits = (nSpace - nStart <= SAL_MAX_UINT16);
1251 OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1252 if (bFits)
1253 return rLine.copy(nStart, nSpace-nStart);
1254 else
1256 rbOverflowCell = true;
1257 return rLine.copy(nStart, SAL_MAX_UINT16);
1262 bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1264 if (!pExtOptions)
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 ) );
1310 OUString aLine;
1311 OUString aCell;
1312 sal_uInt16 i;
1313 SCROW nRow = nStartRow;
1315 while(--nSkipLines>0)
1317 aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr); // content is ignored
1318 if ( rStrm.IsEof() )
1319 break;
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);
1338 for( ;; )
1340 aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr);
1341 if ( rStrm.IsEof() && aLine.isEmpty() )
1342 break;
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
1354 // SC_COL_SKIP.
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
1360 if (nCol > MAXCOL)
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)
1369 nFmt = SC_COL_TEXT;
1371 bMultiLine |= lcl_PutString(
1372 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1373 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1374 pEnglishTransliteration.get(), pEnglishCalendar.get());
1376 ++nCol;
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
1388 // SC_COL_SKIP.
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
1402 break; // for
1405 if ( nFmt != SC_COL_SKIP )
1407 if (nCol > MAXCOL)
1408 bOverflowCol = true; // display warning on import
1409 else if (!bDetermineRange)
1411 if (bIsQuoted && bQuotedAsText)
1412 nFmt = SC_COL_TEXT;
1414 bMultiLine |= lcl_PutString(
1415 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1416 &aNumFormatter, bDetectNumFormat, aTransliteration,
1417 aCalendar, pEnglishTransliteration.get(), pEnglishCalendar.get());
1419 ++nCol;
1422 ++nSourceCol;
1425 if (nEndCol < nCol)
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 );
1434 ++nRow;
1435 if ( nRow > MAXROW )
1437 bOverflowRow = true; // display warning on import
1438 break; // for
1441 // so far nRow/nEndCol pointed to the next free
1442 if (nRow > nStartRow)
1443 --nRow;
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 )
1458 return false;
1462 rStrm.Seek( nOriginalStreamPos );
1463 nRow = nStartRow;
1464 if (!StartPaste())
1466 EndPaste(false);
1467 return false;
1471 bDetermineRange = !bDetermineRange; // toggle
1472 } while (!bDetermineRange);
1473 if ( !mbOverwriting )
1474 aDocImport.finalize();
1476 xProgress.reset(); // make room for AdjustRowHeight progress
1477 if (bRangeIsDetermined)
1478 EndPaste(false);
1480 if (mbImportBroadcast && !mbOverwriting)
1482 pDoc->BroadcastCells(aRange, SC_HINT_DATACHANGED);
1483 pDocSh->PostDataChanged();
1485 return true;
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
1496 // ustring stuff.
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 )
1508 rbIsQuoted = false;
1509 rField.clear();
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)
1518 ++pb;
1519 if (*pb == cStr)
1520 p = pb;
1522 if ( *p == cStr ) // String in quotes
1524 rbIsQuoted = true;
1525 const sal_Unicode* p1;
1526 p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DQM_ESCAPE, rbOverflowCell );
1527 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1528 p++;
1529 // Append remaining unquoted and undelimited data (dirty, dirty) to
1530 // this field.
1531 if (p > p1)
1533 if (!lcl_appendLineData( rField, p1, p))
1534 rbOverflowCell = true;
1536 if( *p )
1537 p++;
1539 else // up to delimiter
1541 const sal_Unicode* p0 = p;
1542 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1543 p++;
1544 if (!lcl_appendLineData( rField, p0, p))
1545 rbOverflowCell = true;
1546 if( *p )
1547 p++;
1549 if ( bMergeSeps ) // skip following delimiters
1551 while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
1552 p++;
1554 return p;
1557 namespace {
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)
1570 sal_Unicode c = *p;
1571 if (c == cSep)
1572 // separator found.
1573 return true;
1575 switch (c)
1577 case '\n':
1578 case '\r':
1579 // line break found.
1580 return true;
1581 default:
1585 return false;
1590 bool ScImportExport::Doc2Text( SvStream& rStrm )
1592 SCCOL nCol;
1593 SCROW nRow;
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 );
1604 OUString aCell;
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++)
1614 CellType eType;
1615 pDoc->GetCellType( nCol, nRow, nStartTab, eType );
1616 switch (eType)
1618 case CELLTYPE_FORMULA:
1620 if (bFormulas)
1622 pDoc->GetFormula( nCol, nRow, nStartTab, aCell );
1623 if( aCell.indexOf( cSep ) != -1 )
1624 lcl_WriteString( rStrm, aCell, cStr, cStr );
1625 else
1626 lcl_WriteSimpleString( rStrm, aCell );
1628 else
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 );
1646 else
1647 lcl_WriteSimpleString( rStrm, aCell );
1650 break;
1651 case CELLTYPE_VALUE:
1653 aCell = pDoc->GetString(nCol, nRow, nStartTab);
1654 lcl_WriteSimpleString( rStrm, aCell );
1656 break;
1657 case CELLTYPE_NONE:
1658 break;
1659 default:
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 );
1677 else
1678 lcl_WriteSimpleString( rStrm, aCell );
1681 if( nCol < nEndCol )
1682 lcl_WriteSimpleString( rStrm, OUString(cSep) );
1684 WriteUnicodeOrByteEndl( rStrm );
1685 if( rStrm.GetError() != SVSTREAM_OK )
1686 break;
1687 if( nSizeLimit && rStrm.Tell() > nSizeLimit )
1688 break;
1692 return rStrm.GetError() == SVSTREAM_OK;
1695 bool ScImportExport::Sylk2Doc( SvStream& rStrm )
1697 bool bOk = true;
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;
1713 if( !bSingle)
1714 bOk = StartPaste();
1716 while( bOk )
1718 OUString aLine;
1719 OUString aText;
1720 OString aByteLine;
1721 SCCOL nCol = nStartCol;
1722 SCROW nRow = nStartRow;
1723 SCCOL nRefCol = 1;
1724 SCROW nRefRow = 1;
1725 rStrm.Seek( nOldPos );
1726 for( ;; )
1728 //! allow unicode
1729 rStrm.ReadLine( aByteLine );
1730 aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
1731 if( rStrm.IsEof() )
1732 break;
1733 const sal_Unicode* p = aLine.getStr();
1734 sal_Unicode cTag = *p++;
1735 if( cTag == 'C' ) // Content
1737 if( *p++ != ';' )
1738 return false;
1739 while( *p )
1741 sal_Unicode ch = *p++;
1742 ch = ScGlobal::ToUpperAlpha( ch );
1743 switch( ch )
1745 case 'X':
1746 nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1747 break;
1748 case 'Y':
1749 nRow = OUString(p).toInt32() + nStartRow - 1;
1750 break;
1751 case 'C':
1752 nRefCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1753 break;
1754 case 'R':
1755 nRefRow = OUString(p).toInt32() + nStartRow - 1;
1756 break;
1757 case 'K':
1759 if( !bSingle &&
1760 ( nCol < nStartCol || nCol > nEndCol
1761 || nRow < nStartRow || nRow > nEndRow
1762 || nCol > MAXCOL || nRow > MAXROW ) )
1763 break;
1764 if( !bData )
1766 if( nRow > nEndRow )
1767 nEndRow = nRow;
1768 if( nCol > nEndCol )
1769 nEndCol = nCol;
1770 break;
1772 bool bText;
1773 if( *p == '"' )
1775 bText = true;
1776 aText.clear();
1777 p = lcl_ScanSylkString( p, aText, eVersion);
1779 else
1780 bText = false;
1781 const sal_Unicode* q = p;
1782 while( *q && *q != ';' )
1783 q++;
1784 if ( !(*q == ';' && *(q+1) == 'I') )
1785 { // don't ignore value
1786 if( bText )
1788 pDoc->EnsureTable(aRange.aStart.Tab());
1789 pDoc->SetTextCell(
1790 ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
1792 else
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 );
1801 break;
1802 case 'E':
1803 case 'M':
1805 if ( ch == 'M' )
1807 if ( nRefCol < nCol )
1808 nRefCol = nCol;
1809 if ( nRefRow < nRow )
1810 nRefRow = nRow;
1811 if ( !bData )
1813 if( nRefRow > nEndRow )
1814 nEndRow = nRefRow;
1815 if( nRefCol > nEndCol )
1816 nEndCol = nRefCol;
1819 if( !bMyDoc || !bData )
1820 break;
1821 aText = "=";
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 );
1831 if ( ch == 'M' )
1833 ScMarkData aMark;
1834 aMark.SelectTable( aPos.Tab(), true );
1835 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1836 nRefRow, aMark, EMPTY_OUSTRING, pCode );
1838 else
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
1846 break;
1848 while( *p && *p != ';' )
1849 p++;
1850 if( *p )
1851 p++;
1854 else if( cTag == 'F' ) // Format
1856 if( *p++ != ';' )
1857 return false;
1858 sal_Int32 nFormat = -1;
1859 while( *p )
1861 sal_Unicode ch = *p++;
1862 ch = ScGlobal::ToUpperAlpha( ch );
1863 switch( ch )
1865 case 'X':
1866 nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
1867 break;
1868 case 'Y':
1869 nRow = OUString(p).toInt32() + nStartRow - 1;
1870 break;
1871 case 'P' :
1872 if ( bData )
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 != ';' )
1879 p++;
1880 OUString aNumber(p0, p - p0);
1881 nFormat = aNumber.toInt32();
1883 break;
1885 while( *p && *p != ';' )
1886 p++;
1887 if( *p )
1888 p++;
1890 if ( !bData )
1892 if( nRow > nEndRow )
1893 nEndRow = nRow;
1894 if( nCol > nEndCol )
1895 nEndCol = nCol;
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;
1914 short nType;
1915 sal_uInt32 nKey;
1916 pDoc->GetFormatTable()->PutandConvertEntry( aCode, nCheckPos, nType, nKey,
1917 LANGUAGE_ENGLISH_US, ScGlobal::eLnge );
1918 if ( nCheckPos )
1919 nKey = 0;
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
1933 break;
1935 if( !bData )
1937 aRange.aEnd.SetCol( nEndCol );
1938 aRange.aEnd.SetRow( nEndRow );
1939 bOk = StartPaste();
1940 bData = true;
1942 else
1943 break;
1946 EndPaste();
1947 return bOk;
1950 bool ScImportExport::Doc2Sylk( SvStream& rStrm )
1952 SCCOL nCol;
1953 SCROW nRow;
1954 SCCOL nStartCol = aRange.aStart.Col();
1955 SCROW nStartRow = aRange.aStart.Row();
1956 SCCOL nEndCol = aRange.aEnd.Col();
1957 SCROW nEndRow = aRange.aEnd.Row();
1958 OUString aCellStr;
1959 OUString aValStr;
1960 lcl_WriteSimpleString( rStrm, OUString("ID;PCALCOOO32") );
1961 WriteUnicodeOrByteEndl( rStrm );
1963 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1965 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1967 OUString aBufStr;
1968 double nVal;
1969 bool bForm = false;
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;
1975 switch( eType )
1977 case CELLTYPE_FORMULA:
1978 bForm = bFormulas;
1979 if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1980 goto hasvalue;
1981 else
1982 goto hasstring;
1984 case CELLTYPE_VALUE:
1985 hasvalue:
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 );
1992 aBufStr = "C;X";
1993 aBufStr += OUString::number( c );
1994 aBufStr += ";Y";
1995 aBufStr += OUString::number( r );
1996 aBufStr += ";K";
1997 aBufStr += aValStr;
1998 lcl_WriteSimpleString( rStrm, aBufStr );
1999 goto checkformula;
2001 case CELLTYPE_STRING:
2002 case CELLTYPE_EDIT:
2003 hasstring:
2004 aCellStr = pDoc->GetString(nCol, nRow, aRange.aStart.Tab());
2005 aCellStr = aCellStr.replaceAll( OUString('\n'), OUString(SYLK_LF) );
2007 aBufStr = "C;X";
2008 aBufStr += OUString::number( c );
2009 aBufStr += ";Y";
2010 aBufStr += OUString::number( r );
2011 aBufStr += ";K";
2012 lcl_WriteSimpleString( rStrm, aBufStr );
2013 lcl_WriteString( rStrm, aCellStr, '"', ';' );
2015 checkformula:
2016 if( bForm )
2018 const ScFormulaCell* pFCell = aCell.mpFormula;
2019 switch ( pFCell->GetMatrixFlag() )
2021 case MM_REFERENCE :
2022 aCellStr.clear();
2023 break;
2024 default:
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);
2041 OUString aPrefix;
2042 switch ( pFCell->GetMatrixFlag() )
2044 case MM_FORMULA :
2045 { // diff expression with 'M' M$-extension
2046 SCCOL nC;
2047 SCROW nR;
2048 pFCell->GetMatColsRows( nC, nR );
2049 nC += c - 1;
2050 nR += r - 1;
2051 aPrefix = ";R";
2052 aPrefix += OUString::number( nR );
2053 aPrefix += ";C";
2054 aPrefix += OUString::number( nC );
2055 aPrefix += ";M";
2057 break;
2058 case MM_REFERENCE :
2059 { // diff expression with 'I' M$-extension
2060 ScAddress aPos;
2061 pFCell->GetMatrixOrigin( aPos );
2062 aPrefix = ";I;R";
2063 aPrefix += OUString::number( aPos.Row() - nStartRow + 1 );
2064 aPrefix += ";C";
2065 aPrefix += OUString::number( aPos.Col() - nStartCol + 1 );
2067 break;
2068 default:
2069 // formula Expression
2070 aPrefix = ";E";
2072 lcl_WriteSimpleString( rStrm, aPrefix );
2073 if ( !aCellStr.isEmpty() )
2074 lcl_WriteString( rStrm, aCellStr, 0, ';' );
2076 WriteUnicodeOrByteEndl( rStrm );
2077 break;
2079 default:
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 );
2110 return true;
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 );
2122 SCCOL nEndCol;
2123 SCROW nEndRow;
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();
2133 if (bOk)
2135 InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
2136 pDoc->DeleteAreaTab( aRange, nFlags );
2137 pImportDoc->CopyToDocument( aRange, nFlags, false, pDoc );
2138 EndPaste();
2141 delete pImportDoc;
2143 return bOk;
2146 bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
2148 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
2149 if (!pImp)
2150 return false;
2151 pImp->Read( rStrm, rBaseURL );
2152 aRange = pImp->GetRange();
2154 bool bOk = StartPaste();
2155 if (bOk)
2157 InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
2158 pDoc->DeleteAreaTab( aRange, nFlags );
2159 pImp->WriteToDocument();
2160 EndPaste();
2162 delete pImp;
2163 return bOk;
2166 bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
2168 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, true);
2169 if (!pImp)
2170 return false;
2171 pImp->Read( rStrm, rBaseURL );
2172 aRange = pImp->GetRange();
2174 bool bOk = StartPaste();
2175 if (bOk)
2177 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2178 // a Draw Layer but no Draw View -> create Draw Layer and View here
2179 if (pDocSh)
2180 pDocSh->MakeDrawLayer();
2182 InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
2183 pDoc->DeleteAreaTab( aRange, nFlags );
2185 if (pExtOptions)
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);
2193 else
2194 // Regular import, with no options.
2195 pImp->WriteToDocument();
2197 EndPaste();
2199 delete pImp;
2200 return bOk;
2203 #ifndef DISABLE_DYNLOADING
2205 class ScFormatFilterMissing : public ScFormatFilterPlugin {
2206 public:
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() {} }
2237 #else
2239 extern "C" {
2240 ScFormatFilterPlugin* ScFilterCreate();
2243 #endif
2245 typedef ScFormatFilterPlugin * (*FilterFn)(void);
2246 ScFormatFilterPlugin &ScFormatFilter::Get()
2248 static ScFormatFilterPlugin *plugin;
2250 if (plugin != NULL)
2251 return *plugin;
2253 #ifndef DISABLE_DYNLOADING
2254 OUString sFilterLib(SVLIBRARY("scfilt"));
2255 static ::osl::Module aModule;
2256 bool bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
2257 if (!bLoaded)
2258 bLoaded = aModule.load(sFilterLib);
2259 if (bLoaded)
2261 oslGenericFunction fn = aModule.getFunctionSymbol( OUString( "ScFilterCreate" ) );
2262 if (fn != NULL)
2263 plugin = reinterpret_cast<FilterFn>(fn)();
2265 if (plugin == NULL)
2266 plugin = new ScFormatFilterMissing();
2267 #else
2268 plugin = ScFilterCreate();
2269 #endif
2271 return *plugin;
2274 // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2275 // array.
2276 static inline const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
2277 sal_Unicode c )
2279 while (*pStr)
2281 if (*pStr == c)
2282 return pStr;
2283 ++pStr;
2285 return 0;
2288 OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
2289 const OUString& rFieldSeparators, sal_Unicode cFieldQuote )
2291 OUString aStr;
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();
2307 p += nLastOffset;
2308 while (*p)
2310 if (nQuotes)
2312 if (*p == cFieldQuote)
2314 if (bFieldStart)
2316 ++nQuotes;
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)
2329 ++nQuotes;
2332 else if (eQuoteState == FIELDEND_QUOTE)
2334 if (bFieldStart)
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);
2339 else
2340 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2343 else
2345 if (*p == cFieldQuote && bFieldStart)
2347 nQuotes = 1;
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.
2357 if (bFieldStart)
2358 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
2359 else
2360 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2363 // A quote character inside a field content does not start
2364 // a quote.
2365 ++p;
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.
2372 break;
2373 else
2375 nLastOffset = aStr.getLength();
2376 OUString aNext;
2377 rStream.ReadUniOrByteStringLine(aNext, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
2378 aStr += OUString('\n');
2379 aStr += aNext;
2383 return aStr;
2386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */