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