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

Generated by: LCOV version 1.10