summaryrefslogtreecommitdiff
path: root/sc/source/ui/docshell/impex.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/docshell/impex.cxx')
-rw-r--r--sc/source/ui/docshell/impex.cxx2101
1 files changed, 2101 insertions, 0 deletions
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
new file mode 100644
index 000000000000..133cb368e117
--- /dev/null
+++ b/sc/source/ui/docshell/impex.cxx
@@ -0,0 +1,2101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// System - Includes -----------------------------------------------------
+
+class StarBASIC;
+
+
+
+#ifndef PCH
+#include "sc.hrc"
+#define GLOBALOVERFLOW
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <osl/endian.h>
+#include <i18npool/mslangid.hxx>
+#include <tools/string.hxx>
+#include <rtl/math.hxx>
+#include <svtools/htmlout.hxx>
+#include <svl/zforlist.hxx>
+#define _SVSTDARR_ULONGS
+#include <svl/svstdarr.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/mieclip.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "global.hxx"
+#include "scerrors.hxx"
+#include "docsh.hxx"
+#include "undoblk.hxx"
+#include "rangenam.hxx"
+#include "viewdata.hxx"
+#include "tabvwsh.hxx"
+#include "filter.hxx"
+#include "asciiopt.hxx"
+#include "cell.hxx"
+#include "docoptio.hxx"
+#include "progress.hxx"
+#include "scitems.hxx"
+#include "editable.hxx"
+#include "compiler.hxx"
+#include "warnbox.hxx"
+
+#include "impex.hxx"
+
+// ause
+#include "editutil.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "stringutil.hxx"
+
+#include "globstr.hrc"
+#include <vcl/msgbox.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/module.hxx>
+
+//========================================================================
+
+namespace
+{
+ const String SYLK_LF = String::CreateFromAscii("\x1b :");
+ const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;");
+ const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\"");
+}
+
+enum SylkVersion
+{
+ SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
+ SYLK_OOO32, // Correct strings, plus multiline content.
+ SYLK_OWN, // Place our new versions, if any, before this value.
+ SYLK_OTHER // Assume that aliens wrote correct strings.
+};
+
+
+// Gesamtdokument ohne Undo
+
+
+ScImportExport::ScImportExport( ScDocument* p )
+ : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
+ nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( sal_True ),
+ bAll( sal_True ), bSingle( sal_True ), bUndo( false ),
+ bOverflow( false ), mbApi( true ), mExportTextOptions()
+{
+ pUndoDoc = NULL;
+ pExtOptions = NULL;
+}
+
+// Insert am Punkt ohne Bereichschecks
+
+
+ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
+ : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
+ aRange( rPt ),
+ nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( sal_True ),
+ bAll( false ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ),
+ bOverflow( false ), mbApi( true ), mExportTextOptions()
+{
+ pUndoDoc = NULL;
+ pExtOptions = NULL;
+}
+
+
+// ctor with a range is only used for export
+//! ctor with a string (and bSingle=sal_True) is also used for DdeSetData
+
+ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
+ : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
+ aRange( r ),
+ nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( sal_True ),
+ bAll( false ), bSingle( false ), bUndo( sal_Bool( pDocSh != NULL ) ),
+ bOverflow( false ), mbApi( true ), mExportTextOptions()
+{
+ pUndoDoc = NULL;
+ pExtOptions = NULL;
+ // Zur Zeit nur in einer Tabelle!
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+}
+
+// String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
+// Falls eine View existiert, wird die TabNo der View entnommen!
+
+
+ScImportExport::ScImportExport( ScDocument* p, const String& rPos )
+ : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
+ nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( sal_True ),
+ bAll( false ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ),
+ bOverflow( false ), mbApi( true ), mExportTextOptions()
+{
+ pUndoDoc = NULL;
+ pExtOptions = NULL;
+
+ SCTAB nTab = ScDocShell::GetCurTab();
+ aRange.aStart.SetTab( nTab );
+ String aPos( rPos );
+ // Benannter Bereich?
+ ScRangeName* pRange = pDoc->GetRangeName();
+ if( pRange )
+ {
+ const ScRangeData* pData = pRange->findByName(aPos);
+ if (pData)
+ {
+ if( pData->HasType( RT_REFAREA )
+ || pData->HasType( RT_ABSAREA )
+ || pData->HasType( RT_ABSPOS ) )
+ pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten
+ }
+ }
+ formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ // Bereich?
+ if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID )
+ bSingle = false;
+ // Zelle?
+ else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID )
+ aRange.aEnd = aRange.aStart;
+ else
+ bAll = sal_True;
+}
+
+
+ScImportExport::~ScImportExport()
+{
+ delete pUndoDoc;
+ delete pExtOptions;
+}
+
+
+void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
+{
+ if ( pExtOptions )
+ *pExtOptions = rOpt;
+ else
+ pExtOptions = new ScAsciiOptions( rOpt );
+
+ // "normale" Optionen uebernehmen
+
+ cSep = rOpt.GetFieldSeps().GetChar(0);
+ cStr = rOpt.GetTextSep();
+}
+
+
+sal_Bool ScImportExport::IsFormatSupported( sal_uLong nFormat )
+{
+ return sal_Bool( nFormat == FORMAT_STRING
+ || nFormat == SOT_FORMATSTR_ID_SYLK
+ || nFormat == SOT_FORMATSTR_ID_LINK
+ || nFormat == SOT_FORMATSTR_ID_HTML
+ || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE
+ || nFormat == SOT_FORMATSTR_ID_DIF );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Vorbereitung fuer Undo: Undo-Dokument erzeugen
+
+
+sal_Bool ScImportExport::StartPaste()
+{
+ if ( !bAll )
+ {
+ ScEditableTester aTester( pDoc, aRange );
+ if ( !aTester.IsEditable() )
+ {
+ InfoBox aInfoBox(Application::GetDefDialogParent(),
+ ScGlobal::GetRscString( aTester.GetMessageId() ) );
+ aInfoBox.Execute();
+ return false;
+ }
+ }
+ if( bUndo && pDocSh && pDoc->IsUndoEnabled())
+ {
+ pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
+ pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
+ pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pUndoDoc );
+ }
+ return sal_True;
+}
+
+// Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
+
+
+void ScImportExport::EndPaste()
+{
+ sal_Bool bHeight = pDocSh && pDocSh->AdjustRowHeight(
+ aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
+
+ if( pUndoDoc && pDoc->IsUndoEnabled() )
+ {
+ ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
+ pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
+ pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pRedoDoc );
+ ScMarkData aDestMark;
+ aDestMark.SelectOneTable( aRange.aStart.Tab() );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ new ScUndoPaste( pDocSh,
+ aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), aDestMark,
+ pUndoDoc, pRedoDoc, IDF_ALL, NULL,NULL,NULL,NULL ) );
+ }
+ pUndoDoc = NULL;
+ if( pDocSh )
+ {
+ if (!bHeight)
+ pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber
+ pDocSh->SetDocumentModified();
+ }
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ pViewSh->UpdateInputHandler();
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+sal_Bool ScImportExport::ImportData( const String& /* rMimeType */,
+ const ::com::sun::star::uno::Any & /* rValue */ )
+{
+ DBG_ASSERT( !this, "Implementation is missing" );
+ return false;
+}
+
+sal_Bool ScImportExport::ExportData( const String& rMimeType,
+ ::com::sun::star::uno::Any & rValue )
+{
+ SvMemoryStream aStrm;
+ // mba: no BaseURL for data exchange
+ if( ExportStream( aStrm, String(),
+ SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
+ {
+ aStrm << (sal_uInt8) 0;
+ rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
+ (sal_Int8*)aStrm.GetData(),
+ aStrm.Seek( STREAM_SEEK_TO_END ) );
+ return sal_True;
+ }
+ return false;
+}
+
+
+sal_Bool ScImportExport::ImportString( const ::rtl::OUString& rText, sal_uLong nFmt )
+{
+ switch ( nFmt )
+ {
+ // formats supporting unicode
+ case FORMAT_STRING :
+ {
+ ScImportStringStream aStrm( rText);
+ return ImportStream( aStrm, String(), nFmt );
+ // ImportStream must handle RTL_TEXTENCODING_UNICODE
+ }
+ //break;
+ default:
+ {
+ rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
+ ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc );
+ SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ );
+ aStrm.SetStreamCharSet( eEnc );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ return ImportStream( aStrm, String(), nFmt );
+ }
+ }
+}
+
+
+sal_Bool ScImportExport::ExportString( ::rtl::OUString& rText, sal_uLong nFmt )
+{
+ DBG_ASSERT( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
+ if ( nFmt != FORMAT_STRING )
+ {
+ rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
+ ByteString aTmp;
+ sal_Bool bOk = ExportByteString( aTmp, eEnc, nFmt );
+ rText = UniString( aTmp, eEnc );
+ return bOk;
+ }
+ // nSizeLimit not needed for OUString
+
+ SvMemoryStream aStrm;
+ aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ // mba: no BaseURL for data exc
+ if( ExportStream( aStrm, String(), nFmt ) )
+ {
+ aStrm << (sal_Unicode) 0;
+ aStrm.Seek( STREAM_SEEK_TO_END );
+
+ rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() );
+ return sal_True;
+ }
+ rText = rtl::OUString();
+ return false;
+
+ // ExportStream must handle RTL_TEXTENCODING_UNICODE
+}
+
+
+sal_Bool ScImportExport::ExportByteString( ByteString& rText, rtl_TextEncoding eEnc, sal_uLong nFmt )
+{
+ DBG_ASSERT( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
+ if ( eEnc == RTL_TEXTENCODING_UNICODE )
+ eEnc = gsl_getSystemTextEncoding();
+
+ if (!nSizeLimit)
+ nSizeLimit = STRING_MAXLEN;
+
+ SvMemoryStream aStrm;
+ aStrm.SetStreamCharSet( eEnc );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ // mba: no BaseURL for data exchange
+ if( ExportStream( aStrm, String(), nFmt ) )
+ {
+ aStrm << (sal_Char) 0;
+ aStrm.Seek( STREAM_SEEK_TO_END );
+ // Sicherheits-Check:
+ if( aStrm.Tell() <= (sal_uLong) STRING_MAXLEN )
+ {
+ rText = (const sal_Char*) aStrm.GetData();
+ return sal_True;
+ }
+ }
+ rText.Erase();
+ return false;
+}
+
+
+sal_Bool ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
+{
+ if( nFmt == FORMAT_STRING )
+ {
+ if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_SYLK )
+ {
+ if( Sylk2Doc( rStrm ) )
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_DIF )
+ {
+ if( Dif2Doc( rStrm ) )
+ return sal_True;
+ }
+ if( nFmt == FORMAT_RTF )
+ {
+ if( RTF2Doc( rStrm, rBaseURL ) )
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_LINK )
+ return sal_True; // Link-Import?
+ if ( nFmt == SOT_FORMATSTR_ID_HTML )
+ {
+ if( HTML2Doc( rStrm, rBaseURL ) )
+ return sal_True;
+ }
+ if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
+ {
+ MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
+ SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
+ if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
+ return sal_True;
+ }
+
+ return false;
+}
+
+
+sal_Bool ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
+{
+ if( nFmt == FORMAT_STRING )
+ {
+ if( Doc2Text( rStrm ) )
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_SYLK )
+ {
+ if( Doc2Sylk( rStrm ) )
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_DIF )
+ {
+ if( Doc2Dif( rStrm ) )
+ return sal_True;
+ }
+ if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll )
+ {
+ String aDocName;
+ if ( pDoc->IsClipboard() )
+ aDocName = ScGlobal::GetClipDocName();
+ else
+ {
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ if (pShell)
+ aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
+ }
+
+ DBG_ASSERT( aDocName.Len(), "ClipBoard document has no name! :-/" );
+ if( aDocName.Len() )
+ {
+ String aRefName;
+ sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
+ if( bSingle )
+ aRange.aStart.Format( aRefName, nFlags, pDoc, pDoc->GetAddressConvention() );
+ else
+ {
+ if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
+ nFlags |= SCA_TAB2_3D;
+ aRange.Format( aRefName, nFlags, pDoc );
+ }
+ String aAppName = Application::GetAppName();
+
+ WriteUnicodeOrByteString( rStrm, aAppName, sal_True );
+ WriteUnicodeOrByteString( rStrm, aDocName, sal_True );
+ WriteUnicodeOrByteString( rStrm, aRefName, sal_True );
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ rStrm << sal_Unicode(0);
+ else
+ rStrm << sal_Char(0);
+ return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
+ }
+ }
+ if( nFmt == SOT_FORMATSTR_ID_HTML )
+ {
+ if( Doc2HTML( rStrm, rBaseURL ) )
+ return sal_True;
+ }
+ if( nFmt == FORMAT_RTF )
+ {
+ if( Doc2RTF( rStrm ) )
+ return sal_True;
+ }
+
+ return false;
+}
+
+
+void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, sal_Bool bZero )
+{
+ rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
+ if ( eEnc == RTL_TEXTENCODING_UNICODE )
+ {
+ if ( !IsEndianSwap( rStrm ) )
+ rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) );
+ else
+ {
+ const sal_Unicode* p = rString.GetBuffer();
+ const sal_Unicode* const pStop = p + rString.Len();
+ while ( p < pStop )
+ {
+ rStrm << *p;
+ }
+ }
+ if ( bZero )
+ rStrm << sal_Unicode(0);
+ }
+ else
+ {
+ ByteString aByteStr( rString, eEnc );
+ rStrm << aByteStr.GetBuffer();
+ if ( bZero )
+ rStrm << sal_Char(0);
+ }
+}
+
+
+// This function could be replaced by endlub()
+void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
+{
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ { // same as endl() but unicode
+ switch ( rStrm.GetLineDelimiter() )
+ {
+ case LINEEND_CR :
+ rStrm << sal_Unicode(_CR);
+ break;
+ case LINEEND_LF :
+ rStrm << sal_Unicode(_LF);
+ break;
+ default:
+ rStrm << sal_Unicode(_CR) << sal_Unicode(_LF);
+ }
+ }
+ else
+ endl( rStrm );
+}
+
+
+enum DoubledQuoteMode
+{
+ DQM_KEEP, // both are taken
+ DQM_ESCAPE, // escaped quote, one is taken, one ignored
+ DQM_CONCAT, // first is end, next is start, both ignored => strings combined
+ DQM_SEPARATE // end one string and begin next
+};
+
+static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
+ sal_Unicode cStr, DoubledQuoteMode eMode )
+{
+ p++; //! jump over opening quote
+ sal_Bool bCont;
+ do
+ {
+ bCont = false;
+ const sal_Unicode* p0 = p;
+ for( ;; )
+ {
+ if( !*p )
+ break;
+ if( *p == cStr )
+ {
+ if ( *++p != cStr )
+ break;
+ // doubled quote char
+ switch ( eMode )
+ {
+ case DQM_KEEP :
+ p++; // both for us (not breaking for-loop)
+ break;
+ case DQM_ESCAPE :
+ p++; // one for us (breaking for-loop)
+ bCont = sal_True; // and more
+ break;
+ case DQM_CONCAT :
+ if ( p0+1 < p )
+ rString.Append( p0, sal::static_int_cast<xub_StrLen>( (p-1) - p0 ) ); // first part
+ p0 = ++p; // text of next part starts here
+ break;
+ case DQM_SEPARATE :
+ // positioned on next opening quote
+ break;
+ }
+ if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
+ break;
+ }
+ else
+ p++;
+ }
+ if ( p0 < p )
+ rString.Append( p0, sal::static_int_cast<xub_StrLen>( ((*p || *(p-1) == cStr) ? p-1 : p) - p0 ) );
+ } while ( bCont );
+ return p;
+}
+
+void lcl_UnescapeSylk( String & rString, SylkVersion eVersion )
+{
+ // Older versions didn't escape the semicolon.
+ // Older versions quoted the string and doubled embedded quotes, but not
+ // the semicolons, which was plain wrong.
+ if (eVersion >= SYLK_OOO32)
+ rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' );
+ else
+ rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' );
+
+ rString.SearchAndReplaceAll( SYLK_LF, _LF );
+}
+
+static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
+ String& rString, SylkVersion eVersion )
+{
+ const sal_Unicode* pStartQuote = p;
+ const sal_Unicode* pEndQuote = 0;
+ while( *(++p) )
+ {
+ if( *p == '"' )
+ {
+ pEndQuote = p;
+ if (eVersion >= SYLK_OOO32)
+ {
+ if (*(p+1) == ';')
+ {
+ if (*(p+2) == ';')
+ {
+ p += 2; // escaped ';'
+ pEndQuote = 0;
+ }
+ else
+ break; // end field
+ }
+ }
+ else
+ {
+ if (*(p+1) == '"')
+ {
+ ++p; // escaped '"'
+ pEndQuote = 0;
+ }
+ else if (*(p+1) == ';')
+ break; // end field
+ }
+ }
+ }
+ if (!pEndQuote)
+ pEndQuote = p; // Take all data as string.
+ rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) );
+ lcl_UnescapeSylk( rString, eVersion);
+ return p;
+}
+
+static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
+ String& rString, SylkVersion eVersion )
+{
+ const sal_Unicode* pStart = p;
+ if (eVersion >= SYLK_OOO32)
+ {
+ while (*p)
+ {
+ if (*p == ';')
+ {
+ if (*(p+1) == ';')
+ ++p; // escaped ';'
+ else
+ break; // end field
+ }
+ ++p;
+ }
+ rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
+ lcl_UnescapeSylk( rString, eVersion);
+ }
+ else
+ {
+ // Nasty. If in old versions the formula contained a semicolon, it was
+ // quoted and embedded quotes were doubled, but semicolons were not. If
+ // there was no semicolon, it could still contain quotes and doubled
+ // embedded quotes if it was something like ="a""b", which was saved as
+ // E"a""b" as is and has to be preserved, even if older versions
+ // couldn't even load it correctly. However, theoretically another
+ // field might follow and thus the line contain a semicolon again, such
+ // as ...;E"a""b";...
+ bool bQuoted = false;
+ if (*p == '"')
+ {
+ // May be a quoted expression or just a string constant expression
+ // with quotes.
+ while (*(++p))
+ {
+ if (*p == '"')
+ {
+ if (*(p+1) == '"')
+ ++p; // escaped '"'
+ else
+ break; // closing '"', had no ';' yet
+ }
+ else if (*p == ';')
+ {
+ bQuoted = true; // ';' within quoted expression
+ break;
+ }
+ }
+ p = pStart;
+ }
+ if (bQuoted)
+ p = lcl_ScanSylkString( p, rString, eVersion);
+ else
+ {
+ while (*p && *p != ';')
+ ++p;
+ rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
+ }
+ }
+ return p;
+}
+
+static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr )
+{
+ xub_StrLen n = 0;
+ while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND )
+ {
+ rString.Insert( cStr, n );
+ n += 2;
+ }
+}
+
+static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc )
+{
+ if (cEsc)
+ lcl_DoubleEscapeChar( rString, cEsc );
+
+ if (cQuote)
+ {
+ rString.Insert( cQuote, 0 );
+ rString.Append( cQuote );
+ }
+
+ ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
+}
+
+inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString )
+{
+ ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+sal_Bool ScImportExport::Text2Doc( SvStream& rStrm )
+{
+ sal_Bool bOk = sal_True;
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ sal_uLong nOldPos = rStrm.Tell();
+ rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
+ sal_Bool bData = sal_Bool( !bSingle );
+ if( !bSingle)
+ bOk = StartPaste();
+
+ while( bOk )
+ {
+ ByteString aByteLine;
+ String aLine, aCell;
+ SCROW nRow = nStartRow;
+ rStrm.Seek( nOldPos );
+ for( ;; )
+ {
+ rStrm.ReadUniOrByteStringLine( aLine );
+ if( rStrm.IsEof() )
+ break;
+ SCCOL nCol = nStartCol;
+ const sal_Unicode* p = aLine.GetBuffer();
+ while( *p )
+ {
+ aCell.Erase();
+ if( *p == cStr )
+ {
+ p = lcl_ScanString( p, aCell, cStr, DQM_KEEP );
+ while( *p && *p != cSep )
+ p++;
+ if( *p )
+ p++;
+ }
+ else
+ {
+ const sal_Unicode* q = p;
+ while( *p && *p != cSep )
+ p++;
+ aCell.Assign( q, sal::static_int_cast<xub_StrLen>( p - q ) );
+ if( *p )
+ p++;
+ }
+ if (ValidCol(nCol) && ValidRow(nRow) )
+ {
+ if( bSingle )
+ {
+ if (nCol>nEndCol) nEndCol = nCol;
+ if (nRow>nEndRow) nEndRow = nRow;
+ }
+ if( bData && nCol <= nEndCol && nRow <= nEndRow )
+ pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
+ }
+ else // zuviele Spalten/Zeilen
+ bOverflow = sal_True; // beim Import Warnung ausgeben
+ ++nCol;
+ }
+ ++nRow;
+ }
+
+ if( !bData )
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ bOk = StartPaste();
+ bData = sal_True;
+ }
+ else
+ break;
+ }
+
+ EndPaste();
+ return bOk;
+}
+
+ //
+ // erweiterter Ascii-Import
+ //
+
+
+static bool lcl_PutString(
+ ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat,
+ SvNumberFormatter* pFormatter, bool bDetectNumFormat,
+ ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
+ ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
+{
+ bool bMultiLine = false;
+ if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) )
+ return bMultiLine;
+
+ if ( nColFormat == SC_COL_TEXT )
+ {
+ double fDummy;
+ sal_uInt32 nIndex;
+ if (pFormatter->IsNumberFormat(rStr, nIndex, fDummy))
+ {
+ // Set the format of this cell to Text.
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
+ ScPatternAttr aNewAttrs(pDoc->GetPool());
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
+ pDoc->ApplyPattern(nCol, nRow, nTab, aNewAttrs);
+
+ }
+ pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) );
+ return bMultiLine;
+ }
+
+ if ( nColFormat == SC_COL_ENGLISH )
+ {
+ //! SetString mit Extra-Flag ???
+
+ SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
+ sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
+ double fVal;
+ if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
+ {
+ // Zahlformat wird nicht auf englisch gesetzt
+ pDoc->SetValue( nCol, nRow, nTab, fVal );
+ return bMultiLine;
+ }
+ // sonst weiter mit SetString
+ }
+ else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate
+ {
+ const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
+ xub_StrLen nLen = rStr.Len();
+ xub_StrLen nStart[nMaxNumberParts];
+ xub_StrLen nEnd[nMaxNumberParts];
+
+ sal_uInt16 nDP, nMP, nYP;
+ switch ( nColFormat )
+ {
+ case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
+ case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
+ case SC_COL_DMY:
+ default: nDP = 0; nMP = 1; nYP = 2; break;
+ }
+
+ sal_uInt16 nFound = 0;
+ sal_Bool bInNum = false;
+ for ( xub_StrLen nPos=0; nPos<nLen && (bInNum ||
+ nFound<nMaxNumberParts); nPos++ )
+ {
+ if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
+ nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T')
+ bInNum = false; // ISO-8601: YYYY-MM-DDThh:mm...
+ else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
+ && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
+ || ScGlobal::pCharClass->isDigit( rStr, nPos))
+ {
+ if (!bInNum)
+ {
+ bInNum = sal_True;
+ nStart[nFound] = nPos;
+ ++nFound;
+ }
+ nEnd[nFound-1] = nPos;
+ }
+ else
+ bInNum = false;
+ }
+
+ if ( nFound == 1 )
+ {
+ // try to break one number (without separators) into date fields
+
+ xub_StrLen nDateStart = nStart[0];
+ xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart;
+
+ if ( nDateLen >= 5 && nDateLen <= 8 &&
+ ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) )
+ {
+ // 6 digits: 2 each for day, month, year
+ // 8 digits: 4 for year, 2 each for day and month
+ // 5 or 7 digits: first field is shortened by 1
+
+ sal_Bool bLongYear = ( nDateLen >= 7 );
+ sal_Bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
+
+ sal_uInt16 nFieldStart = nDateStart;
+ for (sal_uInt16 nPos=0; nPos<3; nPos++)
+ {
+ sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits
+ if ( bLongYear && nPos == nYP )
+ nFieldEnd += 2; // 2 extra digits for long year
+ if ( bShortFirst && nPos == 0 )
+ --nFieldEnd; // first field shortened?
+
+ nStart[nPos] = nFieldStart;
+ nEnd[nPos] = nFieldEnd;
+ nFieldStart = nFieldEnd + 1;
+ }
+ nFound = 3;
+ }
+ }
+
+ if ( nFound >= 3 )
+ {
+ using namespace ::com::sun::star;
+ sal_Bool bSecondCal = false;
+ sal_uInt16 nDay = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32();
+ sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32();
+ String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
+ sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32();
+ if (!nMonth)
+ {
+ static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
+ static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
+ uno::Sequence< i18n::CalendarItem > xMonths;
+ sal_Int32 i, nMonthCount;
+ // first test all month names from local international
+ xMonths = rCalendar.getMonths();
+ nMonthCount = xMonths.getLength();
+ for (i=0; i<nMonthCount && !nMonth; i++)
+ {
+ if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
+ rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
+ xMonths[i].AbbrevName ) &&
+ rTransliteration.isEqual( aMStr, aSepShortened ) )
+ { // correct English abbreviation is SEPT,
+ // but data mostly contains SEP only
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ }
+ }
+ // if none found, then test english month names
+ if ( !nMonth && pSecondCalendar && pSecondTransliteration )
+ {
+ xMonths = pSecondCalendar->getMonths();
+ nMonthCount = xMonths.getLength();
+ for (i=0; i<nMonthCount && !nMonth; i++)
+ {
+ if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
+ pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
+ {
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ bSecondCal = sal_True;
+ }
+ else if ( i == 8 && pSecondTransliteration->isEqual(
+ aMStr, aSepShortened ) )
+ { // correct English abbreviation is SEPT,
+ // but data mostly contains SEP only
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ bSecondCal = sal_True;
+ }
+ }
+ }
+ }
+
+ SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
+ if ( nYear < 100 )
+ nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
+
+ CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
+ sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
+ if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
+ {
+ --nMonth;
+ pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
+ pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
+ sal_Int16 nHour, nMinute, nSecond, nMilli;
+ // #i14974# The imported value should have no fractional value, so set the
+ // time fields to zero (ICU calendar instance defaults to current date/time)
+ nHour = nMinute = nSecond = nMilli = 0;
+ if (nFound > 3)
+ nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32();
+ if (nFound > 4)
+ nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32();
+ if (nFound > 5)
+ nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32();
+ if (nFound > 6)
+ {
+ sal_Unicode cDec = '.';
+ rtl::OUString aT( &cDec, 1);
+ aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]);
+ rtl_math_ConversionStatus eStatus;
+ double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
+ if (eStatus == rtl_math_ConversionStatus_Ok)
+ nMilli = (sal_Int16) (1000.0 * fV + 0.5);
+ }
+ pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
+ pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
+ if ( pCalendar->isValid() )
+ {
+ double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
+ pCalendar->getEpochStart();
+ // #i14974# must use getLocalDateTime to get the same
+ // date values as set above
+ double fDays = pCalendar->getLocalDateTime();
+ fDays -= fDiff;
+
+ LanguageType eLatin, eCjk, eCtl;
+ pDoc->GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eDocLang = eLatin; //! which language for date formats?
+
+ short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
+ sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
+ // maybe there is a special format including seconds or milliseconds
+ if (nFound > 5)
+ nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
+
+ pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, false );
+
+ return bMultiLine; // success
+ }
+ }
+ }
+ }
+
+ // Standard or date not determined -> SetString / EditCell
+ if( rStr.Search( _LF ) == STRING_NOTFOUND )
+ {
+ ScSetStringParam aParam;
+ aParam.mpNumFormatter = pFormatter;
+ aParam.mbDetectNumberFormat = bDetectNumFormat;
+ aParam.mbSetTextCellFormat = true;
+ pDoc->SetString( nCol, nRow, nTab, rStr, &aParam );
+ }
+ else
+ {
+ bMultiLine = true;
+ pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
+ }
+ return bMultiLine;
+}
+
+
+String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted )
+{
+ xub_StrLen nLen = rLine.Len();
+ if (nNext > nLen)
+ nNext = nLen;
+ if ( nNext <= nStart )
+ return EMPTY_STRING;
+
+ const sal_Unicode* pStr = rLine.GetBuffer();
+
+ xub_StrLen nSpace = nNext;
+ while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
+ --nSpace;
+
+ rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"'));
+ if (rbIsQuoted)
+ return rLine.Copy(nStart+1, nSpace-nStart-2);
+ else
+ return rLine.Copy(nStart, nSpace-nStart);
+}
+
+sal_Bool ScImportExport::ExtText2Doc( SvStream& rStrm )
+{
+ if (!pExtOptions)
+ return Text2Doc( rStrm );
+
+ sal_uLong nOldPos = rStrm.Tell();
+ rStrm.Seek( STREAM_SEEK_TO_END );
+ ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
+ ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
+ rStrm.Seek( nOldPos );
+ rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
+
+ ScColumn::DoubleAllocSwitch aAllocSwitch(true);
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ sal_Bool bFixed = pExtOptions->IsFixedLen();
+ const String& rSeps = pExtOptions->GetFieldSeps();
+ const sal_Unicode* pSeps = rSeps.GetBuffer();
+ sal_Bool bMerge = pExtOptions->IsMergeSeps();
+ sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
+ const xub_StrLen* pColStart = pExtOptions->GetColStart();
+ const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
+ long nSkipLines = pExtOptions->GetStartRow();
+
+ LanguageType eDocLang = pExtOptions->GetLanguage();
+ SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang);
+ bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
+
+ // For date recognition
+ ::utl::TransliterationWrapper aTransliteration(
+ pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
+ aTransliteration.loadModuleIfNeeded( eDocLang );
+ CalendarWrapper aCalendar( pDoc->GetServiceManager() );
+ aCalendar.loadDefaultCalendar(
+ MsLangId::convertLanguageToLocale( eDocLang ) );
+ ::utl::TransliterationWrapper* pEnglishTransliteration = NULL;
+ CalendarWrapper* pEnglishCalendar = NULL;
+ if ( eDocLang != LANGUAGE_ENGLISH_US )
+ {
+ pEnglishTransliteration = new ::utl::TransliterationWrapper (
+ pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
+ aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
+ pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() );
+ pEnglishCalendar->loadDefaultCalendar(
+ MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) );
+ }
+
+ String aLine, aCell;
+ sal_uInt16 i;
+ SCROW nRow = nStartRow;
+
+ while(--nSkipLines>0)
+ {
+ rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored
+ if ( rStrm.IsEof() )
+ break;
+ }
+
+ // Determine range for Undo.
+ // TODO: we don't need this during import of a file to a new sheet or
+ // document, could set bDetermineRange=false then.
+ bool bDetermineRange = true;
+
+ // Row heights don't need to be adjusted on the fly if EndPaste() is called
+ // afterwards, which happens only if bDetermineRange. This variable also
+ // survives the toggle of bDetermineRange down at the end of the do{} loop.
+ bool bRangeIsDetermined = bDetermineRange;
+
+ bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
+
+ sal_uLong nOriginalStreamPos = rStrm.Tell();
+
+ do
+ {
+ for( ;; )
+ {
+ rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr);
+ if ( rStrm.IsEof() )
+ break;
+
+ xub_StrLen nLineLen = aLine.Len();
+ SCCOL nCol = nStartCol;
+ bool bMultiLine = false;
+ if ( bFixed ) // Feste Satzlaenge
+ {
+ // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
+ // overflow if there is really data following to be put behind
+ // the last column, which doesn't happen if info is
+ // SC_COL_SKIP.
+ for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
+ {
+ sal_uInt8 nFmt = pColFormat[i];
+ if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen
+ {
+ if (nCol > MAXCOL)
+ bOverflow = sal_True; // display warning on import
+ else if (!bDetermineRange)
+ {
+ xub_StrLen nStart = pColStart[i];
+ xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
+ bool bIsQuoted = false;
+ aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted );
+ if (bIsQuoted && bQuotedAsText)
+ nFmt = SC_COL_TEXT;
+
+ bMultiLine |= lcl_PutString(
+ pDoc, nCol, nRow, nTab, aCell, nFmt,
+ &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
+ pEnglishTransliteration, pEnglishCalendar);
+ }
+ ++nCol;
+ }
+ }
+ }
+ else // Nach Trennzeichen suchen
+ {
+ SCCOL nSourceCol = 0;
+ sal_uInt16 nInfoStart = 0;
+ const sal_Unicode* p = aLine.GetBuffer();
+ // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
+ // overflow if there is really data following to be put behind
+ // the last column, which doesn't happen if info is
+ // SC_COL_SKIP.
+ while (*p && nCol <= MAXCOL+1)
+ {
+ bool bIsQuoted = false;
+ p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted );
+
+ sal_uInt8 nFmt = SC_COL_STANDARD;
+ for ( i=nInfoStart; i<nInfoCount; i++ )
+ {
+ if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert
+ {
+ nFmt = pColFormat[i];
+ nInfoStart = i + 1; // ColInfos sind in Reihenfolge
+ break; // for
+ }
+ }
+ if ( nFmt != SC_COL_SKIP )
+ {
+ if (nCol > MAXCOL)
+ bOverflow = sal_True; // display warning on import
+ else if (!bDetermineRange)
+ {
+ if (bIsQuoted && bQuotedAsText)
+ nFmt = SC_COL_TEXT;
+
+ bMultiLine |= lcl_PutString(
+ pDoc, nCol, nRow, nTab, aCell, nFmt,
+ &aNumFormatter, bDetectNumFormat, aTransliteration,
+ aCalendar, pEnglishTransliteration, pEnglishCalendar);
+ }
+ ++nCol;
+ }
+
+ ++nSourceCol;
+ }
+ }
+ if (nEndCol < nCol)
+ nEndCol = nCol; //! points to the next free or even MAXCOL+2
+
+ if (!bDetermineRange)
+ {
+ if (bMultiLine && !bRangeIsDetermined && pDocSh)
+ pDocSh->AdjustRowHeight( nRow, nRow, nTab);
+ xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
+ }
+ ++nRow;
+ if ( nRow > MAXROW )
+ {
+ bOverflow = sal_True; // display warning on import
+ break; // for
+ }
+ }
+ // so far nRow/nEndCol pointed to the next free
+ if (nRow > nStartRow)
+ --nRow;
+ if (nEndCol > nStartCol)
+ nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
+
+ if (bDetermineRange)
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nRow );
+
+ if ( !mbApi && nStartCol != nEndCol &&
+ !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
+ {
+ ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
+ if ( aBox.Execute() != RET_YES )
+ {
+ delete pEnglishTransliteration;
+ delete pEnglishCalendar;
+ return false;
+ }
+ }
+
+ rStrm.Seek( nOriginalStreamPos );
+ nRow = nStartRow;
+ if (!StartPaste())
+ {
+ EndPaste();
+ return false;
+ }
+ }
+
+ bDetermineRange = !bDetermineRange; // toggle
+ } while (!bDetermineRange);
+
+ pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
+
+ delete pEnglishTransliteration;
+ delete pEnglishCalendar;
+
+ xProgress.reset(); // make room for AdjustRowHeight progress
+ if (bRangeIsDetermined)
+ EndPaste();
+
+ return sal_True;
+}
+
+
+const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
+ String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted )
+{
+ rbIsQuoted = false;
+ rField.Erase();
+ if ( *p == cStr ) // String in Anfuehrungszeichen
+ {
+ rbIsQuoted = true;
+ const sal_Unicode* p1;
+ p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE );
+ while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
+ p++;
+ // Append remaining unquoted and undelimited data (dirty, dirty) to
+ // this field.
+ if (p > p1)
+ rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) );
+ if( *p )
+ p++;
+ }
+ else // bis zum Trennzeichen
+ {
+ const sal_Unicode* p0 = p;
+ while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
+ p++;
+ rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
+ if( *p )
+ p++;
+ }
+ if ( bMergeSeps ) // folgende Trennzeichen ueberspringen
+ {
+ while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
+ p++;
+ }
+ return p;
+}
+
+namespace {
+
+/**
+ * Check if a given string has any line break characters or separators.
+ *
+ * @param rStr string to inspect.
+ * @param cSep separator character.
+ */
+bool hasLineBreaksOrSeps( const String& rStr, sal_Unicode cSep )
+{
+ const sal_Unicode* p = rStr.GetBuffer();
+ for (xub_StrLen i = 0, n = rStr.Len(); i < n; ++i, ++p)
+ {
+ sal_Unicode c = *p;
+ if (c == cSep)
+ // separator found.
+ return true;
+
+ switch (c)
+ {
+ case _LF:
+ case _CR:
+ // line break found.
+ return true;
+ default:
+ ;
+ }
+ }
+ return false;
+}
+
+}
+
+sal_Bool ScImportExport::Doc2Text( SvStream& rStrm )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ String aCell;
+ bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
+
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() ))
+ {
+ for (nCol = nStartCol; nCol <= nEndCol; nCol++)
+ {
+ CellType eType;
+ pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType );
+ switch (eType)
+ {
+ case CELLTYPE_FORMULA:
+ {
+ if (bFormulas)
+ {
+ pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell );
+ if( aCell.Search( cSep ) != STRING_NOTFOUND )
+ lcl_WriteString( rStrm, aCell, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCell );
+ }
+ else
+ {
+ pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
+
+ bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
+ if( bMultiLineText )
+ {
+ if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
+ aCell.SearchAndReplaceAll( _LF, ' ' );
+ else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
+ aCell.ConvertLineEnd();
+ }
+
+ if( mExportTextOptions.mcSeparatorConvertTo && cSep )
+ aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
+
+ if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
+ lcl_WriteString( rStrm, aCell, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCell );
+ }
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
+ lcl_WriteSimpleString( rStrm, aCell );
+ }
+ break;
+ case CELLTYPE_NOTE:
+ case CELLTYPE_NONE:
+ break;
+ default:
+ {
+ pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
+
+ bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
+ if( bMultiLineText )
+ {
+ if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
+ aCell.SearchAndReplaceAll( _LF, ' ' );
+ else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
+ aCell.ConvertLineEnd();
+ }
+
+ if( mExportTextOptions.mcSeparatorConvertTo && cSep )
+ aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
+
+ if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCell, cSep) )
+ lcl_WriteString( rStrm, aCell, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCell );
+ }
+ }
+ if( nCol < nEndCol )
+ lcl_WriteSimpleString( rStrm, String(cSep) );
+ }
+ WriteUnicodeOrByteEndl( rStrm );
+ if( rStrm.GetError() != SVSTREAM_OK )
+ break;
+ if( nSizeLimit && rStrm.Tell() > nSizeLimit )
+ break;
+ }
+ }
+
+ return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
+}
+
+
+sal_Bool ScImportExport::Sylk2Doc( SvStream& rStrm )
+{
+ sal_Bool bOk = sal_True;
+ sal_Bool bMyDoc = false;
+ SylkVersion eVersion = SYLK_OTHER;
+
+ // US-English separators for StringToDouble
+ sal_Unicode cDecSep = '.';
+ sal_Unicode cGrpSep = ',';
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ sal_uLong nOldPos = rStrm.Tell();
+ sal_Bool bData = sal_Bool( !bSingle );
+ SvULongs aFormats;
+
+ if( !bSingle)
+ bOk = StartPaste();
+
+ while( bOk )
+ {
+ String aLine;
+ String aText;
+ ByteString aByteLine;
+ SCCOL nCol = nStartCol;
+ SCROW nRow = nStartRow;
+ SCCOL nRefCol = 1;
+ SCROW nRefRow = 1;
+ rStrm.Seek( nOldPos );
+ for( ;; )
+ {
+ //! allow unicode
+ rStrm.ReadLine( aByteLine );
+ aLine = String( aByteLine, rStrm.GetStreamCharSet() );
+ if( rStrm.IsEof() )
+ break;
+ const sal_Unicode* p = aLine.GetBuffer();
+ sal_Unicode cTag = *p++;
+ if( cTag == 'C' ) // Content
+ {
+ if( *p++ != ';' )
+ return false;
+ while( *p )
+ {
+ sal_Unicode ch = *p++;
+ ch = ScGlobal::ToUpperAlpha( ch );
+ switch( ch )
+ {
+ case 'X':
+ nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
+ break;
+ case 'Y':
+ nRow = String( p ).ToInt32() + nStartRow - 1;
+ break;
+ case 'C':
+ nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
+ break;
+ case 'R':
+ nRefRow = String( p ).ToInt32() + nStartRow - 1;
+ break;
+ case 'K':
+ {
+ if( !bSingle &&
+ ( nCol < nStartCol || nCol > nEndCol
+ || nRow < nStartRow || nRow > nEndRow
+ || nCol > MAXCOL || nRow > MAXROW ) )
+ break;
+ if( !bData )
+ {
+ if( nRow > nEndRow )
+ nEndRow = nRow;
+ if( nCol > nEndCol )
+ nEndCol = nCol;
+ break;
+ }
+ sal_Bool bText;
+ if( *p == '"' )
+ {
+ bText = sal_True;
+ aText.Erase();
+ p = lcl_ScanSylkString( p, aText, eVersion);
+ }
+ else
+ bText = false;
+ const sal_Unicode* q = p;
+ while( *q && *q != ';' )
+ q++;
+ if ( !(*q == ';' && *(q+1) == 'I') )
+ { // don't ignore value
+ if( bText )
+ {
+ pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(),
+ ScBaseCell::CreateTextCell( aText, pDoc),
+ (sal_Bool) sal_True);
+ }
+ else
+ {
+ double fVal = rtl_math_uStringToDouble( p,
+ aLine.GetBuffer() + aLine.Len(),
+ cDecSep, cGrpSep, NULL, NULL );
+ pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
+ }
+ }
+ }
+ break;
+ case 'E':
+ case 'M':
+ {
+ if ( ch == 'M' )
+ {
+ if ( nRefCol < nCol )
+ nRefCol = nCol;
+ if ( nRefRow < nRow )
+ nRefRow = nRow;
+ if ( !bData )
+ {
+ if( nRefRow > nEndRow )
+ nEndRow = nRefRow;
+ if( nRefCol > nEndCol )
+ nEndCol = nRefCol;
+ }
+ }
+ if( !bMyDoc || !bData )
+ break;
+ aText = '=';
+ p = lcl_ScanSylkFormula( p, aText, eVersion);
+ ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
+ /* FIXME: do we want GRAM_ODFF_A1 instead? At the
+ * end it probably should be GRAM_ODFF_R1C1, since
+ * R1C1 is what Excel writes in SYLK. */
+ const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
+ ScCompiler aComp( pDoc, aPos);
+ aComp.SetGrammar(eGrammar);
+ ScTokenArray* pCode = aComp.CompileString( aText );
+ if ( ch == 'M' )
+ {
+ ScMarkData aMark;
+ aMark.SelectTable( aPos.Tab(), sal_True );
+ pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
+ nRefRow, aMark, EMPTY_STRING, pCode );
+ }
+ else
+ {
+ ScFormulaCell* pFCell = new ScFormulaCell(
+ pDoc, aPos, pCode, eGrammar, MM_NONE);
+ pDoc->PutCell( aPos, pFCell );
+ }
+ delete pCode; // ctor/InsertMatrixFormula did copy TokenArray
+ }
+ break;
+ }
+ while( *p && *p != ';' )
+ p++;
+ if( *p )
+ p++;
+ }
+ }
+ else if( cTag == 'F' ) // Format
+ {
+ if( *p++ != ';' )
+ return false;
+ sal_Int32 nFormat = -1;
+ while( *p )
+ {
+ sal_Unicode ch = *p++;
+ ch = ScGlobal::ToUpperAlpha( ch );
+ switch( ch )
+ {
+ case 'X':
+ nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
+ break;
+ case 'Y':
+ nRow = String( p ).ToInt32() + nStartRow - 1;
+ break;
+ case 'P' :
+ if ( bData )
+ {
+ // F;P<n> sets format code of P;P<code> at
+ // current position, or at ;X;Y if specified.
+ // Note that ;X;Y may appear after ;P
+ const sal_Unicode* p0 = p;
+ while( *p && *p != ';' )
+ p++;
+ String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
+ nFormat = aNumber.ToInt32();
+ }
+ break;
+ }
+ while( *p && *p != ';' )
+ p++;
+ if( *p )
+ p++;
+ }
+ if ( !bData )
+ {
+ if( nRow > nEndRow )
+ nEndRow = nRow;
+ if( nCol > nEndCol )
+ nEndCol = nCol;
+ }
+ if ( 0 <= nFormat && nFormat < aFormats.Count() )
+ {
+ sal_uLong nKey = aFormats[(sal_uInt16)nFormat];
+ pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
+ SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
+ }
+ }
+ else if( cTag == 'P' )
+ {
+ if ( bData && *p == ';' && *(p+1) == 'P' )
+ {
+ String aCode( p+2 );
+ // unescape doubled semicolons
+ xub_StrLen nPos = 0;
+ String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;"));
+ while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND )
+ aCode.Erase( nPos++, 1 );
+ // get rid of Xcl escape characters
+ nPos = 0;
+ while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND )
+ aCode.Erase( nPos, 1 );
+ xub_StrLen nCheckPos;
+ short nType;
+ sal_uInt32 nKey;
+ pDoc->GetFormatTable()->PutandConvertEntry(
+ aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US,
+ ScGlobal::eLnge );
+ if ( nCheckPos )
+ nKey = 0;
+ aFormats.Insert( nKey, aFormats.Count() );
+ }
+ }
+ else if( cTag == 'I' && *p == 'D' )
+ {
+ aLine.Erase( 0, 4 );
+ if (aLine.EqualsAscii( "CALCOOO32" ))
+ eVersion = SYLK_OOO32;
+ else if (aLine.EqualsAscii( "SCALC3" ))
+ eVersion = SYLK_SCALC3;
+ bMyDoc = (eVersion <= SYLK_OWN);
+ }
+ else if( cTag == 'E' ) // Ende
+ break;
+ }
+ if( !bData )
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ bOk = StartPaste();
+ bData = sal_True;
+ }
+ else
+ break;
+ }
+
+ EndPaste();
+ return bOk;
+}
+
+
+sal_Bool ScImportExport::Doc2Sylk( SvStream& rStrm )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ String aCellStr;
+ String aValStr;
+ lcl_WriteSimpleString( rStrm,
+ String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
+ WriteUnicodeOrByteEndl( rStrm );
+
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ for (nCol = nStartCol; nCol <= nEndCol; nCol++)
+ {
+ String aBufStr;
+ double nVal;
+ sal_Bool bForm = false;
+ SCROW r = nRow - nStartRow + 1;
+ SCCOL c = nCol - nStartCol + 1;
+ ScBaseCell* pCell;
+ pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell );
+ CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE);
+ switch( eType )
+ {
+ case CELLTYPE_FORMULA:
+ bForm = bFormulas;
+ if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
+ goto hasvalue;
+ else
+ goto hasstring;
+
+ case CELLTYPE_VALUE:
+ hasvalue:
+ pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
+
+ aValStr = ::rtl::math::doubleToUString( nVal,
+ rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, '.', sal_True );
+
+ aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
+ aBufStr += String::CreateFromInt32( c );
+ aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
+ aBufStr += String::CreateFromInt32( r );
+ aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
+ aBufStr += aValStr;
+ lcl_WriteSimpleString( rStrm, aBufStr );
+ goto checkformula;
+
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ hasstring:
+ pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
+ aCellStr.SearchAndReplaceAll( _LF, SYLK_LF );
+
+ aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
+ aBufStr += String::CreateFromInt32( c );
+ aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
+ aBufStr += String::CreateFromInt32( r );
+ aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
+ lcl_WriteSimpleString( rStrm, aBufStr );
+ lcl_WriteString( rStrm, aCellStr, '"', ';' );
+
+ checkformula:
+ if( bForm )
+ {
+ const ScFormulaCell* pFCell =
+ static_cast<const ScFormulaCell*>(pCell);
+ switch ( pFCell->GetMatrixFlag() )
+ {
+ case MM_REFERENCE :
+ aCellStr.Erase();
+ break;
+ default:
+ pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
+ /* FIXME: do we want GRAM_ODFF_A1 instead? At
+ * the end it probably should be
+ * GRAM_ODFF_R1C1, since R1C1 is what Excel
+ * writes in SYLK. */
+ }
+ if ( pFCell->GetMatrixFlag() != MM_NONE &&
+ aCellStr.Len() > 2 &&
+ aCellStr.GetChar(0) == '{' &&
+ aCellStr.GetChar(aCellStr.Len()-1) == '}' )
+ { // cut off matrix {} characters
+ aCellStr.Erase(aCellStr.Len()-1,1);
+ aCellStr.Erase(0,1);
+ }
+ if ( aCellStr.GetChar(0) == '=' )
+ aCellStr.Erase(0,1);
+ String aPrefix;
+ switch ( pFCell->GetMatrixFlag() )
+ {
+ case MM_FORMULA :
+ { // diff expression with 'M' M$-extension
+ SCCOL nC;
+ SCROW nR;
+ pFCell->GetMatColsRows( nC, nR );
+ nC += c - 1;
+ nR += r - 1;
+ aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
+ aPrefix += String::CreateFromInt32( nR );
+ aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
+ aPrefix += String::CreateFromInt32( nC );
+ aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
+ }
+ break;
+ case MM_REFERENCE :
+ { // diff expression with 'I' M$-extension
+ ScAddress aPos;
+ pFCell->GetMatrixOrigin( aPos );
+ aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
+ aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 );
+ aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
+ aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 );
+ }
+ break;
+ default:
+ // formula Expression
+ aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
+ }
+ lcl_WriteSimpleString( rStrm, aPrefix );
+ if ( aCellStr.Len() )
+ lcl_WriteString( rStrm, aCellStr, 0, ';' );
+ }
+ WriteUnicodeOrByteEndl( rStrm );
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ lcl_WriteSimpleString( rStrm, String( 'E' ) );
+ WriteUnicodeOrByteEndl( rStrm );
+ return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
+}
+
+
+sal_Bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL )
+{
+ // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
+ ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
+ aStreamPath, aNonConvertibleChars );
+ return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
+}
+
+sal_Bool ScImportExport::Doc2RTF( SvStream& rStrm )
+{
+ // CharSet is ignored in ScExportRTF
+ ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
+ return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
+}
+
+
+sal_Bool ScImportExport::Doc2Dif( SvStream& rStrm )
+{
+ // for DIF in the clipboard, IBM_850 is always used
+ ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
+ return sal_True;
+}
+
+
+sal_Bool ScImportExport::Dif2Doc( SvStream& rStrm )
+{
+ SCTAB nTab = aRange.aStart.Tab();
+ ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
+ pImportDoc->InitUndo( pDoc, nTab, nTab );
+
+ // for DIF in the clipboard, IBM_850 is always used
+ ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
+
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
+ // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
+ if ( nEndCol < aRange.aStart.Col() )
+ nEndCol = aRange.aStart.Col();
+ if ( nEndRow < aRange.aStart.Row() )
+ nEndRow = aRange.aStart.Row();
+ aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
+
+ sal_Bool bOk = StartPaste();
+ if (bOk)
+ {
+ sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
+ pDoc->DeleteAreaTab( aRange, nFlags );
+ pImportDoc->CopyToDocument( aRange, nFlags, false, pDoc );
+ EndPaste();
+ }
+
+ delete pImportDoc;
+
+ return bOk;
+}
+
+
+sal_Bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL )
+{
+ ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
+ if (!pImp)
+ return false;
+ pImp->Read( rStrm, rBaseURL );
+ aRange = pImp->GetRange();
+
+ sal_Bool bOk = StartPaste();
+ if (bOk)
+ {
+ sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
+ pDoc->DeleteAreaTab( aRange, nFlags );
+ pImp->WriteToDocument();
+ EndPaste();
+ }
+ delete pImp;
+ return bOk;
+}
+
+
+sal_Bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL )
+{
+ ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, sal_True);
+ if (!pImp)
+ return false;
+ pImp->Read( rStrm, rBaseURL );
+ aRange = pImp->GetRange();
+
+ sal_Bool bOk = StartPaste();
+ if (bOk)
+ {
+ // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
+ // a Draw Layer but no Draw View -> create Draw Layer and View here
+ if (pDocSh)
+ pDocSh->MakeDrawLayer();
+
+ sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
+ pDoc->DeleteAreaTab( aRange, nFlags );
+
+ if (pExtOptions)
+ {
+ // Pick up import options if available.
+ LanguageType eLang = pExtOptions->GetLanguage();
+ SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eLang);
+ bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
+ pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
+ }
+ else
+ // Regular import, with no options.
+ pImp->WriteToDocument();
+
+ EndPaste();
+ }
+ delete pImp;
+ return bOk;
+}
+
+#define RETURN_ERROR { return eERR_INTERN; }
+class ScFormatFilterMissing : public ScFormatFilterPlugin {
+ public:
+ ScFormatFilterMissing()
+ {
+ OSL_FAIL("Missing file filters");
+ }
+ virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR
+ virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
+ virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
+ virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
+ virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
+ const CharSet, sal_uInt32 ) RETURN_ERROR
+ virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR
+ virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, sal_Bool, SvNumberFormatter*, bool ) RETURN_ERROR
+
+ virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
+ virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, sal_Bool ) { return NULL; }
+ virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); }
+
+#if ENABLE_LOTUS123_EXPORT
+ virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR
+#endif
+ virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR
+ virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR
+ virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR
+ virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, sal_Bool,
+ const String&, String& ) RETURN_ERROR
+ virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR
+};
+
+extern "C" { static void SAL_CALL thisModule() {} }
+typedef ScFormatFilterPlugin * (*FilterFn)(void);
+ScFormatFilterPlugin &ScFormatFilter::Get()
+{
+ static ScFormatFilterPlugin *plugin;
+
+ if (plugin != NULL)
+ return *plugin;
+
+ static ::osl::Module aModule;
+ if ( aModule.loadRelative( &thisModule,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) )
+ {
+ oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ScFilterCreate" )) );
+ if (fn != NULL)
+ plugin = reinterpret_cast<FilterFn>(fn)();
+ }
+ if (plugin == NULL)
+ plugin = new ScFormatFilterMissing();
+
+ return *plugin;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */