LCOV - code coverage report
Current view: top level - sc/source/ui/docshell - impex.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 533 1255 42.5 %
Date: 2015-06-13 12:38:46 Functions: 33 70 47.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "sc.hrc"
      21             : 
      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>
      27             : 
      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"
      53             : 
      54             : #include "globstr.hrc"
      55             : #include <vcl/svapp.hxx>
      56             : 
      57             : #include <boost/scoped_ptr.hpp>
      58             : 
      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;
      65             : 
      66             : namespace
      67             : {
      68             :     const char SYLK_LF[]  = "\x1b :";
      69             :     const char DOUBLE_SEMICOLON[] = ";;";
      70             :     const char DOUBLE_DOUBLEQUOTE[] = "\"\"";
      71             : }
      72             : 
      73             : enum SylkVersion
      74             : {
      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.
      79             : };
      80             : 
      81             : // Whole document without Undo
      82           9 : ScImportExport::ScImportExport( ScDocument* p )
      83          18 :     : 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          18 :       mExportTextOptions()
      90             : {
      91           9 :     pUndoDoc = NULL;
      92           9 :     pExtOptions = NULL;
      93           9 : }
      94             : 
      95             : // Insert am current cell without range(es)
      96           1 : ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
      97           2 :     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
      98             :       aRange( rPt ),
      99             :       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
     100             :       bFormulas( false ), bIncludeFiltered( true ),
     101           1 :       bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
     102             :       bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
     103             :       mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
     104           3 :       mExportTextOptions()
     105             : {
     106           1 :     pUndoDoc = NULL;
     107           1 :     pExtOptions = NULL;
     108           1 : }
     109             : 
     110             : //  ctor with a range is only used for export
     111             : //! ctor with a string (and bSingle=true) is also used for DdeSetData
     112           5 : ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
     113          10 :     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
     114             :       aRange( r ),
     115             :       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
     116             :       bFormulas( false ), bIncludeFiltered( true ),
     117           5 :       bAll( false ), bSingle( false ), bUndo( pDocSh != NULL ),
     118             :       bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
     119             :       mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
     120          15 :       mExportTextOptions()
     121             : {
     122           5 :     pUndoDoc = NULL;
     123           5 :     pExtOptions = NULL;
     124             :     // Only one sheet (table) supported
     125           5 :     aRange.aEnd.SetTab( aRange.aStart.Tab() );
     126           5 : }
     127             : 
     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           0 : ScImportExport::ScImportExport( ScDocument* p, const OUString& rPos )
     131           0 :     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
     132             :       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
     133             :       bFormulas( false ), bIncludeFiltered( true ),
     134           0 :       bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
     135             :       bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
     136             :       mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ),
     137           0 :       mExportTextOptions()
     138             : {
     139           0 :     pUndoDoc = NULL;
     140           0 :     pExtOptions = NULL;
     141             : 
     142           0 :     SCTAB nTab = ScDocShell::GetCurTab();
     143           0 :     aRange.aStart.SetTab( nTab );
     144           0 :     OUString aPos( rPos );
     145             :     // Named range?
     146           0 :     ScRangeName* pRange = pDoc->GetRangeName();
     147           0 :     if (pRange)
     148             :     {
     149           0 :         const ScRangeData* pData = pRange->findByUpperName(ScGlobal::pCharClass->uppercase(aPos));
     150           0 :         if (pData)
     151             :         {
     152           0 :             if( pData->HasType( RT_REFAREA )
     153           0 :                 || pData->HasType( RT_ABSAREA )
     154           0 :                 || pData->HasType( RT_ABSPOS ) )
     155             :             {
     156           0 :                 pData->GetSymbol(aPos);
     157             :             }
     158             :         }
     159             :     }
     160           0 :     formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
     161             :     // Range?
     162           0 :     if (aRange.Parse(aPos, pDoc, eConv) & SCA_VALID)
     163           0 :         bSingle = false;
     164             :     // Cell?
     165           0 :     else if (aRange.aStart.Parse(aPos, pDoc, eConv) & SCA_VALID)
     166           0 :         aRange.aEnd = aRange.aStart;
     167             :     else
     168           0 :         bAll = true;
     169           0 : }
     170             : 
     171          30 : ScImportExport::~ScImportExport()
     172             : {
     173          15 :     delete pUndoDoc;
     174          15 :     delete pExtOptions;
     175          15 : }
     176             : 
     177           3 : void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
     178             : {
     179           3 :     if ( pExtOptions )
     180           0 :         *pExtOptions = rOpt;
     181             :     else
     182           3 :         pExtOptions = new ScAsciiOptions( rOpt );
     183             : 
     184             :     //  "normal" Options
     185             : 
     186           3 :     cSep = ScAsciiOptions::GetWeightedFieldSep( rOpt.GetFieldSeps(), false);
     187           3 :     cStr = rOpt.GetTextSep();
     188           3 : }
     189             : 
     190           3 : void ScImportExport::SetFilterOptions(const OUString& rFilterOptions)
     191             : {
     192           3 :     maFilterOptions = rFilterOptions;
     193           3 : }
     194             : 
     195           0 : bool ScImportExport::IsFormatSupported( SotClipboardFormatId nFormat )
     196             : {
     197             :     return nFormat == SotClipboardFormatId::STRING
     198           0 :               || nFormat == SotClipboardFormatId::SYLK
     199           0 :               || nFormat == SotClipboardFormatId::LINK
     200           0 :               || nFormat == SotClipboardFormatId::HTML
     201           0 :               || nFormat == SotClipboardFormatId::HTML_SIMPLE
     202           0 :               || nFormat == SotClipboardFormatId::DIF;
     203             : }
     204             : 
     205             : // Prepare for Undo
     206           5 : bool ScImportExport::StartPaste()
     207             : {
     208           5 :     if ( !bAll )
     209             :     {
     210           1 :         ScEditableTester aTester( pDoc, aRange );
     211           1 :         if ( !aTester.IsEditable() )
     212             :         {
     213           0 :             ScopedVclPtrInstance<InfoBox> aInfoBox( Application::GetDefDialogParent(),
     214           0 :                                 ScGlobal::GetRscString( aTester.GetMessageId() ) );
     215           0 :             aInfoBox->Execute();
     216           0 :             return false;
     217             :         }
     218             :     }
     219           5 :     if( bUndo && pDocSh && pDoc->IsUndoEnabled())
     220             :     {
     221           1 :         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
     222           1 :         pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
     223           1 :         pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pUndoDoc );
     224             :     }
     225           5 :     return true;
     226             : }
     227             : 
     228             : // Create Undo/Redo actions, Invalidate/Repaint
     229           5 : void ScImportExport::EndPaste(bool bAutoRowHeight)
     230             : {
     231           9 :     bool bHeight = bAutoRowHeight && pDocSh && pDocSh->AdjustRowHeight(
     232           9 :                     aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
     233             : 
     234           5 :     if( pUndoDoc && pDoc->IsUndoEnabled() && pDocSh )
     235             :     {
     236           1 :         ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
     237           1 :         pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
     238           1 :         pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pRedoDoc );
     239           1 :         ScMarkData aDestMark;
     240           1 :         aDestMark.SetMarkArea(aRange);
     241           1 :         pDocSh->GetUndoManager()->AddUndoAction(
     242           1 :             new ScUndoPaste(pDocSh, aRange, aDestMark, pUndoDoc, pRedoDoc, IDF_ALL, NULL));
     243             :     }
     244           5 :     pUndoDoc = NULL;
     245           5 :     if( pDocSh )
     246             :     {
     247           5 :         if (!bHeight)
     248           5 :             pDocSh->PostPaint( aRange, PAINT_GRID );
     249           5 :         pDocSh->SetDocumentModified();
     250             :     }
     251           5 :     ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
     252           5 :     if ( pViewSh )
     253           0 :         pViewSh->UpdateInputHandler();
     254             : 
     255           5 : }
     256             : 
     257           0 : bool ScImportExport::ImportData( const OUString& /* rMimeType */,
     258             :                      const ::com::sun::star::uno::Any & /* rValue */ )
     259             : {
     260             :     OSL_ENSURE( false, "Implementation is missing" );
     261           0 :     return false;
     262             : }
     263             : 
     264           5 : bool ScImportExport::ExportData( const OUString& rMimeType,
     265             :                                  ::com::sun::star::uno::Any & rValue )
     266             : {
     267           5 :     SvMemoryStream aStrm;
     268             :     // mba: no BaseURL for data exchange
     269          10 :     if( ExportStream( aStrm, OUString(),
     270          10 :                 SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
     271             :     {
     272           5 :         aStrm.WriteUChar( 0 );
     273          15 :         rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
     274           5 :                                         static_cast<sal_Int8 const *>(aStrm.GetData()),
     275          10 :                                         aStrm.Seek( STREAM_SEEK_TO_END ) );
     276           5 :         return true;
     277             :     }
     278           0 :     return false;
     279             : }
     280             : 
     281           1 : bool ScImportExport::ImportString( const OUString& rText, SotClipboardFormatId nFmt )
     282             : {
     283           1 :     switch ( nFmt )
     284             :     {
     285             :         // formats supporting unicode
     286             :         case SotClipboardFormatId::STRING :
     287             :         {
     288           1 :             ScImportStringStream aStrm( rText);
     289           1 :             return ImportStream( aStrm, OUString(), nFmt );
     290             :             // ImportStream must handle RTL_TEXTENCODING_UNICODE
     291             :         }
     292             :         default:
     293             :         {
     294           0 :             rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
     295           0 :             OString aTmp( rText.getStr(), rText.getLength(), eEnc );
     296           0 :             SvMemoryStream aStrm( const_cast<char *>(aTmp.getStr()), aTmp.getLength() * sizeof(sal_Char), StreamMode::READ );
     297           0 :             aStrm.SetStreamCharSet( eEnc );
     298           0 :             SetNoEndianSwap( aStrm );       //! no swapping in memory
     299           0 :             return ImportStream( aStrm, OUString(), nFmt );
     300             :         }
     301             :     }
     302             : }
     303             : 
     304           0 : bool ScImportExport::ExportString( OUString& rText, SotClipboardFormatId nFmt )
     305             : {
     306             :     OSL_ENSURE( nFmt == SotClipboardFormatId::STRING, "ScImportExport::ExportString: Unicode not supported for other formats than SotClipboardFormatId::STRING" );
     307           0 :     if ( nFmt != SotClipboardFormatId::STRING )
     308             :     {
     309           0 :         rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
     310           0 :         OString aTmp;
     311           0 :         bool bOk = ExportByteString( aTmp, eEnc, nFmt );
     312           0 :         rText = OStringToOUString( aTmp, eEnc );
     313           0 :         return bOk;
     314             :     }
     315             :     //  nSizeLimit not needed for OUString
     316             : 
     317           0 :     SvMemoryStream aStrm;
     318           0 :     aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
     319           0 :     SetNoEndianSwap( aStrm );       //! no swapping in memory
     320             :     // mba: no BaseURL for data exc
     321           0 :     if( ExportStream( aStrm, OUString(), nFmt ) )
     322             :     {
     323           0 :         aStrm.WriteUInt16( 0 );
     324           0 :         aStrm.Seek( STREAM_SEEK_TO_END );
     325             : 
     326           0 :         rText = OUString( static_cast<const sal_Unicode*>(aStrm.GetData()) );
     327           0 :         return true;
     328             :     }
     329           0 :     rText.clear();
     330           0 :     return false;
     331             : 
     332             :     // ExportStream must handle RTL_TEXTENCODING_UNICODE
     333             : }
     334             : 
     335           0 : bool ScImportExport::ExportByteString( OString& rText, rtl_TextEncoding eEnc, SotClipboardFormatId nFmt )
     336             : {
     337             :     OSL_ENSURE( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
     338           0 :     if ( eEnc == RTL_TEXTENCODING_UNICODE )
     339           0 :         eEnc = osl_getThreadTextEncoding();
     340             : 
     341           0 :     if (!nSizeLimit)
     342           0 :         nSizeLimit = SAL_MAX_UINT16;
     343             : 
     344           0 :     SvMemoryStream aStrm;
     345           0 :     aStrm.SetStreamCharSet( eEnc );
     346           0 :     SetNoEndianSwap( aStrm );       //! no swapping in memory
     347             :     // mba: no BaseURL for data exchange
     348           0 :     if( ExportStream( aStrm, OUString(), nFmt ) )
     349             :     {
     350           0 :         aStrm.WriteChar( 0 );
     351           0 :         aStrm.Seek( STREAM_SEEK_TO_END );
     352           0 :         if( aStrm.Tell() <= nSizeLimit )
     353             :         {
     354           0 :             rText = static_cast<const sal_Char*>(aStrm.GetData());
     355           0 :             return true;
     356             :         }
     357             :     }
     358           0 :     rText.clear();
     359           0 :     return false;
     360             : }
     361             : 
     362           7 : bool ScImportExport::ImportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
     363             : {
     364           7 :     if( nFmt == SotClipboardFormatId::STRING )
     365             :     {
     366           3 :         if( ExtText2Doc( rStrm ) )      // evaluate pExtOptions
     367           3 :             return true;
     368             :     }
     369           4 :     if( nFmt == SotClipboardFormatId::SYLK )
     370             :     {
     371           4 :         if( Sylk2Doc( rStrm ) )
     372           4 :             return true;
     373             :     }
     374           0 :     if( nFmt == SotClipboardFormatId::DIF )
     375             :     {
     376           0 :         if( Dif2Doc( rStrm ) )
     377           0 :             return true;
     378             :     }
     379           0 :     if( nFmt == SotClipboardFormatId::RTF )
     380             :     {
     381           0 :         if( RTF2Doc( rStrm, rBaseURL ) )
     382           0 :             return true;
     383             :     }
     384           0 :     if( nFmt == SotClipboardFormatId::LINK )
     385           0 :         return true;            // Link-Import?
     386           0 :     if ( nFmt == SotClipboardFormatId::HTML )
     387             :     {
     388           0 :         if( HTML2Doc( rStrm, rBaseURL ) )
     389           0 :             return true;
     390             :     }
     391           0 :     if ( nFmt == SotClipboardFormatId::HTML_SIMPLE )
     392             :     {
     393           0 :         MSE40HTMLClipFormatObj aMSE40ClpObj;                // needed to skip the header data
     394           0 :         SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
     395           0 :         if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
     396           0 :             return true;
     397             :     }
     398             : 
     399           0 :     return false;
     400             : }
     401             : 
     402           8 : bool ScImportExport::ExportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
     403             : {
     404           8 :     if( nFmt == SotClipboardFormatId::STRING )
     405             :     {
     406           5 :         if( Doc2Text( rStrm ) )
     407           5 :             return true;
     408             :     }
     409           3 :     if( nFmt == SotClipboardFormatId::SYLK )
     410             :     {
     411           0 :         if( Doc2Sylk( rStrm ) )
     412           0 :             return true;
     413             :     }
     414           3 :     if( nFmt == SotClipboardFormatId::DIF )
     415             :     {
     416           0 :         if( Doc2Dif( rStrm ) )
     417           0 :             return true;
     418             :     }
     419           3 :     if( nFmt == SotClipboardFormatId::LINK && !bAll )
     420             :     {
     421           0 :         OUString aDocName;
     422           0 :         if ( pDoc->IsClipboard() )
     423           0 :             aDocName = ScGlobal::GetClipDocName();
     424             :         else
     425             :         {
     426           0 :             SfxObjectShell* pShell = pDoc->GetDocumentShell();
     427           0 :             if (pShell)
     428           0 :                 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
     429             :         }
     430             : 
     431             :         OSL_ENSURE( !aDocName.isEmpty(), "ClipBoard document has no name! :-/" );
     432           0 :         if( !aDocName.isEmpty() )
     433             :         {
     434             :             // Always use Calc A1 syntax for paste link.
     435           0 :             OUString aRefName;
     436           0 :             sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
     437           0 :             if( bSingle )
     438           0 :                 aRefName = aRange.aStart.Format(nFlags, pDoc, formula::FormulaGrammar::CONV_OOO);
     439             :             else
     440             :             {
     441           0 :                 if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
     442           0 :                     nFlags |= SCA_TAB2_3D;
     443           0 :                 aRefName = aRange.Format(nFlags, pDoc, formula::FormulaGrammar::CONV_OOO);
     444             :             }
     445           0 :             OUString aAppName = Application::GetAppName();
     446             : 
     447             :             // extra bits are used to tell the client to prefer external
     448             :             // reference link.
     449           0 :             OUString aExtraBits("calc:extref");
     450             : 
     451           0 :             WriteUnicodeOrByteString( rStrm, aAppName, true );
     452           0 :             WriteUnicodeOrByteString( rStrm, aDocName, true );
     453           0 :             WriteUnicodeOrByteString( rStrm, aRefName, true );
     454           0 :             WriteUnicodeOrByteString( rStrm, aExtraBits, true );
     455           0 :             if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
     456           0 :                 rStrm.WriteUInt16( 0 );
     457             :             else
     458           0 :                 rStrm.WriteChar( 0 );
     459           0 :             return rStrm.GetError() == SVSTREAM_OK;
     460           0 :         }
     461             :     }
     462           3 :     if( nFmt == SotClipboardFormatId::HTML )
     463             :     {
     464           3 :         if( Doc2HTML( rStrm, rBaseURL ) )
     465           3 :             return true;
     466             :     }
     467           0 :     if( nFmt == SotClipboardFormatId::RTF )
     468             :     {
     469           0 :         if( Doc2RTF( rStrm ) )
     470           0 :             return true;
     471             :     }
     472             : 
     473           0 :     return false;
     474             : }
     475             : 
     476           5 : void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const OUString& rString, bool bZero )
     477             : {
     478           5 :     rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
     479           5 :     if ( eEnc == RTL_TEXTENCODING_UNICODE )
     480             :     {
     481           0 :         if ( !IsEndianSwap( rStrm ) )
     482           0 :             rStrm.Write( rString.getStr(), rString.getLength() * sizeof(sal_Unicode) );
     483             :         else
     484             :         {
     485           0 :             const sal_Unicode* p = rString.getStr();
     486           0 :             const sal_Unicode* const pStop = p + rString.getLength();
     487           0 :             while ( p < pStop )
     488             :             {
     489           0 :                 rStrm.WriteUInt16( *p );
     490             :             }
     491             :         }
     492           0 :         if ( bZero )
     493           0 :             rStrm.WriteUInt16( 0 );
     494             :     }
     495             :     else
     496             :     {
     497           5 :         OString aByteStr(OUStringToOString(rString, eEnc));
     498           5 :         rStrm.WriteCharPtr( aByteStr.getStr() );
     499           5 :         if ( bZero )
     500           0 :             rStrm.WriteChar( 0 );
     501             :     }
     502           5 : }
     503             : 
     504             : // This function could be replaced by endlub()
     505           5 : void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
     506             : {
     507           5 :     if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
     508             :     {   // same as endl() but unicode
     509           0 :         switch ( rStrm.GetLineDelimiter() )
     510             :         {
     511             :             case LINEEND_CR :
     512           0 :                 rStrm.WriteUInt16( '\r' );
     513           0 :             break;
     514             :             case LINEEND_LF :
     515           0 :                 rStrm.WriteUInt16( '\n' );
     516           0 :             break;
     517             :             default:
     518           0 :                 rStrm.WriteUInt16( '\r' ).WriteUInt16( '\n' );
     519             :         }
     520             :     }
     521             :     else
     522           5 :         endl( rStrm );
     523           5 : }
     524             : 
     525             : enum QuoteType
     526             : {
     527             :     FIELDSTART_QUOTE,
     528             :     FIRST_QUOTE,
     529             :     SECOND_QUOTE,
     530             :     FIELDEND_QUOTE,
     531             :     DONTKNOW_QUOTE
     532             : };
     533             : 
     534             : /** Determine if *p is a quote that ends a quoted field.
     535             : 
     536             :     Precondition: we are parsing a quoted field already and *p is a quote.
     537             : 
     538             :     @return
     539             :         FIELDEND_QUOTE if end of field quote
     540             :         DONTKNOW_QUOTE anything else
     541             :  */
     542         484 : static QuoteType lcl_isFieldEndQuote( const sal_Unicode* p, const sal_Unicode* pSeps )
     543             : {
     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         484 :     const sal_Unicode cBlank = ' ';
     548         484 :     if (p[1] == cBlank && ScGlobal::UnicodeStrChr( pSeps, cBlank))
     549           0 :         return FIELDEND_QUOTE;
     550         988 :     while (p[1] == cBlank)
     551          20 :         ++p;
     552         484 :     if (!p[1] || ScGlobal::UnicodeStrChr( pSeps, p[1]))
     553         386 :         return FIELDEND_QUOTE;
     554          98 :     return DONTKNOW_QUOTE;
     555             : }
     556             : 
     557             : /** Determine if *p is a quote that is escaped by being doubled or ends a
     558             :     quoted field.
     559             : 
     560             :     Precondition: *p is a quote.
     561             : 
     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.
     568             : 
     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!
     577             :  */
     578         290 : static QuoteType lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes, const sal_Unicode* p,
     579             :         const sal_Unicode* pSeps, sal_Unicode cStr )
     580             : {
     581         290 :     if ((nQuotes % 2) == 0)
     582             :     {
     583          24 :         if (p[-1] == cStr)
     584          24 :             return SECOND_QUOTE;
     585             :         else
     586             :         {
     587             :             SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
     588           0 :             return FIELDSTART_QUOTE;
     589             :         }
     590             :     }
     591         266 :     if (p[1] == cStr)
     592          24 :         return FIRST_QUOTE;
     593         242 :     return lcl_isFieldEndQuote( p, pSeps);
     594             : }
     595             : 
     596             : /** Append characters of [p1,p2) to rField.
     597             : 
     598             :     @returns TRUE if ok; FALSE if data overflow, truncated
     599             :  */
     600         395 : static bool lcl_appendLineData( OUString& rField, const sal_Unicode* p1, const sal_Unicode* p2 )
     601             : {
     602             :     OSL_ENSURE( rField.getLength() + (p2 - p1) <= SAL_MAX_UINT16, "lcl_appendLineData: data overflow");
     603         395 :     if (rField.getLength() + (p2 - p1) <= SAL_MAX_UINT16)
     604             :     {
     605         395 :         rField += OUString( p1, sal::static_int_cast<sal_Int32>( p2 - p1 ) );
     606         395 :         return true;
     607             :     }
     608             :     else
     609             :     {
     610           0 :         rField += OUString( p1, SAL_MAX_UINT16 - rField.getLength() );
     611           0 :         return false;
     612             :     }
     613             : }
     614             : 
     615             : enum DoubledQuoteMode
     616             : {
     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
     622             : };
     623             : 
     624         193 : static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rString,
     625             :             const sal_Unicode* pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool& rbOverflowCell )
     626             : {
     627         193 :     if (eMode != DQM_KEEP_ALL)
     628         193 :         p++;    //! jump over opening quote
     629             :     bool bCont;
     630         217 :     do
     631             :     {
     632         217 :         bCont = false;
     633         217 :         const sal_Unicode* p0 = p;
     634             :         for( ;; )
     635             :         {
     636        2099 :             if( !*p )
     637           0 :                 break;
     638        2099 :             if( *p == cStr )
     639             :             {
     640         266 :                 if ( *++p != cStr )
     641             :                 {
     642             :                     // break or continue for loop
     643         242 :                     if (eMode == DQM_ESCAPE)
     644             :                     {
     645         242 :                         if (lcl_isFieldEndQuote( p-1, pSeps) == FIELDEND_QUOTE)
     646         193 :                             break;
     647             :                         else
     648          49 :                             continue;
     649             :                     }
     650             :                     else
     651           0 :                         break;
     652             :                 }
     653             :                 // doubled quote char
     654          24 :                 switch ( eMode )
     655             :                 {
     656             :                     case DQM_KEEP_ALL :
     657             :                     case DQM_KEEP :
     658           0 :                         p++;            // both for us (not breaking for-loop)
     659           0 :                     break;
     660             :                     case DQM_ESCAPE :
     661          24 :                         p++;            // one for us (breaking for-loop)
     662          24 :                         bCont = true;   // and more
     663          24 :                     break;
     664             :                     case DQM_CONCAT :
     665           0 :                         if ( p0+1 < p )
     666             :                         {
     667             :                             // first part
     668           0 :                             if (!lcl_appendLineData( rString, p0, p-1))
     669           0 :                                 rbOverflowCell = true;
     670             :                         }
     671           0 :                         p0 = ++p;       // text of next part starts here
     672           0 :                     break;
     673             :                     case DQM_SEPARATE :
     674             :                                         // positioned on next opening quote
     675           0 :                     break;
     676             :                 }
     677          24 :                 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
     678             :                     break;
     679             :             }
     680             :             else
     681        1833 :                 p++;
     682             :         }
     683         217 :         if ( p0 < p )
     684             :         {
     685         217 :             if (!lcl_appendLineData( rString, p0, ((eMode != DQM_KEEP_ALL && (*p || *(p-1) == cStr)) ? p-1 : p)))
     686           0 :                 rbOverflowCell = true;
     687        1882 :         }
     688             :     } while ( bCont );
     689         193 :     return p;
     690             : }
     691             : 
     692         941 : static void lcl_UnescapeSylk( OUString & rString, SylkVersion eVersion )
     693             : {
     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         941 :     if (eVersion >= SYLK_OOO32)
     698         496 :         rString = rString.replaceAll( OUString(DOUBLE_SEMICOLON), OUString(';') );
     699             :     else
     700         445 :         rString = rString.replaceAll( OUString(DOUBLE_DOUBLEQUOTE), OUString('"') );
     701             : 
     702         941 :     rString = rString.replaceAll( OUString(SYLK_LF), OUString('\n') );
     703         941 : }
     704             : 
     705         941 : static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
     706             :         OUString& rString, SylkVersion eVersion )
     707             : {
     708         941 :     const sal_Unicode* pStartQuote = p;
     709         941 :     const sal_Unicode* pEndQuote = 0;
     710       16714 :     while( *(++p) )
     711             :     {
     712       14832 :         if( *p == '"' )
     713             :         {
     714         941 :             pEndQuote = p;
     715         941 :             if (eVersion >= SYLK_OOO32)
     716             :             {
     717         496 :                 if (*(p+1) == ';')
     718             :                 {
     719           0 :                     if (*(p+2) == ';')
     720             :                     {
     721           0 :                         p += 2;     // escaped ';'
     722           0 :                         pEndQuote = 0;
     723             :                     }
     724             :                     else
     725           0 :                         break;      // end field
     726             :                 }
     727             :             }
     728             :             else
     729             :             {
     730         445 :                 if (*(p+1) == '"')
     731             :                 {
     732           0 :                     ++p;            // escaped '"'
     733           0 :                     pEndQuote = 0;
     734             :                 }
     735         445 :                 else if (*(p+1) == ';')
     736           0 :                     break;          // end field
     737             :             }
     738             :         }
     739             :     }
     740         941 :     if (!pEndQuote)
     741           0 :         pEndQuote = p;  // Take all data as string.
     742         941 :     rString += OUString(pStartQuote + 1, sal::static_int_cast<sal_Int32>( pEndQuote - pStartQuote - 1 ) );
     743         941 :     lcl_UnescapeSylk( rString, eVersion);
     744         941 :     return p;
     745             : }
     746             : 
     747           0 : static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
     748             :         OUString& rString, SylkVersion eVersion )
     749             : {
     750           0 :     const sal_Unicode* pStart = p;
     751           0 :     if (eVersion >= SYLK_OOO32)
     752             :     {
     753           0 :         while (*p)
     754             :         {
     755           0 :             if (*p == ';')
     756             :             {
     757           0 :                 if (*(p+1) == ';')
     758           0 :                     ++p;        // escaped ';'
     759             :                 else
     760           0 :                     break;      // end field
     761             :             }
     762           0 :             ++p;
     763             :         }
     764           0 :         rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
     765           0 :         lcl_UnescapeSylk( rString, eVersion);
     766             :     }
     767             :     else
     768             :     {
     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           0 :         bool bQuoted = false;
     778           0 :         if (*p == '"')
     779             :         {
     780             :             // May be a quoted expression or just a string constant expression
     781             :             // with quotes.
     782           0 :             while (*(++p))
     783             :             {
     784           0 :                 if (*p == '"')
     785             :                 {
     786           0 :                     if (*(p+1) == '"')
     787           0 :                         ++p;            // escaped '"'
     788             :                     else
     789           0 :                         break;          // closing '"', had no ';' yet
     790             :                 }
     791           0 :                 else if (*p == ';')
     792             :                 {
     793           0 :                     bQuoted = true;     // ';' within quoted expression
     794           0 :                     break;
     795             :                 }
     796             :             }
     797           0 :             p = pStart;
     798             :         }
     799           0 :         if (bQuoted)
     800           0 :             p = lcl_ScanSylkString( p, rString, eVersion);
     801             :         else
     802             :         {
     803           0 :             while (*p && *p != ';')
     804           0 :                 ++p;
     805           0 :             rString += OUString( pStart, sal::static_int_cast<sal_Int32>( p - pStart));
     806             :         }
     807             :     }
     808           0 :     return p;
     809             : }
     810             : 
     811           0 : static void lcl_DoubleEscapeChar( OUString& rString, sal_Unicode cStr )
     812             : {
     813           0 :     sal_Int32 n = 0;
     814           0 :     while( ( n = rString.indexOf( cStr, n ) ) != -1 )
     815             :     {
     816           0 :         rString = rString.replaceAt( n, 0, OUString(cStr) );
     817           0 :         n += 2;
     818             :     }
     819           0 : }
     820             : 
     821           0 : static void lcl_WriteString( SvStream& rStrm, OUString& rString, sal_Unicode cQuote, sal_Unicode cEsc )
     822             : {
     823           0 :     if (cEsc)
     824           0 :         lcl_DoubleEscapeChar( rString, cEsc );
     825             : 
     826           0 :     if (cQuote)
     827             :     {
     828           0 :         rString = OUString(cQuote) + rString + OUString(cQuote);
     829             :     }
     830             : 
     831           0 :     ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
     832           0 : }
     833             : 
     834           5 : static inline void lcl_WriteSimpleString( SvStream& rStrm, const OUString& rString )
     835             : {
     836           5 :     ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
     837           5 : }
     838             : 
     839           0 : bool ScImportExport::Text2Doc( SvStream& rStrm )
     840             : {
     841           0 :     bool bOk = true;
     842             : 
     843             :     sal_Unicode pSeps[2];
     844           0 :     pSeps[0] = cSep;
     845           0 :     pSeps[1] = 0;
     846             : 
     847           0 :     SCCOL nStartCol = aRange.aStart.Col();
     848           0 :     SCROW nStartRow = aRange.aStart.Row();
     849           0 :     SCCOL nEndCol = aRange.aEnd.Col();
     850           0 :     SCROW nEndRow = aRange.aEnd.Row();
     851           0 :     sal_uLong  nOldPos = rStrm.Tell();
     852           0 :     rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
     853           0 :     bool   bData = !bSingle;
     854           0 :     if( !bSingle)
     855           0 :         bOk = StartPaste();
     856             : 
     857           0 :     while( bOk )
     858             :     {
     859           0 :         OUString aLine;
     860           0 :         OUString aCell;
     861           0 :         SCROW nRow = nStartRow;
     862           0 :         rStrm.Seek( nOldPos );
     863             :         for( ;; )
     864             :         {
     865           0 :             rStrm.ReadUniOrByteStringLine( aLine, rStrm.GetStreamCharSet(), nArbitraryLineLengthLimit );
     866           0 :             if( rStrm.IsEof() )
     867           0 :                 break;
     868           0 :             SCCOL nCol = nStartCol;
     869           0 :             const sal_Unicode* p = aLine.getStr();
     870           0 :             while( *p )
     871             :             {
     872           0 :                 aCell.clear();
     873           0 :                 const sal_Unicode* q = p;
     874           0 :                 while (*p && *p != cSep)
     875             :                 {
     876             :                     // Always look for a pairing quote and ignore separator in between.
     877           0 :                     while (*p && *p == cStr)
     878           0 :                         q = p = lcl_ScanString( p, aCell, pSeps, cStr, DQM_KEEP_ALL, bOverflowCell );
     879             :                     // All until next separator or quote.
     880           0 :                     while (*p && *p != cSep && *p != cStr)
     881           0 :                         ++p;
     882           0 :                     if (!lcl_appendLineData( aCell, q, p))
     883           0 :                         bOverflowCell = true;   // display warning on import
     884           0 :                     q = p;
     885             :                 }
     886           0 :                 if (*p)
     887           0 :                     ++p;
     888           0 :                 if (ValidCol(nCol) && ValidRow(nRow) )
     889             :                 {
     890           0 :                     if( bSingle )
     891             :                     {
     892           0 :                         if (nCol>nEndCol) nEndCol = nCol;
     893           0 :                         if (nRow>nEndRow) nEndRow = nRow;
     894             :                     }
     895           0 :                     if( bData && nCol <= nEndCol && nRow <= nEndRow )
     896           0 :                         pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
     897             :                 }
     898             :                 else                            // zuviele Spalten/Zeilen
     899             :                 {
     900           0 :                     if (!ValidRow(nRow))
     901           0 :                         bOverflowRow = true;    // display warning on import
     902           0 :                     if (!ValidCol(nCol))
     903           0 :                         bOverflowCol = true;    // display warning on import
     904             :                 }
     905           0 :                 ++nCol;
     906             :             }
     907           0 :             ++nRow;
     908           0 :         }
     909             : 
     910           0 :         if( !bData )
     911             :         {
     912           0 :             aRange.aEnd.SetCol( nEndCol );
     913           0 :             aRange.aEnd.SetRow( nEndRow );
     914           0 :             bOk = StartPaste();
     915           0 :             bData = true;
     916             :         }
     917             :         else
     918           0 :             break;
     919           0 :     }
     920             : 
     921           0 :     EndPaste();
     922           0 :     if (bOk && mbImportBroadcast)
     923             :     {
     924           0 :         pDoc->BroadcastCells(aRange, SC_HINT_DATACHANGED);
     925           0 :         pDocSh->PostDataChanged();
     926             :     }
     927             : 
     928           0 :     return bOk;
     929             : }
     930             : 
     931             : //  Extended Ascii-Import
     932             : 
     933         364 : 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 )
     939             : {
     940         364 :     ScDocument* pDoc = &rDocImport.getDoc();
     941         364 :     bool bMultiLine = false;
     942         364 :     if ( nColFormat == SC_COL_SKIP || rStr.isEmpty() || !ValidCol(nCol) || !ValidRow(nRow) )
     943          74 :         return bMultiLine;
     944             : 
     945         290 :     if ( nColFormat == SC_COL_TEXT )
     946             :     {
     947             :         double fDummy;
     948           0 :         sal_uInt32 nIndex = 0;
     949           0 :         if (pFormatter->IsNumberFormat(rStr, nIndex, fDummy))
     950             :         {
     951             :             // Set the format of this cell to Text.
     952           0 :             sal_uInt32 nFormat = pFormatter->GetStandardFormat(css::util::NumberFormat::TEXT);
     953           0 :             ScPatternAttr aNewAttrs(pDoc->GetPool());
     954           0 :             SfxItemSet& rSet = aNewAttrs.GetItemSet();
     955           0 :             rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
     956           0 :             pDoc->ApplyPattern(nCol, nRow, nTab, aNewAttrs);
     957             : 
     958             :         }
     959           0 :         if ( bUseDocImport )
     960             :         {
     961           0 :             if(ScStringUtil::isMultiline(rStr))
     962             :             {
     963           0 :                 ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
     964           0 :                 rEngine.SetText(rStr);
     965           0 :                 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
     966           0 :                 return true;
     967             :             }
     968             :             else
     969             :             {
     970           0 :                 rDocImport.setStringCell(ScAddress(nCol, nRow, nTab), rStr);
     971           0 :                 return false;
     972             :             }
     973             :         } else
     974             :         {
     975           0 :             pDoc->SetTextCell(ScAddress(nCol, nRow, nTab), rStr);
     976           0 :             return bMultiLine;
     977             :         }
     978             :     }
     979             : 
     980         290 :     if ( nColFormat == SC_COL_ENGLISH )
     981             :     {
     982             :         //! SetString with Extra-Flag ???
     983             : 
     984           0 :         SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
     985           0 :         sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
     986             :         double fVal;
     987           0 :         if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
     988             :         {
     989             :             // Numberformat will not be set to English
     990           0 :             if ( bUseDocImport )
     991           0 :                 rDocImport.setNumericCell( ScAddress( nCol, nRow, nTab ), fVal );
     992             :             else
     993           0 :                 pDoc->SetValue( nCol, nRow, nTab, fVal );
     994           0 :             return bMultiLine;
     995             :         }
     996             :         // else, continue with SetString
     997             :     }
     998         290 :     else if ( nColFormat != SC_COL_STANDARD ) // Datumformats
     999             :     {
    1000           0 :         const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
    1001           0 :         sal_Int32 nLen = rStr.getLength();
    1002             :         sal_Int32 nStart[nMaxNumberParts];
    1003             :         sal_Int32 nEnd[nMaxNumberParts];
    1004             : 
    1005             :         sal_uInt16 nDP, nMP, nYP;
    1006           0 :         switch ( nColFormat )
    1007             :         {
    1008           0 :             case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
    1009           0 :             case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
    1010             :             case SC_COL_DMY:
    1011           0 :             default:         nDP = 0; nMP = 1; nYP = 2; break;
    1012             :         }
    1013             : 
    1014           0 :         sal_uInt16 nFound = 0;
    1015           0 :         bool bInNum = false;
    1016           0 :         for ( sal_Int32 nPos=0; nPos<nLen && (bInNum ||
    1017             :                     nFound<nMaxNumberParts); nPos++ )
    1018             :         {
    1019           0 :             if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
    1020           0 :                     nPos <= nStart[nFound]+2 && rStr[nPos] == 'T')
    1021           0 :                 bInNum = false;     // ISO-8601: YYYY-MM-DDThh:mm...
    1022           0 :             else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
    1023           0 :                         && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
    1024           0 :                     || ScGlobal::pCharClass->isDigit( rStr, nPos))
    1025             :             {
    1026           0 :                 if (!bInNum)
    1027             :                 {
    1028           0 :                     bInNum = true;
    1029           0 :                     nStart[nFound] = nPos;
    1030           0 :                     ++nFound;
    1031             :                 }
    1032           0 :                 nEnd[nFound-1] = nPos;
    1033             :             }
    1034             :             else
    1035           0 :                 bInNum = false;
    1036             :         }
    1037             : 
    1038           0 :         if ( nFound == 1 )
    1039             :         {
    1040             :             //  try to break one number (without separators) into date fields
    1041             : 
    1042           0 :             sal_Int32 nDateStart = nStart[0];
    1043           0 :             sal_Int32 nDateLen = nEnd[0] + 1 - nDateStart;
    1044             : 
    1045           0 :             if ( nDateLen >= 5 && nDateLen <= 8 &&
    1046           0 :                     ScGlobal::pCharClass->isNumeric( rStr.copy( nDateStart, nDateLen ) ) )
    1047             :             {
    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
    1051             : 
    1052           0 :                 bool bLongYear = ( nDateLen >= 7 );
    1053           0 :                 bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
    1054             : 
    1055           0 :                 sal_uInt16 nFieldStart = nDateStart;
    1056           0 :                 for (sal_uInt16 nPos=0; nPos<3; nPos++)
    1057             :                 {
    1058           0 :                     sal_uInt16 nFieldEnd = nFieldStart + 1;     // default: 2 digits
    1059           0 :                     if ( bLongYear && nPos == nYP )
    1060           0 :                         nFieldEnd += 2;                     // 2 extra digits for long year
    1061           0 :                     if ( bShortFirst && nPos == 0 )
    1062           0 :                         --nFieldEnd;                        // first field shortened?
    1063             : 
    1064           0 :                     nStart[nPos] = nFieldStart;
    1065           0 :                     nEnd[nPos]   = nFieldEnd;
    1066           0 :                     nFieldStart  = nFieldEnd + 1;
    1067             :                 }
    1068           0 :                 nFound = 3;
    1069             :             }
    1070             :         }
    1071             : 
    1072           0 :         if ( nFound >= 3 )
    1073             :         {
    1074             :             using namespace ::com::sun::star;
    1075           0 :             bool bSecondCal = false;
    1076           0 :             sal_uInt16 nDay  = (sal_uInt16) rStr.copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).toInt32();
    1077           0 :             sal_uInt16 nYear = (sal_uInt16) rStr.copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).toInt32();
    1078           0 :             OUString aMStr = rStr.copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
    1079           0 :             sal_Int16 nMonth = (sal_Int16) aMStr.toInt32();
    1080           0 :             if (!nMonth)
    1081             :             {
    1082             :                 static const char aSeptCorrect[] =  "SEPT";
    1083             :                 static const char aSepShortened[] =  "SEP";
    1084           0 :                 uno::Sequence< i18n::CalendarItem2 > xMonths;
    1085             :                 sal_Int32 i, nMonthCount;
    1086             :                 //  first test all month names from local international
    1087           0 :                 xMonths = rCalendar.getMonths();
    1088           0 :                 nMonthCount = xMonths.getLength();
    1089           0 :                 for (i=0; i<nMonthCount && !nMonth; i++)
    1090             :                 {
    1091           0 :                     if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
    1092           0 :                          rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
    1093           0 :                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
    1094           0 :                     else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
    1095           0 :                                 xMonths[i].AbbrevName ) &&
    1096           0 :                             rTransliteration.isEqual( aMStr, aSepShortened ) )
    1097             :                     {   // correct English abbreviation is SEPT,
    1098             :                         // but data mostly contains SEP only
    1099           0 :                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
    1100             :                     }
    1101             :                 }
    1102             :                 //  if none found, then test english month names
    1103           0 :                 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
    1104             :                 {
    1105           0 :                     xMonths = pSecondCalendar->getMonths();
    1106           0 :                     nMonthCount = xMonths.getLength();
    1107           0 :                     for (i=0; i<nMonthCount && !nMonth; i++)
    1108             :                     {
    1109           0 :                         if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
    1110           0 :                              pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
    1111             :                         {
    1112           0 :                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
    1113           0 :                             bSecondCal = true;
    1114             :                         }
    1115           0 :                         else if ( i == 8 && pSecondTransliteration->isEqual(
    1116           0 :                                     aMStr, aSepShortened ) )
    1117             :                         {   // correct English abbreviation is SEPT,
    1118             :                             // but data mostly contains SEP only
    1119           0 :                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
    1120           0 :                             bSecondCal = true;
    1121             :                         }
    1122             :                     }
    1123           0 :                 }
    1124             :             }
    1125             : 
    1126           0 :             SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
    1127           0 :             if ( nYear < 100 )
    1128           0 :                 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
    1129             : 
    1130           0 :             CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
    1131           0 :             sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
    1132           0 :             if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
    1133             :             {
    1134           0 :                 --nMonth;
    1135           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
    1136           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
    1137           0 :                 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           0 :                 nHour = nMinute = nSecond = nMilli = 0;
    1142           0 :                 if (nFound > 3)
    1143           0 :                     nHour = (sal_Int16) rStr.copy( nStart[3], nEnd[3]+1-nStart[3]).toInt32();
    1144           0 :                 if (nFound > 4)
    1145           0 :                     nMinute = (sal_Int16) rStr.copy( nStart[4], nEnd[4]+1-nStart[4]).toInt32();
    1146           0 :                 if (nFound > 5)
    1147           0 :                     nSecond = (sal_Int16) rStr.copy( nStart[5], nEnd[5]+1-nStart[5]).toInt32();
    1148           0 :                 if (nFound > 6)
    1149             :                 {
    1150           0 :                     sal_Unicode cDec = '.';
    1151           0 :                     OUString aT( &cDec, 1);
    1152           0 :                     aT += rStr.copy( nStart[6], nEnd[6]+1-nStart[6]);
    1153             :                     rtl_math_ConversionStatus eStatus;
    1154           0 :                     double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
    1155           0 :                     if (eStatus == rtl_math_ConversionStatus_Ok)
    1156           0 :                         nMilli = (sal_Int16) (1000.0 * fV + 0.5);
    1157             :                 }
    1158           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
    1159           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
    1160           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
    1161           0 :                 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
    1162           0 :                 if ( pCalendar->isValid() )
    1163             :                 {
    1164           0 :                     double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
    1165           0 :                         pCalendar->getEpochStart();
    1166             :                     // #i14974# must use getLocalDateTime to get the same
    1167             :                     // date values as set above
    1168           0 :                     double fDays = pCalendar->getLocalDateTime();
    1169           0 :                     fDays -= fDiff;
    1170             : 
    1171             :                     LanguageType eLatin, eCjk, eCtl;
    1172           0 :                     pDoc->GetLanguage( eLatin, eCjk, eCtl );
    1173           0 :                     LanguageType eDocLang = eLatin;     //! which language for date formats?
    1174             : 
    1175           0 :                     short nType = (nFound > 3 ? css::util::NumberFormat::DATETIME : css::util::NumberFormat::DATE);
    1176           0 :                     sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
    1177             :                     // maybe there is a special format including seconds or milliseconds
    1178           0 :                     if (nFound > 5)
    1179           0 :                         nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
    1180             : 
    1181           0 :                     ScAddress aPos(nCol,nRow,nTab);
    1182           0 :                     if ( bUseDocImport )
    1183           0 :                         rDocImport.setNumericCell(aPos, fDays);
    1184             :                     else
    1185           0 :                         pDoc->SetValue( aPos, fDays );
    1186           0 :                     pDoc->SetNumberFormat(aPos, nFormat);
    1187             : 
    1188           0 :                     return bMultiLine;     // success
    1189             :                 }
    1190           0 :             }
    1191             :         }
    1192             :     }
    1193             : 
    1194             :     // Standard or date not determined -> SetString / EditCell
    1195         290 :     if( rStr.indexOf( '\n' ) == -1 )
    1196             :     {
    1197         274 :         ScSetStringParam aParam;
    1198         274 :         aParam.mpNumFormatter = pFormatter;
    1199         274 :         aParam.mbDetectNumberFormat = bDetectNumFormat;
    1200         274 :         aParam.meSetTextNumFormat = ScSetStringParam::SpecialNumberOnly;
    1201         274 :         aParam.mbHandleApostrophe = false;
    1202         274 :         if ( bUseDocImport )
    1203         274 :             rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr, &aParam);
    1204             :         else
    1205           0 :             pDoc->SetString( nCol, nRow, nTab, rStr, &aParam );
    1206             :     }
    1207             :     else
    1208             :     {
    1209          16 :         bMultiLine = true;
    1210          16 :         ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
    1211          16 :         rEngine.SetText(rStr);
    1212          16 :         if ( bUseDocImport )
    1213          16 :             rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
    1214             :         else
    1215           0 :             pDoc->SetEditText( ScAddress( nCol, nRow, nTab ), rEngine.CreateTextObject() );
    1216             :     }
    1217         290 :     return bMultiLine;
    1218             : }
    1219             : 
    1220           0 : static OUString lcl_GetFixed( const OUString& rLine, sal_Int32 nStart, sal_Int32 nNext,
    1221             :                      bool& rbIsQuoted, bool& rbOverflowCell )
    1222             : {
    1223           0 :     sal_Int32 nLen = rLine.getLength();
    1224           0 :     if (nNext > nLen)
    1225           0 :         nNext = nLen;
    1226           0 :     if ( nNext <= nStart )
    1227           0 :         return EMPTY_OUSTRING;
    1228             : 
    1229           0 :     const sal_Unicode* pStr = rLine.getStr();
    1230             : 
    1231           0 :     sal_Int32 nSpace = nNext;
    1232           0 :     while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
    1233           0 :         --nSpace;
    1234             : 
    1235           0 :     rbIsQuoted = (pStr[nStart] == '"' && pStr[nSpace-1] == '"');
    1236           0 :     if (rbIsQuoted)
    1237             :     {
    1238           0 :         bool bFits = (nSpace - nStart - 3 <= SAL_MAX_UINT16);
    1239             :         OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
    1240           0 :         if (bFits)
    1241           0 :             return rLine.copy(nStart+1, nSpace-nStart-2);
    1242             :         else
    1243             :         {
    1244           0 :             rbOverflowCell = true;
    1245           0 :             return rLine.copy(nStart+1, SAL_MAX_UINT16);
    1246             :         }
    1247             :     }
    1248             :     else
    1249             :     {
    1250           0 :         bool bFits = (nSpace - nStart <= SAL_MAX_UINT16);
    1251             :         OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
    1252           0 :         if (bFits)
    1253           0 :             return rLine.copy(nStart, nSpace-nStart);
    1254             :         else
    1255             :         {
    1256           0 :             rbOverflowCell = true;
    1257           0 :             return rLine.copy(nStart, SAL_MAX_UINT16);
    1258             :         }
    1259             :     }
    1260             : }
    1261             : 
    1262           3 : bool ScImportExport::ExtText2Doc( SvStream& rStrm )
    1263             : {
    1264           3 :     if (!pExtOptions)
    1265           0 :         return Text2Doc( rStrm );
    1266             : 
    1267           3 :     sal_uInt64 const nOldPos = rStrm.Tell();
    1268           3 :     sal_uInt64 const nRemaining = rStrm.remainingSize();
    1269             :     boost::scoped_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
    1270           3 :             ScGlobal::GetRscString( STR_LOAD_DOC ), nRemaining ));
    1271           3 :     rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
    1272             : 
    1273           3 :     SCCOL nStartCol = aRange.aStart.Col();
    1274           3 :     SCCOL nEndCol = aRange.aEnd.Col();
    1275           3 :     SCROW nStartRow = aRange.aStart.Row();
    1276           3 :     SCTAB nTab = aRange.aStart.Tab();
    1277             : 
    1278           3 :     bool    bFixed              = pExtOptions->IsFixedLen();
    1279           3 :     const OUString& rSeps       = pExtOptions->GetFieldSeps();
    1280           3 :     const sal_Unicode* pSeps    = rSeps.getStr();
    1281           3 :     bool    bMerge              = pExtOptions->IsMergeSeps();
    1282           3 :     sal_uInt16  nInfoCount      = pExtOptions->GetInfoCount();
    1283           3 :     const sal_Int32* pColStart  = pExtOptions->GetColStart();
    1284           3 :     const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
    1285           3 :     long nSkipLines             = pExtOptions->GetStartRow();
    1286             : 
    1287           3 :     LanguageType eDocLang = pExtOptions->GetLanguage();
    1288           6 :     SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eDocLang);
    1289           3 :     bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
    1290             : 
    1291             :     // For date recognition
    1292             :     ::utl::TransliterationWrapper aTransliteration(
    1293           6 :         comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE );
    1294           3 :     aTransliteration.loadModuleIfNeeded( eDocLang );
    1295           6 :     CalendarWrapper aCalendar( comphelper::getProcessComponentContext() );
    1296             :     aCalendar.loadDefaultCalendar(
    1297           3 :         LanguageTag::convertToLocale( eDocLang ) );
    1298           6 :     boost::scoped_ptr< ::utl::TransliterationWrapper > pEnglishTransliteration;
    1299           6 :     boost::scoped_ptr< CalendarWrapper > pEnglishCalendar;
    1300           3 :     if ( eDocLang != LANGUAGE_ENGLISH_US )
    1301             :     {
    1302             :         pEnglishTransliteration.reset(new ::utl::TransliterationWrapper (
    1303           3 :             comphelper::getProcessComponentContext(), SC_TRANSLITERATION_IGNORECASE ));
    1304           3 :         aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
    1305           3 :         pEnglishCalendar.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
    1306             :         pEnglishCalendar->loadDefaultCalendar(
    1307           3 :             LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) );
    1308             :     }
    1309             : 
    1310           6 :     OUString aLine;
    1311           6 :     OUString aCell;
    1312             :     sal_uInt16 i;
    1313           3 :     SCROW nRow = nStartRow;
    1314             : 
    1315           6 :     while(--nSkipLines>0)
    1316             :     {
    1317           0 :         aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr); // content is ignored
    1318           0 :         if ( rStrm.IsEof() )
    1319           0 :             break;
    1320             :     }
    1321             : 
    1322             :     // Determine range for Undo.
    1323             :     // We don't need this during import of a file to a new sheet or document...
    1324           3 :     bool bDetermineRange = bUndo;
    1325             : 
    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           3 :     bool bRangeIsDetermined = bDetermineRange;
    1330             : 
    1331           3 :     bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
    1332             : 
    1333           3 :     sal_uLong nOriginalStreamPos = rStrm.Tell();
    1334             : 
    1335           6 :     ScDocumentImport aDocImport(*pDoc);
    1336           4 :     do
    1337             :     {
    1338             :         for( ;; )
    1339             :         {
    1340          77 :             aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr);
    1341          77 :             if ( rStrm.IsEof() && aLine.isEmpty() )
    1342           4 :                 break;
    1343             : 
    1344          73 :             EmbeddedNullTreatment( aLine);
    1345             : 
    1346          73 :             sal_Int32 nLineLen = aLine.getLength();
    1347          73 :             SCCOL nCol = nStartCol;
    1348          73 :             bool bMultiLine = false;
    1349          73 :             if ( bFixed ) //  Fixed line length
    1350             :             {
    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           0 :                 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
    1356             :                 {
    1357           0 :                     sal_uInt8 nFmt = pColFormat[i];
    1358           0 :                     if (nFmt != SC_COL_SKIP)        // sonst auch nCol nicht hochzaehlen
    1359             :                     {
    1360           0 :                         if (nCol > MAXCOL)
    1361           0 :                             bOverflowCol = true;    // display warning on import
    1362           0 :                         else if (!bDetermineRange)
    1363             :                         {
    1364           0 :                             sal_Int32 nStart = pColStart[i];
    1365           0 :                             sal_Int32 nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
    1366           0 :                             bool bIsQuoted = false;
    1367           0 :                             aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted, bOverflowCell );
    1368           0 :                             if (bIsQuoted && bQuotedAsText)
    1369           0 :                                 nFmt = SC_COL_TEXT;
    1370             : 
    1371             :                             bMultiLine |= lcl_PutString(
    1372           0 :                                 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
    1373             :                                 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
    1374           0 :                                 pEnglishTransliteration.get(), pEnglishCalendar.get());
    1375             :                         }
    1376           0 :                         ++nCol;
    1377             :                     }
    1378             :                 }
    1379             :             }
    1380             :             else // Search for the separator
    1381             :             {
    1382          73 :                 SCCOL nSourceCol = 0;
    1383          73 :                 sal_uInt16 nInfoStart = 0;
    1384          73 :                 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         513 :                 while (*p && nCol <= MAXCOL+1)
    1390             :                 {
    1391         367 :                     bool bIsQuoted = false;
    1392             :                     p = ScImportExport::ScanNextFieldFromString( p, aCell,
    1393         367 :                             cStr, pSeps, bMerge, bIsQuoted, bOverflowCell );
    1394             : 
    1395         367 :                     sal_uInt8 nFmt = SC_COL_STANDARD;
    1396         367 :                     for ( i=nInfoStart; i<nInfoCount; i++ )
    1397             :                     {
    1398           0 :                         if ( pColStart[i] == nSourceCol + 1 )       // pColStart ist 1-basiert
    1399             :                         {
    1400           0 :                             nFmt = pColFormat[i];
    1401           0 :                             nInfoStart = i + 1;     // ColInfos sind in Reihenfolge
    1402           0 :                             break;  // for
    1403             :                         }
    1404             :                     }
    1405         367 :                     if ( nFmt != SC_COL_SKIP )
    1406             :                     {
    1407         367 :                         if (nCol > MAXCOL)
    1408           0 :                             bOverflowCol = true;    // display warning on import
    1409         367 :                         else if (!bDetermineRange)
    1410             :                         {
    1411         364 :                             if (bIsQuoted && bQuotedAsText)
    1412           0 :                                 nFmt = SC_COL_TEXT;
    1413             : 
    1414             :                             bMultiLine |= lcl_PutString(
    1415         364 :                                 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
    1416             :                                 &aNumFormatter, bDetectNumFormat, aTransliteration,
    1417         728 :                                 aCalendar, pEnglishTransliteration.get(), pEnglishCalendar.get());
    1418             :                         }
    1419         367 :                         ++nCol;
    1420             :                     }
    1421             : 
    1422         367 :                     ++nSourceCol;
    1423             :                 }
    1424             :             }
    1425          73 :             if (nEndCol < nCol)
    1426           6 :                 nEndCol = nCol;     //! points to the next free or even MAXCOL+2
    1427             : 
    1428          73 :             if (!bDetermineRange)
    1429             :             {
    1430          72 :                 if (bMultiLine && !bRangeIsDetermined && pDocSh)
    1431          12 :                     pDocSh->AdjustRowHeight( nRow, nRow, nTab);
    1432          72 :                 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
    1433             :             }
    1434          73 :             ++nRow;
    1435          73 :             if ( nRow > MAXROW )
    1436             :             {
    1437           0 :                 bOverflowRow = true;    // display warning on import
    1438           0 :                 break;  // for
    1439             :             }
    1440          73 :         }
    1441             :         // so far nRow/nEndCol pointed to the next free
    1442           4 :         if (nRow > nStartRow)
    1443           4 :             --nRow;
    1444           4 :         if (nEndCol > nStartCol)
    1445           4 :             nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
    1446             : 
    1447           4 :         if (bDetermineRange)
    1448             :         {
    1449           1 :             aRange.aEnd.SetCol( nEndCol );
    1450           1 :             aRange.aEnd.SetRow( nRow );
    1451             : 
    1452           1 :             if ( !mbApi && nStartCol != nEndCol &&
    1453           0 :                  !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
    1454             :             {
    1455           0 :                 ScopedVclPtrInstance< ScReplaceWarnBox > aBox( ScDocShell::GetActiveDialogParent() );
    1456           0 :                 if ( aBox->Execute() != RET_YES )
    1457             :                 {
    1458           0 :                     return false;
    1459           0 :                 }
    1460             :             }
    1461             : 
    1462           1 :             rStrm.Seek( nOriginalStreamPos );
    1463           1 :             nRow = nStartRow;
    1464           1 :             if (!StartPaste())
    1465             :             {
    1466           0 :                 EndPaste(false);
    1467           0 :                 return false;
    1468             :             }
    1469             :         }
    1470             : 
    1471           4 :         bDetermineRange = !bDetermineRange;     // toggle
    1472           4 :     } while (!bDetermineRange);
    1473           3 :     if ( !mbOverwriting )
    1474           3 :         aDocImport.finalize();
    1475             : 
    1476           3 :     xProgress.reset();    // make room for AdjustRowHeight progress
    1477           3 :     if (bRangeIsDetermined)
    1478           1 :         EndPaste(false);
    1479             : 
    1480           3 :     if (mbImportBroadcast && !mbOverwriting)
    1481             :     {
    1482           1 :         pDoc->BroadcastCells(aRange, SC_HINT_DATACHANGED);
    1483           1 :         pDocSh->PostDataChanged();
    1484             :     }
    1485           6 :     return true;
    1486             : }
    1487             : 
    1488          73 : void ScImportExport::EmbeddedNullTreatment( OUString & rStr )
    1489             : {
    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.
    1494             : 
    1495             :     // The normal case is no embedded NULL, check first before de-/allocating
    1496             :     // ustring stuff.
    1497          73 :     sal_Unicode cNull = 0;
    1498          73 :     if (rStr.indexOf( cNull) >= 0)
    1499             :     {
    1500           0 :         rStr = rStr.replaceAll( OUString( &cNull, 1), OUString());
    1501             :     }
    1502          73 : }
    1503             : 
    1504         367 : 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 )
    1507             : {
    1508         367 :     rbIsQuoted = false;
    1509         367 :     rField.clear();
    1510         367 :     const sal_Unicode cBlank = ' ';
    1511         367 :     if (!ScGlobal::UnicodeStrChr( pSeps, cBlank))
    1512             :     {
    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         367 :         const sal_Unicode* pb = p;
    1517         746 :         while (*pb == cBlank)
    1518          12 :             ++pb;
    1519         367 :         if (*pb == cStr)
    1520         193 :             p = pb;
    1521             :     }
    1522         367 :     if ( *p == cStr )           // String in quotes
    1523             :     {
    1524         193 :         rbIsQuoted = true;
    1525             :         const sal_Unicode* p1;
    1526         193 :         p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DQM_ESCAPE, rbOverflowCell );
    1527         390 :         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
    1528           4 :             p++;
    1529             :         // Append remaining unquoted and undelimited data (dirty, dirty) to
    1530             :         // this field.
    1531         193 :         if (p > p1)
    1532             :         {
    1533           4 :             if (!lcl_appendLineData( rField, p1, p))
    1534           0 :                 rbOverflowCell = true;
    1535             :         }
    1536         193 :         if( *p )
    1537         177 :             p++;
    1538             :     }
    1539             :     else                        // up to delimiter
    1540             :     {
    1541         174 :         const sal_Unicode* p0 = p;
    1542        1724 :         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
    1543        1376 :             p++;
    1544         174 :         if (!lcl_appendLineData( rField, p0, p))
    1545           0 :             rbOverflowCell = true;
    1546         174 :         if( *p )
    1547         130 :             p++;
    1548             :     }
    1549         367 :     if ( bMergeSeps )           // skip following delimiters
    1550             :     {
    1551           0 :         while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
    1552           0 :             p++;
    1553             :     }
    1554         367 :     return p;
    1555             : }
    1556             : 
    1557             : namespace {
    1558             : 
    1559             : /**
    1560             :  * Check if a given string has any line break characters or separators.
    1561             :  *
    1562             :  * @param rStr string to inspect.
    1563             :  * @param cSep separator character.
    1564             :  */
    1565           0 : bool hasLineBreaksOrSeps( const OUString& rStr, sal_Unicode cSep )
    1566             : {
    1567           0 :     const sal_Unicode* p = rStr.getStr();
    1568           0 :     for (sal_Int32 i = 0, n = rStr.getLength(); i < n; ++i, ++p)
    1569             :     {
    1570           0 :         sal_Unicode c = *p;
    1571           0 :         if (c == cSep)
    1572             :             // separator found.
    1573           0 :             return true;
    1574             : 
    1575           0 :         switch (c)
    1576             :         {
    1577             :             case '\n':
    1578             :             case '\r':
    1579             :                 // line break found.
    1580           0 :                 return true;
    1581             :             default:
    1582             :                 ;
    1583             :         }
    1584             :     }
    1585           0 :     return false;
    1586             : }
    1587             : 
    1588             : }
    1589             : 
    1590           5 : bool ScImportExport::Doc2Text( SvStream& rStrm )
    1591             : {
    1592             :     SCCOL nCol;
    1593             :     SCROW nRow;
    1594           5 :     SCCOL nStartCol = aRange.aStart.Col();
    1595           5 :     SCROW nStartRow = aRange.aStart.Row();
    1596           5 :     SCTAB nStartTab = aRange.aStart.Tab();
    1597           5 :     SCCOL nEndCol = aRange.aEnd.Col();
    1598           5 :     SCROW nEndRow = aRange.aEnd.Row();
    1599           5 :     SCTAB nEndTab = aRange.aEnd.Tab();
    1600             : 
    1601           5 :     if (!pDoc->GetClipParam().isMultiRange() && nStartTab == nEndTab)
    1602           5 :         pDoc->ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow );
    1603             : 
    1604           5 :     OUString aCell;
    1605             : 
    1606           5 :     bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
    1607             : 
    1608          10 :     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
    1609             :     {
    1610           5 :         if (bIncludeFiltered || !pDoc->RowFiltered( nRow, nStartTab ))
    1611             :         {
    1612          10 :             for (nCol = nStartCol; nCol <= nEndCol; nCol++)
    1613             :             {
    1614             :                 CellType eType;
    1615           5 :                 pDoc->GetCellType( nCol, nRow, nStartTab, eType );
    1616           5 :                 switch (eType)
    1617             :                 {
    1618             :                     case CELLTYPE_FORMULA:
    1619             :                     {
    1620           0 :                         if (bFormulas)
    1621             :                         {
    1622           0 :                             pDoc->GetFormula( nCol, nRow, nStartTab, aCell );
    1623           0 :                             if( aCell.indexOf( cSep ) != -1 )
    1624           0 :                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
    1625             :                             else
    1626           0 :                                 lcl_WriteSimpleString( rStrm, aCell );
    1627             :                         }
    1628             :                         else
    1629             :                         {
    1630           0 :                             aCell = pDoc->GetString(nCol, nRow, nStartTab);
    1631             : 
    1632           0 :                             bool bMultiLineText = ( aCell.indexOf( '\n' ) != -1 );
    1633           0 :                             if( bMultiLineText )
    1634             :                             {
    1635           0 :                                 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
    1636           0 :                                     aCell = aCell.replaceAll( "\n", " " );
    1637           0 :                                 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
    1638           0 :                                     aCell = convertLineEnd(aCell, GetSystemLineEnd());
    1639             :                             }
    1640             : 
    1641           0 :                             if( mExportTextOptions.mcSeparatorConvertTo && cSep )
    1642           0 :                                 aCell = aCell.replaceAll( OUString(cSep), OUString(mExportTextOptions.mcSeparatorConvertTo) );
    1643             : 
    1644           0 :                             if( mExportTextOptions.mbAddQuotes && ( aCell.indexOf( cSep ) != -1 ) )
    1645           0 :                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
    1646             :                             else
    1647           0 :                                 lcl_WriteSimpleString( rStrm, aCell );
    1648             :                         }
    1649             :                     }
    1650           0 :                     break;
    1651             :                     case CELLTYPE_VALUE:
    1652             :                     {
    1653           5 :                         aCell = pDoc->GetString(nCol, nRow, nStartTab);
    1654           5 :                         lcl_WriteSimpleString( rStrm, aCell );
    1655             :                     }
    1656           5 :                     break;
    1657             :                     case CELLTYPE_NONE:
    1658           0 :                     break;
    1659             :                     default:
    1660             :                     {
    1661           0 :                         aCell = pDoc->GetString(nCol, nRow, nStartTab);
    1662             : 
    1663           0 :                         bool bMultiLineText = ( aCell.indexOf( '\n' ) != -1 );
    1664           0 :                         if( bMultiLineText )
    1665             :                         {
    1666           0 :                             if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
    1667           0 :                                 aCell = aCell.replaceAll( "\n", " " );
    1668           0 :                             else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
    1669           0 :                                 aCell = convertLineEnd(aCell, GetSystemLineEnd());
    1670             :                         }
    1671             : 
    1672           0 :                         if( mExportTextOptions.mcSeparatorConvertTo && cSep )
    1673           0 :                             aCell = aCell.replaceAll( OUString(cSep), OUString(mExportTextOptions.mcSeparatorConvertTo) );
    1674             : 
    1675           0 :                         if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCell, cSep) )
    1676           0 :                             lcl_WriteString( rStrm, aCell, cStr, cStr );
    1677             :                         else
    1678           0 :                             lcl_WriteSimpleString( rStrm, aCell );
    1679             :                     }
    1680             :                 }
    1681           5 :                 if( nCol < nEndCol )
    1682           0 :                     lcl_WriteSimpleString( rStrm, OUString(cSep) );
    1683             :             }
    1684           5 :             WriteUnicodeOrByteEndl( rStrm );
    1685           5 :             if( rStrm.GetError() != SVSTREAM_OK )
    1686           0 :                 break;
    1687           5 :             if( nSizeLimit && rStrm.Tell() > nSizeLimit )
    1688           0 :                 break;
    1689             :         }
    1690             :     }
    1691             : 
    1692           5 :     return rStrm.GetError() == SVSTREAM_OK;
    1693             : }
    1694             : 
    1695           4 : bool ScImportExport::Sylk2Doc( SvStream& rStrm )
    1696             : {
    1697           4 :     bool bOk = true;
    1698           4 :     bool bMyDoc = false;
    1699           4 :     SylkVersion eVersion = SYLK_OTHER;
    1700             : 
    1701             :     // US-English separators for StringToDouble
    1702           4 :     sal_Unicode cDecSep = '.';
    1703           4 :     sal_Unicode cGrpSep = ',';
    1704             : 
    1705           4 :     SCCOL nStartCol = aRange.aStart.Col();
    1706           4 :     SCROW nStartRow = aRange.aStart.Row();
    1707           4 :     SCCOL nEndCol = aRange.aEnd.Col();
    1708           4 :     SCROW nEndRow = aRange.aEnd.Row();
    1709           4 :     sal_uLong nOldPos = rStrm.Tell();
    1710           4 :     bool bData = !bSingle;
    1711           4 :     ::std::vector< sal_uInt32 > aFormats;
    1712             : 
    1713           4 :     if( !bSingle)
    1714           0 :         bOk = StartPaste();
    1715             : 
    1716          12 :     while( bOk )
    1717             :     {
    1718           8 :         OUString aLine;
    1719          12 :         OUString aText;
    1720          12 :         OString aByteLine;
    1721           8 :         SCCOL nCol = nStartCol;
    1722           8 :         SCROW nRow = nStartRow;
    1723           8 :         SCCOL nRefCol = 1;
    1724           8 :         SCROW nRefRow = 1;
    1725           8 :         rStrm.Seek( nOldPos );
    1726             :         for( ;; )
    1727             :         {
    1728             :             //! allow unicode
    1729        6060 :             rStrm.ReadLine( aByteLine );
    1730        6060 :             aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
    1731        6060 :             if( rStrm.IsEof() )
    1732           2 :                 break;
    1733        6058 :             const sal_Unicode* p = aLine.getStr();
    1734        6058 :             sal_Unicode cTag = *p++;
    1735        6058 :             if( cTag == 'C' )       // Content
    1736             :             {
    1737        4620 :                 if( *p++ != ';' )
    1738           0 :                     return false;
    1739       20780 :                 while( *p )
    1740             :                 {
    1741       11540 :                     sal_Unicode ch = *p++;
    1742       11540 :                     ch = ScGlobal::ToUpperAlpha( ch );
    1743       11540 :                     switch( ch )
    1744             :                     {
    1745             :                         case 'X':
    1746        4460 :                             nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
    1747        4460 :                             break;
    1748             :                         case 'Y':
    1749        2444 :                             nRow = OUString(p).toInt32() + nStartRow - 1;
    1750        2444 :                             break;
    1751             :                         case 'C':
    1752           0 :                             nRefCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
    1753           0 :                             break;
    1754             :                         case 'R':
    1755           0 :                             nRefRow = OUString(p).toInt32() + nStartRow - 1;
    1756           0 :                             break;
    1757             :                         case 'K':
    1758             :                         {
    1759        4620 :                             if( !bSingle &&
    1760           0 :                                     ( nCol < nStartCol || nCol > nEndCol
    1761           0 :                                       || nRow < nStartRow || nRow > nEndRow
    1762           0 :                                       || nCol > MAXCOL || nRow > MAXROW ) )
    1763             :                                 break;
    1764        4620 :                             if( !bData )
    1765             :                             {
    1766        2310 :                                 if( nRow > nEndRow )
    1767         221 :                                     nEndRow = nRow;
    1768        2310 :                                 if( nCol > nEndCol )
    1769          18 :                                     nEndCol = nCol;
    1770        2310 :                                 break;
    1771             :                             }
    1772             :                             bool bText;
    1773        2310 :                             if( *p == '"' )
    1774             :                             {
    1775         941 :                                 bText = true;
    1776         941 :                                 aText.clear();
    1777         941 :                                 p = lcl_ScanSylkString( p, aText, eVersion);
    1778             :                             }
    1779             :                             else
    1780        1369 :                                 bText = false;
    1781        2310 :                             const sal_Unicode* q = p;
    1782        9527 :                             while( *q && *q != ';' )
    1783        4907 :                                 q++;
    1784        2310 :                             if ( !(*q == ';' && *(q+1) == 'I') )
    1785             :                             {   // don't ignore value
    1786        2310 :                                 if( bText )
    1787             :                                 {
    1788         941 :                                     pDoc->EnsureTable(aRange.aStart.Tab());
    1789             :                                     pDoc->SetTextCell(
    1790         941 :                                         ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
    1791             :                                 }
    1792             :                                 else
    1793             :                                 {
    1794             :                                     double fVal = rtl_math_uStringToDouble( p,
    1795        1369 :                                             aLine.getStr() + aLine.getLength(),
    1796        2738 :                                             cDecSep, cGrpSep, NULL, NULL );
    1797        1369 :                                     pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
    1798             :                                 }
    1799             :                             }
    1800             :                         }
    1801        2310 :                         break;
    1802             :                         case 'E':
    1803             :                         case 'M':
    1804             :                         {
    1805           0 :                             if ( ch == 'M' )
    1806             :                             {
    1807           0 :                                 if ( nRefCol < nCol )
    1808           0 :                                     nRefCol = nCol;
    1809           0 :                                 if ( nRefRow < nRow )
    1810           0 :                                     nRefRow = nRow;
    1811           0 :                                 if ( !bData )
    1812             :                                 {
    1813           0 :                                     if( nRefRow > nEndRow )
    1814           0 :                                         nEndRow = nRefRow;
    1815           0 :                                     if( nRefCol > nEndCol )
    1816           0 :                                         nEndCol = nRefCol;
    1817             :                                 }
    1818             :                             }
    1819           0 :                             if( !bMyDoc || !bData )
    1820             :                                 break;
    1821           0 :                             aText = "=";
    1822           0 :                             p = lcl_ScanSylkFormula( p, aText, eVersion);
    1823           0 :                             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           0 :                             const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
    1828           0 :                             ScCompiler aComp( pDoc, aPos);
    1829           0 :                             aComp.SetGrammar(eGrammar);
    1830           0 :                             ScTokenArray* pCode = aComp.CompileString( aText );
    1831           0 :                             if ( ch == 'M' )
    1832             :                             {
    1833           0 :                                 ScMarkData aMark;
    1834           0 :                                 aMark.SelectTable( aPos.Tab(), true );
    1835             :                                 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
    1836           0 :                                     nRefRow, aMark, EMPTY_OUSTRING, pCode );
    1837             :                             }
    1838             :                             else
    1839             :                             {
    1840             :                                 ScFormulaCell* pFCell = new ScFormulaCell(
    1841           0 :                                         pDoc, aPos, *pCode, eGrammar, MM_NONE);
    1842           0 :                                 pDoc->SetFormulaCell(aPos, pFCell);
    1843             :                             }
    1844           0 :                             delete pCode;   // ctor/InsertMatrixFormula did copy TokenArray
    1845             :                         }
    1846           0 :                         break;
    1847             :                     }
    1848       58497 :                     while( *p && *p != ';' )
    1849       35417 :                         p++;
    1850       11540 :                     if( *p )
    1851        6920 :                         p++;
    1852             :                 }
    1853             :             }
    1854        1438 :             else if( cTag == 'F' )      // Format
    1855             :             {
    1856         196 :                 if( *p++ != ';' )
    1857           0 :                     return false;
    1858         196 :                 sal_Int32 nFormat = -1;
    1859         942 :                 while( *p )
    1860             :                 {
    1861         550 :                     sal_Unicode ch = *p++;
    1862         550 :                     ch = ScGlobal::ToUpperAlpha( ch );
    1863         550 :                     switch( ch )
    1864             :                     {
    1865             :                         case 'X':
    1866         160 :                             nCol = static_cast<SCCOL>(OUString(p).toInt32()) + nStartCol - 1;
    1867         160 :                             break;
    1868             :                         case 'Y':
    1869          22 :                             nRow = OUString(p).toInt32() + nStartRow - 1;
    1870          22 :                             break;
    1871             :                         case 'P' :
    1872         166 :                             if ( bData )
    1873             :                             {
    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          83 :                                 const sal_Unicode* p0 = p;
    1878         258 :                                 while( *p && *p != ';' )
    1879          92 :                                     p++;
    1880          83 :                                 OUString aNumber(p0, p - p0);
    1881          83 :                                 nFormat = aNumber.toInt32();
    1882             :                             }
    1883         166 :                             break;
    1884             :                     }
    1885        2100 :                     while( *p && *p != ';' )
    1886        1000 :                         p++;
    1887         550 :                     if( *p )
    1888         354 :                         p++;
    1889             :                 }
    1890         196 :                 if ( !bData )
    1891             :                 {
    1892          98 :                     if( nRow > nEndRow )
    1893          10 :                         nEndRow = nRow;
    1894          98 :                     if( nCol > nEndCol )
    1895           1 :                         nEndCol = nCol;
    1896             :                 }
    1897         196 :                 if ( 0 <= nFormat && nFormat < (sal_Int32)aFormats.size() )
    1898             :                 {
    1899          83 :                     sal_uInt32 nKey = aFormats[nFormat];
    1900          83 :                     pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
    1901         166 :                             SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
    1902             :                 }
    1903             :             }
    1904        1242 :             else if( cTag == 'P' )
    1905             :             {
    1906        1220 :                 if ( bData && *p == ';' && *(p+1) == 'P' )
    1907             :                 {
    1908         605 :                     OUString aCode( p+2 );
    1909             :                     // unescape doubled semicolons
    1910         605 :                     aCode = aCode.replaceAll(";;", ";");
    1911             :                     // get rid of Xcl escape characters
    1912         605 :                     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         605 :                                                                 LANGUAGE_ENGLISH_US, ScGlobal::eLnge );
    1918         605 :                     if ( nCheckPos )
    1919           0 :                         nKey = 0;
    1920         605 :                     aFormats.push_back( nKey );
    1921             :                 }
    1922             :             }
    1923          22 :             else if( cTag == 'I' && *p == 'D' )
    1924             :             {
    1925           8 :                 aLine = aLine.copy(4);
    1926           8 :                 if (aLine == "CALCOOO32")
    1927           0 :                     eVersion = SYLK_OOO32;
    1928           8 :                 else if (aLine == "SCALC3")
    1929           2 :                     eVersion = SYLK_SCALC3;
    1930           8 :                 bMyDoc = (eVersion <= SYLK_OWN);
    1931             :             }
    1932          14 :             else if( cTag == 'E' )                      // Ende
    1933           6 :                 break;
    1934        6052 :         }
    1935           8 :         if( !bData )
    1936             :         {
    1937           4 :             aRange.aEnd.SetCol( nEndCol );
    1938           4 :             aRange.aEnd.SetRow( nEndRow );
    1939           4 :             bOk = StartPaste();
    1940           4 :             bData = true;
    1941             :         }
    1942             :         else
    1943           4 :             break;
    1944           4 :     }
    1945             : 
    1946           4 :     EndPaste();
    1947           4 :     return bOk;
    1948             : }
    1949             : 
    1950           0 : bool ScImportExport::Doc2Sylk( SvStream& rStrm )
    1951             : {
    1952             :     SCCOL nCol;
    1953             :     SCROW nRow;
    1954           0 :     SCCOL nStartCol = aRange.aStart.Col();
    1955           0 :     SCROW nStartRow = aRange.aStart.Row();
    1956           0 :     SCCOL nEndCol = aRange.aEnd.Col();
    1957           0 :     SCROW nEndRow = aRange.aEnd.Row();
    1958           0 :     OUString aCellStr;
    1959           0 :     OUString aValStr;
    1960           0 :     lcl_WriteSimpleString( rStrm, OUString("ID;PCALCOOO32") );
    1961           0 :     WriteUnicodeOrByteEndl( rStrm );
    1962             : 
    1963           0 :     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
    1964             :     {
    1965           0 :         for (nCol = nStartCol; nCol <= nEndCol; nCol++)
    1966             :         {
    1967           0 :             OUString aBufStr;
    1968             :             double nVal;
    1969           0 :             bool bForm = false;
    1970           0 :             SCROW r = nRow - nStartRow + 1;
    1971           0 :             SCCOL c = nCol - nStartCol + 1;
    1972           0 :             ScRefCellValue aCell;
    1973           0 :             aCell.assign(*pDoc, ScAddress(nCol, nRow, aRange.aStart.Tab()));
    1974           0 :             CellType eType = aCell.meType;
    1975           0 :             switch( eType )
    1976             :             {
    1977             :                 case CELLTYPE_FORMULA:
    1978           0 :                     bForm = bFormulas;
    1979           0 :                     if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
    1980           0 :                         goto hasvalue;
    1981             :                     else
    1982           0 :                         goto hasstring;
    1983             : 
    1984             :                 case CELLTYPE_VALUE:
    1985             :                 hasvalue:
    1986           0 :                     pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
    1987             : 
    1988           0 :                     aValStr = ::rtl::math::doubleToUString( nVal,
    1989             :                             rtl_math_StringFormat_Automatic,
    1990           0 :                             rtl_math_DecimalPlaces_Max, '.', true );
    1991             : 
    1992           0 :                     aBufStr = "C;X";
    1993           0 :                     aBufStr += OUString::number( c );
    1994           0 :                     aBufStr += ";Y";
    1995           0 :                     aBufStr += OUString::number( r );
    1996           0 :                     aBufStr += ";K";
    1997           0 :                     aBufStr += aValStr;
    1998           0 :                     lcl_WriteSimpleString( rStrm, aBufStr );
    1999           0 :                     goto checkformula;
    2000             : 
    2001             :                 case CELLTYPE_STRING:
    2002             :                 case CELLTYPE_EDIT:
    2003             :                 hasstring:
    2004           0 :                     aCellStr = pDoc->GetString(nCol, nRow, aRange.aStart.Tab());
    2005           0 :                     aCellStr = aCellStr.replaceAll( OUString('\n'), OUString(SYLK_LF) );
    2006             : 
    2007           0 :                     aBufStr = "C;X";
    2008           0 :                     aBufStr += OUString::number( c );
    2009           0 :                     aBufStr += ";Y";
    2010           0 :                     aBufStr += OUString::number( r );
    2011           0 :                     aBufStr += ";K";
    2012           0 :                     lcl_WriteSimpleString( rStrm, aBufStr );
    2013           0 :                     lcl_WriteString( rStrm, aCellStr, '"', ';' );
    2014             : 
    2015             :                 checkformula:
    2016           0 :                     if( bForm )
    2017             :                     {
    2018           0 :                         const ScFormulaCell* pFCell = aCell.mpFormula;
    2019           0 :                         switch ( pFCell->GetMatrixFlag() )
    2020             :                         {
    2021             :                             case MM_REFERENCE :
    2022           0 :                                 aCellStr.clear();
    2023           0 :                             break;
    2024             :                             default:
    2025           0 :                                 OUString aOUCellStr;
    2026           0 :                                 pFCell->GetFormula( aOUCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
    2027           0 :                                 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. */
    2032             :                         }
    2033           0 :                         if ( pFCell->GetMatrixFlag() != MM_NONE &&
    2034           0 :                                 aCellStr.startsWith("{") &&
    2035           0 :                                 aCellStr.endsWith("}") )
    2036             :                         {   // cut off matrix {} characters
    2037           0 :                             aCellStr = aCellStr.copy(1, aCellStr.getLength()-2);
    2038             :                         }
    2039           0 :                         if ( aCellStr[0] == '=' )
    2040           0 :                             aCellStr = aCellStr.copy(1);
    2041           0 :                         OUString aPrefix;
    2042           0 :                         switch ( pFCell->GetMatrixFlag() )
    2043             :                         {
    2044             :                             case MM_FORMULA :
    2045             :                             {   // diff expression with 'M' M$-extension
    2046             :                                 SCCOL nC;
    2047             :                                 SCROW nR;
    2048           0 :                                 pFCell->GetMatColsRows( nC, nR );
    2049           0 :                                 nC += c - 1;
    2050           0 :                                 nR += r - 1;
    2051           0 :                                 aPrefix = ";R";
    2052           0 :                                 aPrefix += OUString::number( nR );
    2053           0 :                                 aPrefix += ";C";
    2054           0 :                                 aPrefix += OUString::number( nC );
    2055           0 :                                 aPrefix += ";M";
    2056             :                             }
    2057           0 :                             break;
    2058             :                             case MM_REFERENCE :
    2059             :                             {   // diff expression with 'I' M$-extension
    2060           0 :                                 ScAddress aPos;
    2061           0 :                                 pFCell->GetMatrixOrigin( aPos );
    2062           0 :                                 aPrefix = ";I;R";
    2063           0 :                                 aPrefix += OUString::number( aPos.Row() - nStartRow + 1 );
    2064           0 :                                 aPrefix += ";C";
    2065           0 :                                 aPrefix += OUString::number( aPos.Col() - nStartCol + 1 );
    2066             :                             }
    2067           0 :                             break;
    2068             :                             default:
    2069             :                                 // formula Expression
    2070           0 :                                 aPrefix = ";E";
    2071             :                         }
    2072           0 :                         lcl_WriteSimpleString( rStrm, aPrefix );
    2073           0 :                         if ( !aCellStr.isEmpty() )
    2074           0 :                             lcl_WriteString( rStrm, aCellStr, 0, ';' );
    2075             :                     }
    2076           0 :                     WriteUnicodeOrByteEndl( rStrm );
    2077           0 :                     break;
    2078             : 
    2079             :                 default:
    2080             :                 {
    2081             :                     // added to avoid warnings
    2082             :                 }
    2083             :             }
    2084           0 :         }
    2085             :     }
    2086           0 :     lcl_WriteSimpleString( rStrm, OUString( 'E' ) );
    2087           0 :     WriteUnicodeOrByteEndl( rStrm );
    2088           0 :     return rStrm.GetError() == SVSTREAM_OK;
    2089             : }
    2090             : 
    2091           3 : bool ScImportExport::Doc2HTML( SvStream& rStrm, const OUString& rBaseURL )
    2092             : {
    2093             :     // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
    2094           3 :     ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
    2095           3 :         aStreamPath, aNonConvertibleChars, maFilterOptions );
    2096           3 :     return rStrm.GetError() == SVSTREAM_OK;
    2097             : }
    2098             : 
    2099           0 : bool ScImportExport::Doc2RTF( SvStream& rStrm )
    2100             : {
    2101             :     //  rtl_TextEncoding is ignored in ScExportRTF
    2102           0 :     ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
    2103           0 :     return rStrm.GetError() == SVSTREAM_OK;
    2104             : }
    2105             : 
    2106           0 : bool ScImportExport::Doc2Dif( SvStream& rStrm )
    2107             : {
    2108             :     // for DIF in the clipboard, IBM_850 is always used
    2109           0 :     ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
    2110           0 :     return true;
    2111             : }
    2112             : 
    2113           0 : bool ScImportExport::Dif2Doc( SvStream& rStrm )
    2114             : {
    2115           0 :     SCTAB nTab = aRange.aStart.Tab();
    2116           0 :     ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
    2117           0 :     pImportDoc->InitUndo( pDoc, nTab, nTab );
    2118             : 
    2119             :     // for DIF in the clipboard, IBM_850 is always used
    2120           0 :     ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
    2121             : 
    2122             :     SCCOL nEndCol;
    2123             :     SCROW nEndRow;
    2124           0 :     pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
    2125             :     // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
    2126           0 :     if ( nEndCol < aRange.aStart.Col() )
    2127           0 :         nEndCol = aRange.aStart.Col();
    2128           0 :     if ( nEndRow < aRange.aStart.Row() )
    2129           0 :         nEndRow = aRange.aStart.Row();
    2130           0 :     aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
    2131             : 
    2132           0 :     bool bOk = StartPaste();
    2133           0 :     if (bOk)
    2134             :     {
    2135           0 :         InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
    2136           0 :         pDoc->DeleteAreaTab( aRange, nFlags );
    2137           0 :         pImportDoc->CopyToDocument( aRange, nFlags, false, pDoc );
    2138           0 :         EndPaste();
    2139             :     }
    2140             : 
    2141           0 :     delete pImportDoc;
    2142             : 
    2143           0 :     return bOk;
    2144             : }
    2145             : 
    2146           0 : bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
    2147             : {
    2148           0 :     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
    2149           0 :     if (!pImp)
    2150           0 :         return false;
    2151           0 :     pImp->Read( rStrm, rBaseURL );
    2152           0 :     aRange = pImp->GetRange();
    2153             : 
    2154           0 :     bool bOk = StartPaste();
    2155           0 :     if (bOk)
    2156             :     {
    2157           0 :         InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
    2158           0 :         pDoc->DeleteAreaTab( aRange, nFlags );
    2159           0 :         pImp->WriteToDocument();
    2160           0 :         EndPaste();
    2161             :     }
    2162           0 :     delete pImp;
    2163           0 :     return bOk;
    2164             : }
    2165             : 
    2166           0 : bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
    2167             : {
    2168           0 :     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, true);
    2169           0 :     if (!pImp)
    2170           0 :         return false;
    2171           0 :     pImp->Read( rStrm, rBaseURL );
    2172           0 :     aRange = pImp->GetRange();
    2173             : 
    2174           0 :     bool bOk = StartPaste();
    2175           0 :     if (bOk)
    2176             :     {
    2177             :         // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
    2178             :         // a Draw Layer but no Draw View -> create Draw Layer and View here
    2179           0 :         if (pDocSh)
    2180           0 :             pDocSh->MakeDrawLayer();
    2181             : 
    2182           0 :         InsertDeleteFlags nFlags = IDF_ALL & ~IDF_STYLES;
    2183           0 :         pDoc->DeleteAreaTab( aRange, nFlags );
    2184             : 
    2185           0 :         if (pExtOptions)
    2186             :         {
    2187             :             // Pick up import options if available.
    2188           0 :             LanguageType eLang = pExtOptions->GetLanguage();
    2189           0 :             SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
    2190           0 :             bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
    2191           0 :             pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
    2192             :         }
    2193             :         else
    2194             :             // Regular import, with no options.
    2195           0 :             pImp->WriteToDocument();
    2196             : 
    2197           0 :         EndPaste();
    2198             :     }
    2199           0 :     delete pImp;
    2200           0 :     return bOk;
    2201             : }
    2202             : 
    2203             : #ifndef DISABLE_DYNLOADING
    2204             : 
    2205             : class ScFormatFilterMissing : public ScFormatFilterPlugin {
    2206             :   public:
    2207           0 :     ScFormatFilterMissing()
    2208           0 :     {
    2209             :       OSL_FAIL("Missing file filters");
    2210           0 :     }
    2211           0 :     virtual ~ScFormatFilterMissing() {}
    2212           0 :     virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, rtl_TextEncoding ) SAL_OVERRIDE { return eERR_INTERN; }
    2213           0 :     virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) SAL_OVERRIDE { return eERR_INTERN; }
    2214           0 :     virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) SAL_OVERRIDE { return eERR_INTERN; }
    2215           0 :     virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) SAL_OVERRIDE { return eERR_INTERN; }
    2216           0 :     virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
    2217           0 :                  const rtl_TextEncoding, sal_uInt32 ) SAL_OVERRIDE { return eERR_INTERN; }
    2218           0 :     virtual FltError ScImportRTF( SvStream&, const OUString&, ScDocument*, ScRange& ) SAL_OVERRIDE { return eERR_INTERN; }
    2219           0 :     virtual FltError ScImportHTML( SvStream&, const OUString&, ScDocument*, ScRange&, double, bool, SvNumberFormatter*, bool ) SAL_OVERRIDE { return eERR_INTERN; }
    2220             : 
    2221           0 :     virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) SAL_OVERRIDE { return NULL; }
    2222           0 :     virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const OUString&, const ScRange&, bool ) SAL_OVERRIDE { return NULL; }
    2223           0 :     virtual OUString       GetHTMLRangeNameList( ScDocument*, const OUString& ) SAL_OVERRIDE { return OUString(); }
    2224             : 
    2225           0 :     virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, rtl_TextEncoding ) SAL_OVERRIDE { return eERR_INTERN; }
    2226           0 :     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const rtl_TextEncoding, sal_uInt32 ) SAL_OVERRIDE { return eERR_INTERN; }
    2227           0 :     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const rtl_TextEncoding, sal_uInt32 ) SAL_OVERRIDE { return eERR_INTERN; }
    2228           0 :     virtual FltError ScExportHTML( SvStream&, const OUString&, ScDocument*, const ScRange&, const rtl_TextEncoding, bool,
    2229           0 :                   const OUString&, OUString&, const OUString& ) SAL_OVERRIDE { return eERR_INTERN; }
    2230           0 :     virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const rtl_TextEncoding ) SAL_OVERRIDE { return eERR_INTERN; }
    2231             : 
    2232           0 :     virtual ScOrcusFilters* GetOrcusFilters() SAL_OVERRIDE { return NULL; }
    2233             : };
    2234             : 
    2235           0 : extern "C" { static void SAL_CALL thisModule() {} }
    2236             : 
    2237             : #else
    2238             : 
    2239             : extern "C" {
    2240             : ScFormatFilterPlugin* ScFilterCreate();
    2241             : }
    2242             : 
    2243             : #endif
    2244             : 
    2245             : typedef ScFormatFilterPlugin * (*FilterFn)(void);
    2246         114 : ScFormatFilterPlugin &ScFormatFilter::Get()
    2247             : {
    2248             :     static ScFormatFilterPlugin *plugin;
    2249             : 
    2250         114 :     if (plugin != NULL)
    2251         105 :         return *plugin;
    2252             : 
    2253             : #ifndef DISABLE_DYNLOADING
    2254           9 :     OUString sFilterLib(SVLIBRARY("scfilt"));
    2255           9 :     static ::osl::Module aModule;
    2256           9 :     bool bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
    2257           9 :     if (!bLoaded)
    2258           0 :         bLoaded = aModule.load(sFilterLib);
    2259           9 :     if (bLoaded)
    2260             :     {
    2261           9 :         oslGenericFunction fn = aModule.getFunctionSymbol( OUString( "ScFilterCreate" ) );
    2262           9 :         if (fn != NULL)
    2263           9 :             plugin = reinterpret_cast<FilterFn>(fn)();
    2264             :     }
    2265           9 :     if (plugin == NULL)
    2266           0 :         plugin = new ScFormatFilterMissing();
    2267             : #else
    2268             :     plugin = ScFilterCreate();
    2269             : #endif
    2270             : 
    2271           9 :     return *plugin;
    2272             : }
    2273             : 
    2274             : // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
    2275             : // array.
    2276        1649 : static inline const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
    2277             :         sal_Unicode c )
    2278             : {
    2279        4640 :     while (*pStr)
    2280             :     {
    2281        1649 :         if (*pStr == c)
    2282         307 :             return pStr;
    2283        1342 :         ++pStr;
    2284             :     }
    2285        1342 :     return 0;
    2286             : }
    2287             : 
    2288          77 : OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
    2289             :         const OUString& rFieldSeparators, sal_Unicode cFieldQuote )
    2290             : {
    2291          77 :     OUString aStr;
    2292          77 :     rStream.ReadUniOrByteStringLine(aStr, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
    2293             : 
    2294          77 :     if (bEmbeddedLineBreak)
    2295             :     {
    2296          77 :         const sal_Unicode* pSeps = rFieldSeparators.getStr();
    2297             : 
    2298          77 :         QuoteType eQuoteState = FIELDEND_QUOTE;
    2299          77 :         bool bFieldStart = true;
    2300             : 
    2301          77 :         sal_Int32 nLastOffset = 0;
    2302          77 :         sal_Int32 nQuotes = 0;
    2303         176 :         while (!rStream.IsEof() && aStr.getLength() < nArbitraryLineLengthLimit)
    2304             :         {
    2305             :             const sal_Unicode *p, *pStart;
    2306          95 :             p = pStart = aStr.getStr();
    2307          95 :             p += nLastOffset;
    2308        4197 :             while (*p)
    2309             :             {
    2310        4007 :                 if (nQuotes)
    2311             :                 {
    2312        2863 :                     if (*p == cFieldQuote)
    2313             :                     {
    2314         484 :                         if (bFieldStart)
    2315             :                         {
    2316         164 :                             ++nQuotes;
    2317         164 :                             bFieldStart = false;
    2318         164 :                             eQuoteState = FIELDSTART_QUOTE;
    2319             :                         }
    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         320 :                         else if (eQuoteState != FIELDEND_QUOTE)
    2324             :                         {
    2325         290 :                             eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote);
    2326             :                             // DONTKNOW_QUOTE is an embedded unescaped quote we
    2327             :                             // don't count for pairing.
    2328         290 :                             if (eQuoteState != DONTKNOW_QUOTE)
    2329         241 :                                 ++nQuotes;
    2330             :                         }
    2331             :                     }
    2332        2379 :                     else if (eQuoteState == FIELDEND_QUOTE)
    2333             :                     {
    2334         546 :                         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         117 :                             bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
    2339             :                         else
    2340         429 :                             bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
    2341             :                     }
    2342             :                 }
    2343             :                 else
    2344             :                 {
    2345        1144 :                     if (*p == cFieldQuote && bFieldStart)
    2346             :                     {
    2347          29 :                         nQuotes = 1;
    2348          29 :                         eQuoteState = FIELDSTART_QUOTE;
    2349          29 :                         bFieldStart = false;
    2350             :                     }
    2351        1115 :                     else if (eQuoteState == FIELDEND_QUOTE)
    2352             :                     {
    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        1115 :                         if (bFieldStart)
    2358          69 :                             bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
    2359             :                         else
    2360        1046 :                             bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
    2361             :                     }
    2362             :                 }
    2363             :                 // A quote character inside a field content does not start
    2364             :                 // a quote.
    2365        4007 :                 ++p;
    2366             :             }
    2367             : 
    2368          95 :             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          73 :                 break;
    2373             :             else
    2374             :             {
    2375          22 :                 nLastOffset = aStr.getLength();
    2376          22 :                 OUString aNext;
    2377          22 :                 rStream.ReadUniOrByteStringLine(aNext, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
    2378          22 :                 aStr += OUString('\n');
    2379          22 :                 aStr += aNext;
    2380             :             }
    2381             :         }
    2382             :     }
    2383          77 :     return aStr;
    2384         156 : }
    2385             : 
    2386             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11