| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 --------------------------------------------------------------- |
| |
| #include <stdio.h> |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <osl/endian.h> |
| #include <i18npool/mslangid.hxx> |
| #include <tools/list.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 "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( sal_False ), bIncludeFiltered( sal_True ), |
| bAll( sal_True ), bSingle( sal_True ), bUndo( sal_False ), |
| bOverflow( sal_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( sal_False ), bIncludeFiltered( sal_True ), |
| bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ), |
| bOverflow( sal_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( sal_False ), bIncludeFiltered( sal_True ), |
| bAll( sal_False ), bSingle( sal_False ), bUndo( sal_Bool( pDocSh != NULL ) ), |
| bOverflow( sal_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( sal_False ), bIncludeFiltered( sal_True ), |
| bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ), |
| bOverflow( sal_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 ) |
| { |
| sal_uInt16 nPos; |
| if( pRange->SearchName( aPos, nPos ) ) |
| { |
| ScRangeData* pData = (*pRange)[ nPos ]; |
| 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 = sal_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 sal_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, sal_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, sal_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(); |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| |
| #if 0 |
| sal_Bool ScImportExport::ImportData( SvData& rData ) |
| { |
| sal_uLong nFmt = rData.GetFormat(); |
| if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE ) |
| { |
| MSE40HTMLClipFormatObj aMSE40ClpObj; |
| if ( aMSE40ClpObj.GetData( rData ) ) |
| { |
| SvStream* pStream = aMSE40ClpObj.GetStream(); |
| return ImportStream( *pStream, nFmt ); |
| } |
| return sal_False; |
| } |
| else |
| { |
| void* pMem; |
| sal_uLong nSize = rData.GetMinMemorySize(); |
| rData.GetData( &pMem, TRANSFER_REFERENCE ); |
| if( nFmt == FORMAT_STRING |
| || nFmt == FORMAT_RTF |
| || nFmt == SOT_FORMATSTR_ID_SYLK |
| || nFmt == SOT_FORMATSTR_ID_HTML |
| || nFmt == SOT_FORMATSTR_ID_DIF ) |
| { |
| //! String? Unicode?? |
| |
| // Stringende ermitteln! |
| sal_Char* pBegin = (sal_Char*) pMem; |
| sal_Char* pEnd = (sal_Char*) pMem + nSize; |
| |
| nSize = 0; |
| while( pBegin != pEnd && *pBegin != '\0' ) |
| pBegin++, nSize++; |
| // #72909# MT says only STRING has to be zero-terminated |
| DBG_ASSERT( pBegin != pEnd || nFmt != FORMAT_STRING, "non zero-terminated String" ) |
| } |
| SvMemoryStream aStrm( pMem, nSize, STREAM_READ ); |
| return ImportStream( aStrm, nFmt ); |
| } |
| } |
| |
| #endif |
| |
| sal_Bool ScImportExport::ImportData( const String& /* rMimeType */, |
| const ::com::sun::star::uno::Any & /* rValue */ ) |
| { |
| DBG_ASSERT( !this, "Implementation is missing" ); |
| return sal_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 sal_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 sal_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 sal_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 sal_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 sal_False; |
| } |
| |
| |
| //static |
| 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() |
| // static |
| 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 = sal_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 )//cStr = " |
| { |
| p = lcl_ScanString( p, aCell, cStr, DQM_KEEP ); |
| } |
| |
| const sal_Unicode* q = p; |
| while( *p && *p != cSep )// cSep = tab |
| p++; |
| |
| aCell.Append( 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 ) |
| { |
| 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 = sal_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 = sal_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 = sal_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 = sal_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 ) ) |
| { // #102136# 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 ) ) |
| { // #102136# 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, sal_False ); |
| |
| return bMultiLine; // success |
| } |
| } |
| } |
| } |
| |
| // Standard or date not determined -> SetString / EditCell |
| if( rStr.Search( _LF ) == STRING_NOTFOUND ) |
| pDoc->SetString( nCol, nRow, nTab, rStr, pFormatter, bDetectNumFormat ); |
| 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() ); |
| |
| sal_Bool bOld = ScColumn::bDoubleAlloc; |
| ScColumn::bDoubleAlloc = sal_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 sal_False; |
| } |
| } |
| |
| rStrm.Seek( nOriginalStreamPos ); |
| nRow = nStartRow; |
| if (!StartPaste()) |
| { |
| EndPaste(); |
| return sal_False; |
| } |
| } |
| |
| bDetermineRange = !bDetermineRange; // toggle |
| } while (!bDetermineRange); |
| |
| ScColumn::bDoubleAlloc = bOld; |
| pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 ); |
| |
| delete pEnglishTransliteration; |
| delete pEnglishCalendar; |
| |
| xProgress.reset(); // make room for AdjustRowHeight progress |
| if (bRangeIsDetermined) |
| EndPaste(); |
| |
| return sal_True; |
| } |
| |
| |
| // static |
| 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; |
| } |
| |
| // |
| // |
| // |
| |
| |
| 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, sal_True ); |
| 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 && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) |
| lcl_WriteString( rStrm, aCell, cStr, cStr ); |
| else |
| lcl_WriteSimpleString( rStrm, aCell ); |
| } |
| } |
| if( nCol < nEndCol ) |
| lcl_WriteSimpleString( rStrm, String(cSep) ); |
| } |
| // if( nRow < nEndRow ) |
| 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 = sal_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 sal_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 = sal_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 sal_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 = sal_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 ); |
| // #131247# 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, sal_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 ); |
| pImp->WriteToDocument(); |
| EndPaste(); |
| } |
| delete pImp; |
| return bOk; |
| } |
| |
| #define RETURN_ERROR { return eERR_INTERN; } |
| class ScFormatFilterMissing : public ScFormatFilterPlugin { |
| public: |
| ScFormatFilterMissing() |
| { |
| OSL_ASSERT ("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::createFromAscii( "ScFilterCreate" ) ); |
| if (fn != NULL) |
| plugin = reinterpret_cast<FilterFn>(fn)(); |
| } |
| if (plugin == NULL) |
| plugin = new ScFormatFilterMissing(); |
| |
| return *plugin; |
| } |