merge the formfield patch from ooo-build
[ooovba.git] / sc / source / ui / docshell / impex.cxx
blob8dc864664b4934f803dbdd1bf7484d1f99dc8e73
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impex.cxx,v $
10 * $Revision: 1.43 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // System - Includes -----------------------------------------------------
36 class StarBASIC;
40 #ifndef PCH
41 #include "sc.hrc"
42 #define GLOBALOVERFLOW
43 #endif
45 // INCLUDE ---------------------------------------------------------------
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <stdlib.h>
50 #include <osl/endian.h>
51 #include <i18npool/mslangid.hxx>
52 #include <tools/list.hxx>
53 #include <tools/string.hxx>
54 #include <rtl/math.hxx>
55 #include <svtools/htmlout.hxx>
56 #include <svtools/zforlist.hxx>
57 #define _SVSTDARR_ULONGS
58 #include <svtools/svstdarr.hxx>
59 #include <sot/formats.hxx>
60 #include <sfx2/mieclip.hxx>
61 #include <unotools/charclass.hxx>
62 #include <unotools/collatorwrapper.hxx>
63 #include <unotools/calendarwrapper.hxx>
64 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
65 #include <unotools/transliterationwrapper.hxx>
67 #include "global.hxx"
68 #include "scerrors.hxx"
69 #include "docsh.hxx"
70 #include "undoblk.hxx"
71 #include "rangenam.hxx"
72 #include "viewdata.hxx"
73 #include "tabvwsh.hxx"
74 #include "filter.hxx"
75 #include "asciiopt.hxx"
76 #include "cell.hxx"
77 #include "docoptio.hxx"
78 #include "progress.hxx"
79 #include "scitems.hxx"
80 #include "editable.hxx"
81 #include "compiler.hxx"
82 #include "warnbox.hxx"
84 #include "impex.hxx"
86 // ause
87 #include "editutil.hxx"
88 #include "patattr.hxx"
89 #include "docpool.hxx"
90 #include "stringutil.hxx"
92 #include "globstr.hrc"
93 #include <vcl/msgbox.hxx>
94 #include <vcl/svapp.hxx>
95 #include <osl/module.hxx>
97 //========================================================================
99 namespace
101 const String SYLK_LF = String::CreateFromAscii("\x1b :");
102 const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;");
103 const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\"");
106 enum SylkVersion
108 SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
109 SYLK_OOO32, // Correct strings, plus multiline content.
110 SYLK_OWN, // Place our new versions, if any, before this value.
111 SYLK_OTHER // Assume that aliens wrote correct strings.
115 // Gesamtdokument ohne Undo
118 ScImportExport::ScImportExport( ScDocument* p )
119 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
120 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
121 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
122 bAll( TRUE ), bSingle( TRUE ), bUndo( FALSE ),
123 bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
125 pUndoDoc = NULL;
126 pExtOptions = NULL;
129 // Insert am Punkt ohne Bereichschecks
132 ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
133 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
134 aRange( rPt ),
135 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
136 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
137 bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ),
138 bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
140 pUndoDoc = NULL;
141 pExtOptions = NULL;
145 // ctor with a range is only used for export
146 //! ctor with a string (and bSingle=TRUE) is also used for DdeSetData
148 ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
149 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
150 aRange( r ),
151 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
152 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
153 bAll( FALSE ), bSingle( FALSE ), bUndo( BOOL( pDocSh != NULL ) ),
154 bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
156 pUndoDoc = NULL;
157 pExtOptions = NULL;
158 // Zur Zeit nur in einer Tabelle!
159 aRange.aEnd.SetTab( aRange.aStart.Tab() );
162 // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
163 // Falls eine View existiert, wird die TabNo der View entnommen!
166 ScImportExport::ScImportExport( ScDocument* p, const String& rPos )
167 : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
168 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
169 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
170 bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ),
171 bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
173 pUndoDoc = NULL;
174 pExtOptions = NULL;
176 SCTAB nTab = ScDocShell::GetCurTab();
177 aRange.aStart.SetTab( nTab );
178 String aPos( rPos );
179 // Benannter Bereich?
180 ScRangeName* pRange = pDoc->GetRangeName();
181 if( pRange )
183 USHORT nPos;
184 if( pRange->SearchName( aPos, nPos ) )
186 ScRangeData* pData = (*pRange)[ nPos ];
187 if( pData->HasType( RT_REFAREA )
188 || pData->HasType( RT_ABSAREA )
189 || pData->HasType( RT_ABSPOS ) )
190 pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten
193 formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
194 // Bereich?
195 if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID )
196 bSingle = FALSE;
197 // Zelle?
198 else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID )
199 aRange.aEnd = aRange.aStart;
200 else
201 bAll = TRUE;
205 ScImportExport::~ScImportExport()
207 delete pUndoDoc;
208 delete pExtOptions;
212 void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
214 if ( pExtOptions )
215 *pExtOptions = rOpt;
216 else
217 pExtOptions = new ScAsciiOptions( rOpt );
219 // "normale" Optionen uebernehmen
221 cSep = rOpt.GetFieldSeps().GetChar(0);
222 cStr = rOpt.GetTextSep();
226 BOOL ScImportExport::IsFormatSupported( ULONG nFormat )
228 return BOOL( nFormat == FORMAT_STRING
229 || nFormat == SOT_FORMATSTR_ID_SYLK
230 || nFormat == SOT_FORMATSTR_ID_LINK
231 || nFormat == SOT_FORMATSTR_ID_HTML
232 || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE
233 || nFormat == SOT_FORMATSTR_ID_DIF );
237 //////////////////////////////////////////////////////////////////////////////
239 // Vorbereitung fuer Undo: Undo-Dokument erzeugen
242 BOOL ScImportExport::StartPaste()
244 if ( !bAll )
246 ScEditableTester aTester( pDoc, aRange );
247 if ( !aTester.IsEditable() )
249 InfoBox aInfoBox(Application::GetDefDialogParent(),
250 ScGlobal::GetRscString( aTester.GetMessageId() ) );
251 aInfoBox.Execute();
252 return FALSE;
255 if( bUndo && pDocSh && pDoc->IsUndoEnabled())
257 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
258 pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
259 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, FALSE, pUndoDoc );
261 return TRUE;
264 // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
267 void ScImportExport::EndPaste()
269 BOOL bHeight = pDocSh && pDocSh->AdjustRowHeight(
270 aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
272 if( pUndoDoc && pDoc->IsUndoEnabled() )
274 ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
275 pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
276 pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, FALSE, pRedoDoc );
277 ScMarkData aDestMark;
278 aDestMark.SelectOneTable( aRange.aStart.Tab() );
279 pDocSh->GetUndoManager()->AddUndoAction(
280 new ScUndoPaste( pDocSh,
281 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(),
282 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), aDestMark,
283 pUndoDoc, pRedoDoc, IDF_ALL, NULL,NULL,NULL,NULL ) );
285 pUndoDoc = NULL;
286 if( pDocSh )
288 if (!bHeight)
289 pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber
290 pDocSh->SetDocumentModified();
292 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
293 if ( pViewSh )
294 pViewSh->UpdateInputHandler();
298 /////////////////////////////////////////////////////////////////////////////
301 #if 0
302 BOOL ScImportExport::ImportData( SvData& rData )
304 ULONG nFmt = rData.GetFormat();
305 if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
307 MSE40HTMLClipFormatObj aMSE40ClpObj;
308 if ( aMSE40ClpObj.GetData( rData ) )
310 SvStream* pStream = aMSE40ClpObj.GetStream();
311 return ImportStream( *pStream, nFmt );
313 return FALSE;
315 else
317 void* pMem;
318 ULONG nSize = rData.GetMinMemorySize();
319 rData.GetData( &pMem, TRANSFER_REFERENCE );
320 if( nFmt == FORMAT_STRING
321 || nFmt == FORMAT_RTF
322 || nFmt == SOT_FORMATSTR_ID_SYLK
323 || nFmt == SOT_FORMATSTR_ID_HTML
324 || nFmt == SOT_FORMATSTR_ID_DIF )
326 //! String? Unicode??
328 // Stringende ermitteln!
329 sal_Char* pBegin = (sal_Char*) pMem;
330 sal_Char* pEnd = (sal_Char*) pMem + nSize;
332 nSize = 0;
333 while( pBegin != pEnd && *pBegin != '\0' )
334 pBegin++, nSize++;
335 // #72909# MT says only STRING has to be zero-terminated
336 DBG_ASSERT( pBegin != pEnd || nFmt != FORMAT_STRING, "non zero-terminated String" )
338 SvMemoryStream aStrm( pMem, nSize, STREAM_READ );
339 return ImportStream( aStrm, nFmt );
343 #endif
345 BOOL ScImportExport::ImportData( const String& /* rMimeType */,
346 const ::com::sun::star::uno::Any & /* rValue */ )
348 DBG_ASSERT( !this, "Implementation is missing" );
349 return FALSE;
352 BOOL ScImportExport::ExportData( const String& rMimeType,
353 ::com::sun::star::uno::Any & rValue )
355 SvMemoryStream aStrm;
356 // mba: no BaseURL for data exchange
357 if( ExportStream( aStrm, String(),
358 SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
360 aStrm << (BYTE) 0;
361 rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
362 (sal_Int8*)aStrm.GetData(),
363 aStrm.Seek( STREAM_SEEK_TO_END ) );
364 return TRUE;
366 return FALSE;
370 BOOL ScImportExport::ImportString( const ::rtl::OUString& rText, ULONG nFmt )
372 switch ( nFmt )
374 // formats supporting unicode
375 case FORMAT_STRING :
377 ScImportStringStream aStrm( rText);
378 return ImportStream( aStrm, String(), nFmt );
379 // ImportStream must handle RTL_TEXTENCODING_UNICODE
381 //break;
382 default:
384 rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
385 ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc );
386 SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ );
387 aStrm.SetStreamCharSet( eEnc );
388 SetNoEndianSwap( aStrm ); //! no swapping in memory
389 return ImportStream( aStrm, String(), nFmt );
395 BOOL ScImportExport::ExportString( ::rtl::OUString& rText, ULONG nFmt )
397 DBG_ASSERT( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
398 if ( nFmt != FORMAT_STRING )
400 rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
401 ByteString aTmp;
402 BOOL bOk = ExportByteString( aTmp, eEnc, nFmt );
403 rText = UniString( aTmp, eEnc );
404 return bOk;
406 // nSizeLimit not needed for OUString
408 SvMemoryStream aStrm;
409 aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
410 SetNoEndianSwap( aStrm ); //! no swapping in memory
411 // mba: no BaseURL for data exc
412 if( ExportStream( aStrm, String(), nFmt ) )
414 aStrm << (sal_Unicode) 0;
415 aStrm.Seek( STREAM_SEEK_TO_END );
417 rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() );
418 return TRUE;
420 rText = rtl::OUString();
421 return FALSE;
423 // ExportStream must handle RTL_TEXTENCODING_UNICODE
427 BOOL ScImportExport::ExportByteString( ByteString& rText, rtl_TextEncoding eEnc, ULONG nFmt )
429 DBG_ASSERT( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
430 if ( eEnc == RTL_TEXTENCODING_UNICODE )
431 eEnc = gsl_getSystemTextEncoding();
433 if (!nSizeLimit)
434 nSizeLimit = STRING_MAXLEN;
436 SvMemoryStream aStrm;
437 aStrm.SetStreamCharSet( eEnc );
438 SetNoEndianSwap( aStrm ); //! no swapping in memory
439 // mba: no BaseURL for data exchange
440 if( ExportStream( aStrm, String(), nFmt ) )
442 aStrm << (sal_Char) 0;
443 aStrm.Seek( STREAM_SEEK_TO_END );
444 // Sicherheits-Check:
445 if( aStrm.Tell() <= (ULONG) STRING_MAXLEN )
447 rText = (const sal_Char*) aStrm.GetData();
448 return TRUE;
451 rText.Erase();
452 return FALSE;
456 BOOL ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, ULONG nFmt )
458 if( nFmt == FORMAT_STRING )
460 if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten
461 return TRUE;
463 if( nFmt == SOT_FORMATSTR_ID_SYLK )
465 if( Sylk2Doc( rStrm ) )
466 return TRUE;
468 if( nFmt == SOT_FORMATSTR_ID_DIF )
470 if( Dif2Doc( rStrm ) )
471 return TRUE;
473 if( nFmt == FORMAT_RTF )
475 if( RTF2Doc( rStrm, rBaseURL ) )
476 return TRUE;
478 if( nFmt == SOT_FORMATSTR_ID_LINK )
479 return TRUE; // Link-Import?
480 if ( nFmt == SOT_FORMATSTR_ID_HTML )
482 if( HTML2Doc( rStrm, rBaseURL ) )
483 return TRUE;
485 if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
487 MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
488 SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
489 if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
490 return TRUE;
493 return FALSE;
497 BOOL ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, ULONG nFmt )
499 if( nFmt == FORMAT_STRING )
501 if( Doc2Text( rStrm ) )
502 return TRUE;
504 if( nFmt == SOT_FORMATSTR_ID_SYLK )
506 if( Doc2Sylk( rStrm ) )
507 return TRUE;
509 if( nFmt == SOT_FORMATSTR_ID_DIF )
511 if( Doc2Dif( rStrm ) )
512 return TRUE;
514 if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll )
516 String aDocName;
517 if ( pDoc->IsClipboard() )
518 aDocName = ScGlobal::GetClipDocName();
519 else
521 SfxObjectShell* pShell = pDoc->GetDocumentShell();
522 if (pShell)
523 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
526 DBG_ASSERT( aDocName.Len(), "ClipBoard document has no name! :-/" );
527 if( aDocName.Len() )
529 String aRefName;
530 USHORT nFlags = SCA_VALID | SCA_TAB_3D;
531 if( bSingle )
532 aRange.aStart.Format( aRefName, nFlags, pDoc, pDoc->GetAddressConvention() );
533 else
535 if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
536 nFlags |= SCA_TAB2_3D;
537 aRange.Format( aRefName, nFlags, pDoc );
539 String aAppName = Application::GetAppName();
541 WriteUnicodeOrByteString( rStrm, aAppName, TRUE );
542 WriteUnicodeOrByteString( rStrm, aDocName, TRUE );
543 WriteUnicodeOrByteString( rStrm, aRefName, TRUE );
544 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
545 rStrm << sal_Unicode(0);
546 else
547 rStrm << sal_Char(0);
548 return BOOL( rStrm.GetError() == SVSTREAM_OK );
551 if( nFmt == SOT_FORMATSTR_ID_HTML )
553 if( Doc2HTML( rStrm, rBaseURL ) )
554 return TRUE;
556 if( nFmt == FORMAT_RTF )
558 if( Doc2RTF( rStrm ) )
559 return TRUE;
562 return FALSE;
566 //static
567 void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, BOOL bZero )
569 rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
570 if ( eEnc == RTL_TEXTENCODING_UNICODE )
572 if ( !IsEndianSwap( rStrm ) )
573 rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) );
574 else
576 const sal_Unicode* p = rString.GetBuffer();
577 const sal_Unicode* const pStop = p + rString.Len();
578 while ( p < pStop )
580 rStrm << *p;
583 if ( bZero )
584 rStrm << sal_Unicode(0);
586 else
588 ByteString aByteStr( rString, eEnc );
589 rStrm << aByteStr.GetBuffer();
590 if ( bZero )
591 rStrm << sal_Char(0);
596 // This function could be replaced by endlub()
597 // static
598 void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
600 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
601 { // same as endl() but unicode
602 switch ( rStrm.GetLineDelimiter() )
604 case LINEEND_CR :
605 rStrm << sal_Unicode(_CR);
606 break;
607 case LINEEND_LF :
608 rStrm << sal_Unicode(_LF);
609 break;
610 default:
611 rStrm << sal_Unicode(_CR) << sal_Unicode(_LF);
614 else
615 endl( rStrm );
619 enum DoubledQuoteMode
621 DQM_KEEP, // both are taken
622 DQM_ESCAPE, // escaped quote, one is taken, one ignored
623 DQM_CONCAT, // first is end, next is start, both ignored => strings combined
624 DQM_SEPARATE // end one string and begin next
627 static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
628 sal_Unicode cStr, DoubledQuoteMode eMode )
630 p++; //! jump over opening quote
631 BOOL bCont;
634 bCont = FALSE;
635 const sal_Unicode* p0 = p;
636 for( ;; )
638 if( !*p )
639 break;
640 if( *p == cStr )
642 if ( *++p != cStr )
643 break;
644 // doubled quote char
645 switch ( eMode )
647 case DQM_KEEP :
648 p++; // both for us (not breaking for-loop)
649 break;
650 case DQM_ESCAPE :
651 p++; // one for us (breaking for-loop)
652 bCont = TRUE; // and more
653 break;
654 case DQM_CONCAT :
655 if ( p0+1 < p )
656 rString.Append( p0, sal::static_int_cast<xub_StrLen>( (p-1) - p0 ) ); // first part
657 p0 = ++p; // text of next part starts here
658 break;
659 case DQM_SEPARATE :
660 // positioned on next opening quote
661 break;
663 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
664 break;
666 else
667 p++;
669 if ( p0 < p )
670 rString.Append( p0, sal::static_int_cast<xub_StrLen>( ((*p || *(p-1) == cStr) ? p-1 : p) - p0 ) );
671 } while ( bCont );
672 return p;
675 void lcl_UnescapeSylk( String & rString, SylkVersion eVersion )
677 // Older versions didn't escape the semicolon.
678 // Older versions quoted the string and doubled embedded quotes, but not
679 // the semicolons, which was plain wrong.
680 if (eVersion >= SYLK_OOO32)
681 rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' );
682 else
683 rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' );
685 rString.SearchAndReplaceAll( SYLK_LF, _LF );
688 static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
689 String& rString, SylkVersion eVersion )
691 const sal_Unicode* pStartQuote = p;
692 const sal_Unicode* pEndQuote = 0;
693 while( *(++p) )
695 if( *p == '"' )
697 pEndQuote = p;
698 if (eVersion >= SYLK_OOO32)
700 if (*(p+1) == ';')
702 if (*(p+2) == ';')
704 p += 2; // escaped ';'
705 pEndQuote = 0;
707 else
708 break; // end field
711 else
713 if (*(p+1) == '"')
715 ++p; // escaped '"'
716 pEndQuote = 0;
718 else if (*(p+1) == ';')
719 break; // end field
723 if (!pEndQuote)
724 pEndQuote = p; // Take all data as string.
725 rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) );
726 lcl_UnescapeSylk( rString, eVersion);
727 return p;
730 static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
731 String& rString, SylkVersion eVersion )
733 const sal_Unicode* pStart = p;
734 if (eVersion >= SYLK_OOO32)
736 while (*p)
738 if (*p == ';')
740 if (*(p+1) == ';')
741 ++p; // escaped ';'
742 else
743 break; // end field
745 ++p;
747 rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
748 lcl_UnescapeSylk( rString, eVersion);
750 else
752 // Nasty. If in old versions the formula contained a semicolon, it was
753 // quoted and embedded quotes were doubled, but semicolons were not. If
754 // there was no semicolon, it could still contain quotes and doubled
755 // embedded quotes if it was something like ="a""b", which was saved as
756 // E"a""b" as is and has to be preserved, even if older versions
757 // couldn't even load it correctly. However, theoretically another
758 // field might follow and thus the line contain a semicolon again, such
759 // as ...;E"a""b";...
760 bool bQuoted = false;
761 if (*p == '"')
763 // May be a quoted expression or just a string constant expression
764 // with quotes.
765 while (*(++p))
767 if (*p == '"')
769 if (*(p+1) == '"')
770 ++p; // escaped '"'
771 else
772 break; // closing '"', had no ';' yet
774 else if (*p == ';')
776 bQuoted = true; // ';' within quoted expression
777 break;
780 p = pStart;
782 if (bQuoted)
783 p = lcl_ScanSylkString( p, rString, eVersion);
784 else
786 while (*p && *p != ';')
787 ++p;
788 rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
791 return p;
794 static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr )
796 xub_StrLen n = 0;
797 while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND )
799 rString.Insert( cStr, n );
800 n += 2;
804 static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc )
806 if (cEsc)
807 lcl_DoubleEscapeChar( rString, cEsc );
809 if (cQuote)
811 rString.Insert( cQuote, 0 );
812 rString.Append( cQuote );
815 ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
818 inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString )
820 ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
823 //////////////////////////////////////////////////////////////////////////////
826 BOOL ScImportExport::Text2Doc( SvStream& rStrm )
828 BOOL bOk = TRUE;
830 SCCOL nStartCol = aRange.aStart.Col();
831 SCROW nStartRow = aRange.aStart.Row();
832 SCCOL nEndCol = aRange.aEnd.Col();
833 SCROW nEndRow = aRange.aEnd.Row();
834 ULONG nOldPos = rStrm.Tell();
835 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
836 rStrm.StartReadingUnicodeText();
837 BOOL bData = BOOL( !bSingle );
838 if( !bSingle)
839 bOk = StartPaste();
841 while( bOk )
843 ByteString aByteLine;
844 String aLine, aCell;
845 SCROW nRow = nStartRow;
846 rStrm.Seek( nOldPos );
847 for( ;; )
849 rStrm.ReadUniOrByteStringLine( aLine );
850 if( rStrm.IsEof() )
851 break;
852 SCCOL nCol = nStartCol;
853 const sal_Unicode* p = aLine.GetBuffer();
854 while( *p )
856 aCell.Erase();
857 if( *p == cStr )
859 p = lcl_ScanString( p, aCell, cStr, DQM_KEEP );
860 while( *p && *p != cSep )
861 p++;
862 if( *p )
863 p++;
865 else
867 const sal_Unicode* q = p;
868 while( *p && *p != cSep )
869 p++;
870 aCell.Assign( q, sal::static_int_cast<xub_StrLen>( p - q ) );
871 if( *p )
872 p++;
874 if (ValidCol(nCol) && ValidRow(nRow) )
876 if( bSingle )
878 if (nCol>nEndCol) nEndCol = nCol;
879 if (nRow>nEndRow) nEndRow = nRow;
881 if( bData && nCol <= nEndCol && nRow <= nEndRow )
882 pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
884 else // zuviele Spalten/Zeilen
885 bOverflow = TRUE; // beim Import Warnung ausgeben
886 ++nCol;
888 ++nRow;
891 if( !bData )
893 aRange.aEnd.SetCol( nEndCol );
894 aRange.aEnd.SetRow( nEndRow );
895 bOk = StartPaste();
896 bData = TRUE;
898 else
899 break;
902 EndPaste();
903 return bOk;
907 // erweiterter Ascii-Import
911 static bool lcl_PutString(
912 ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, BYTE nColFormat,
913 SvNumberFormatter* pFormatter, bool bDetectNumFormat,
914 ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
915 ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
917 bool bMultiLine = false;
918 if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) )
919 return bMultiLine;
921 if ( nColFormat == SC_COL_TEXT )
923 double fDummy;
924 sal_uInt32 nIndex;
925 if (pFormatter->IsNumberFormat(rStr, nIndex, fDummy))
927 // Set the format of this cell to Text.
928 sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
929 ScPatternAttr aNewAttrs(pDoc->GetPool());
930 SfxItemSet& rSet = aNewAttrs.GetItemSet();
931 rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
932 pDoc->ApplyPattern(nCol, nRow, nTab, aNewAttrs);
935 pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) );
936 return bMultiLine;
939 if ( nColFormat == SC_COL_ENGLISH )
941 //! SetString mit Extra-Flag ???
943 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
944 sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
945 double fVal;
946 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
948 // Zahlformat wird nicht auf englisch gesetzt
949 pDoc->SetValue( nCol, nRow, nTab, fVal );
950 return bMultiLine;
952 // sonst weiter mit SetString
954 else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate
956 const USHORT nMaxNumberParts = 7; // Y-M-D h:m:s.t
957 xub_StrLen nLen = rStr.Len();
958 xub_StrLen nStart[nMaxNumberParts];
959 xub_StrLen nEnd[nMaxNumberParts];
961 USHORT nDP, nMP, nYP;
962 switch ( nColFormat )
964 case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
965 case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
966 case SC_COL_DMY:
967 default: nDP = 0; nMP = 1; nYP = 2; break;
970 USHORT nFound = 0;
971 BOOL bInNum = FALSE;
972 for ( xub_StrLen nPos=0; nPos<nLen && (bInNum ||
973 nFound<nMaxNumberParts); nPos++ )
975 if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
976 nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T')
977 bInNum = FALSE; // ISO-8601: YYYY-MM-DDThh:mm...
978 else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
979 && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
980 || ScGlobal::pCharClass->isDigit( rStr, nPos))
982 if (!bInNum)
984 bInNum = TRUE;
985 nStart[nFound] = nPos;
986 ++nFound;
988 nEnd[nFound-1] = nPos;
990 else
991 bInNum = FALSE;
994 if ( nFound == 1 )
996 // try to break one number (without separators) into date fields
998 xub_StrLen nDateStart = nStart[0];
999 xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart;
1001 if ( nDateLen >= 5 && nDateLen <= 8 &&
1002 ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) )
1004 // 6 digits: 2 each for day, month, year
1005 // 8 digits: 4 for year, 2 each for day and month
1006 // 5 or 7 digits: first field is shortened by 1
1008 BOOL bLongYear = ( nDateLen >= 7 );
1009 BOOL bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
1011 USHORT nFieldStart = nDateStart;
1012 for (USHORT nPos=0; nPos<3; nPos++)
1014 USHORT nFieldEnd = nFieldStart + 1; // default: 2 digits
1015 if ( bLongYear && nPos == nYP )
1016 nFieldEnd += 2; // 2 extra digits for long year
1017 if ( bShortFirst && nPos == 0 )
1018 --nFieldEnd; // first field shortened?
1020 nStart[nPos] = nFieldStart;
1021 nEnd[nPos] = nFieldEnd;
1022 nFieldStart = nFieldEnd + 1;
1024 nFound = 3;
1028 if ( nFound >= 3 )
1030 using namespace ::com::sun::star;
1031 BOOL bSecondCal = FALSE;
1032 USHORT nDay = (USHORT) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32();
1033 USHORT nYear = (USHORT) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32();
1034 String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1035 sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32();
1036 if (!nMonth)
1038 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
1039 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
1040 uno::Sequence< i18n::CalendarItem > xMonths;
1041 sal_Int32 i, nMonthCount;
1042 // first test all month names from local international
1043 xMonths = rCalendar.getMonths();
1044 nMonthCount = xMonths.getLength();
1045 for (i=0; i<nMonthCount && !nMonth; i++)
1047 if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
1048 rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
1049 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1050 else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
1051 xMonths[i].AbbrevName ) &&
1052 rTransliteration.isEqual( aMStr, aSepShortened ) )
1053 { // #102136# correct English abbreviation is SEPT,
1054 // but data mostly contains SEP only
1055 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1058 // if none found, then test english month names
1059 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
1061 xMonths = pSecondCalendar->getMonths();
1062 nMonthCount = xMonths.getLength();
1063 for (i=0; i<nMonthCount && !nMonth; i++)
1065 if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
1066 pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
1068 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1069 bSecondCal = TRUE;
1071 else if ( i == 8 && pSecondTransliteration->isEqual(
1072 aMStr, aSepShortened ) )
1073 { // #102136# correct English abbreviation is SEPT,
1074 // but data mostly contains SEP only
1075 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1076 bSecondCal = TRUE;
1082 SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1083 if ( nYear < 100 )
1084 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1086 CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1087 sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1088 if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
1090 --nMonth;
1091 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1092 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1093 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1094 sal_Int16 nHour, nMinute, nSecond, nMilli;
1095 // #i14974# The imported value should have no fractional value, so set the
1096 // time fields to zero (ICU calendar instance defaults to current date/time)
1097 nHour = nMinute = nSecond = nMilli = 0;
1098 if (nFound > 3)
1099 nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32();
1100 if (nFound > 4)
1101 nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32();
1102 if (nFound > 5)
1103 nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32();
1104 if (nFound > 6)
1106 sal_Unicode cDec = '.';
1107 rtl::OUString aT( &cDec, 1);
1108 aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]);
1109 rtl_math_ConversionStatus eStatus;
1110 double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
1111 if (eStatus == rtl_math_ConversionStatus_Ok)
1112 nMilli = (sal_Int16) (1000.0 * fV + 0.5);
1114 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1115 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1116 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1117 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
1118 if ( pCalendar->isValid() )
1120 double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
1121 pCalendar->getEpochStart();
1122 // #i14974# must use getLocalDateTime to get the same
1123 // date values as set above
1124 double fDays = pCalendar->getLocalDateTime();
1125 fDays -= fDiff;
1127 LanguageType eLatin, eCjk, eCtl;
1128 pDoc->GetLanguage( eLatin, eCjk, eCtl );
1129 LanguageType eDocLang = eLatin; //! which language for date formats?
1131 short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
1132 ULONG nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1133 // maybe there is a special format including seconds or milliseconds
1134 if (nFound > 5)
1135 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1137 pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, FALSE );
1139 return bMultiLine; // success
1145 // Standard or date not determined -> SetString / EditCell
1146 if( rStr.Search( _LF ) == STRING_NOTFOUND )
1148 ScSetStringParam aParam;
1149 aParam.mpNumFormatter = pFormatter;
1150 aParam.mbDetectNumberFormat = bDetectNumFormat;
1151 aParam.mbSetTextCellFormat = true;
1152 pDoc->SetString( nCol, nRow, nTab, rStr, &aParam );
1154 else
1156 bMultiLine = true;
1157 pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
1159 return bMultiLine;
1163 String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted )
1165 xub_StrLen nLen = rLine.Len();
1166 if (nNext > nLen)
1167 nNext = nLen;
1168 if ( nNext <= nStart )
1169 return EMPTY_STRING;
1171 const sal_Unicode* pStr = rLine.GetBuffer();
1173 xub_StrLen nSpace = nNext;
1174 while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
1175 --nSpace;
1177 rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"'));
1178 if (rbIsQuoted)
1179 return rLine.Copy(nStart+1, nSpace-nStart-2);
1180 else
1181 return rLine.Copy(nStart, nSpace-nStart);
1184 BOOL ScImportExport::ExtText2Doc( SvStream& rStrm )
1186 if (!pExtOptions)
1187 return Text2Doc( rStrm );
1189 ULONG nOldPos = rStrm.Tell();
1190 rStrm.Seek( STREAM_SEEK_TO_END );
1191 ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1192 ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
1193 rStrm.Seek( nOldPos );
1194 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
1195 rStrm.StartReadingUnicodeText();
1197 BOOL bOld = ScColumn::bDoubleAlloc;
1198 ScColumn::bDoubleAlloc = TRUE;
1200 SCCOL nStartCol = aRange.aStart.Col();
1201 SCCOL nEndCol = aRange.aEnd.Col();
1202 SCROW nStartRow = aRange.aStart.Row();
1203 SCTAB nTab = aRange.aStart.Tab();
1205 BOOL bFixed = pExtOptions->IsFixedLen();
1206 const String& rSeps = pExtOptions->GetFieldSeps();
1207 const sal_Unicode* pSeps = rSeps.GetBuffer();
1208 BOOL bMerge = pExtOptions->IsMergeSeps();
1209 USHORT nInfoCount = pExtOptions->GetInfoCount();
1210 const xub_StrLen* pColStart = pExtOptions->GetColStart();
1211 const BYTE* pColFormat = pExtOptions->GetColFormat();
1212 long nSkipLines = pExtOptions->GetStartRow();
1214 LanguageType eDocLang = pExtOptions->GetLanguage();
1215 SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang);
1216 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1218 // For date recognition
1219 ::utl::TransliterationWrapper aTransliteration(
1220 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1221 aTransliteration.loadModuleIfNeeded( eDocLang );
1222 CalendarWrapper aCalendar( pDoc->GetServiceManager() );
1223 aCalendar.loadDefaultCalendar(
1224 MsLangId::convertLanguageToLocale( eDocLang ) );
1225 ::utl::TransliterationWrapper* pEnglishTransliteration = NULL;
1226 CalendarWrapper* pEnglishCalendar = NULL;
1227 if ( eDocLang != LANGUAGE_ENGLISH_US )
1229 pEnglishTransliteration = new ::utl::TransliterationWrapper (
1230 pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1231 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1232 pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() );
1233 pEnglishCalendar->loadDefaultCalendar(
1234 MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) );
1237 String aLine, aCell;
1238 USHORT i;
1239 SCROW nRow = nStartRow;
1241 while(--nSkipLines>0)
1243 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored
1244 if ( rStrm.IsEof() )
1245 break;
1248 // Determine range for Undo.
1249 // TODO: we don't need this during import of a file to a new sheet or
1250 // document, could set bDetermineRange=false then.
1251 bool bDetermineRange = true;
1253 // Row heights don't need to be adjusted on the fly if EndPaste() is called
1254 // afterwards, which happens only if bDetermineRange. This variable also
1255 // survives the toggle of bDetermineRange down at the end of the do{} loop.
1256 bool bRangeIsDetermined = bDetermineRange;
1258 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1260 ULONG nOriginalStreamPos = rStrm.Tell();
1264 for( ;; )
1266 rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr);
1267 if ( rStrm.IsEof() )
1268 break;
1270 xub_StrLen nLineLen = aLine.Len();
1271 SCCOL nCol = nStartCol;
1272 bool bMultiLine = false;
1273 if ( bFixed ) // Feste Satzlaenge
1275 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1276 // overflow if there is really data following to be put behind
1277 // the last column, which doesn't happen if info is
1278 // SC_COL_SKIP.
1279 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
1281 BYTE nFmt = pColFormat[i];
1282 if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen
1284 if (nCol > MAXCOL)
1285 bOverflow = TRUE; // display warning on import
1286 else if (!bDetermineRange)
1288 xub_StrLen nStart = pColStart[i];
1289 xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
1290 bool bIsQuoted = false;
1291 aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted );
1292 if (bIsQuoted && bQuotedAsText)
1293 nFmt = SC_COL_TEXT;
1295 bMultiLine |= lcl_PutString(
1296 pDoc, nCol, nRow, nTab, aCell, nFmt,
1297 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1298 pEnglishTransliteration, pEnglishCalendar);
1300 ++nCol;
1304 else // Nach Trennzeichen suchen
1306 SCCOL nSourceCol = 0;
1307 USHORT nInfoStart = 0;
1308 const sal_Unicode* p = aLine.GetBuffer();
1309 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1310 // overflow if there is really data following to be put behind
1311 // the last column, which doesn't happen if info is
1312 // SC_COL_SKIP.
1313 while (*p && nCol <= MAXCOL+1)
1315 bool bIsQuoted = false;
1316 p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted );
1318 BYTE nFmt = SC_COL_STANDARD;
1319 for ( i=nInfoStart; i<nInfoCount; i++ )
1321 if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert
1323 nFmt = pColFormat[i];
1324 nInfoStart = i + 1; // ColInfos sind in Reihenfolge
1325 break; // for
1328 if ( nFmt != SC_COL_SKIP )
1330 if (nCol > MAXCOL)
1331 bOverflow = TRUE; // display warning on import
1332 else if (!bDetermineRange)
1334 if (bIsQuoted && bQuotedAsText)
1335 nFmt = SC_COL_TEXT;
1337 bMultiLine |= lcl_PutString(
1338 pDoc, nCol, nRow, nTab, aCell, nFmt,
1339 &aNumFormatter, bDetectNumFormat, aTransliteration,
1340 aCalendar, pEnglishTransliteration, pEnglishCalendar);
1342 ++nCol;
1345 ++nSourceCol;
1348 if (nEndCol < nCol)
1349 nEndCol = nCol; //! points to the next free or even MAXCOL+2
1351 if (!bDetermineRange)
1353 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1354 pDocSh->AdjustRowHeight( nRow, nRow, nTab);
1355 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1357 ++nRow;
1358 if ( nRow > MAXROW )
1360 bOverflow = TRUE; // display warning on import
1361 break; // for
1364 // so far nRow/nEndCol pointed to the next free
1365 if (nRow > nStartRow)
1366 --nRow;
1367 if (nEndCol > nStartCol)
1368 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
1370 if (bDetermineRange)
1372 aRange.aEnd.SetCol( nEndCol );
1373 aRange.aEnd.SetRow( nRow );
1375 if ( !mbApi && nStartCol != nEndCol &&
1376 !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
1378 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
1379 if ( aBox.Execute() != RET_YES )
1381 delete pEnglishTransliteration;
1382 delete pEnglishCalendar;
1383 return FALSE;
1387 rStrm.Seek( nOriginalStreamPos );
1388 nRow = nStartRow;
1389 if (!StartPaste())
1391 EndPaste();
1392 return FALSE;
1396 bDetermineRange = !bDetermineRange; // toggle
1397 } while (!bDetermineRange);
1399 ScColumn::bDoubleAlloc = bOld;
1400 pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
1402 delete pEnglishTransliteration;
1403 delete pEnglishCalendar;
1405 xProgress.reset(); // make room for AdjustRowHeight progress
1406 if (bRangeIsDetermined)
1407 EndPaste();
1409 return TRUE;
1413 // static
1414 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
1415 String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted )
1417 rbIsQuoted = false;
1418 rField.Erase();
1419 if ( *p == cStr ) // String in Anfuehrungszeichen
1421 rbIsQuoted = true;
1422 const sal_Unicode* p1;
1423 p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE );
1424 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1425 p++;
1426 // Append remaining unquoted and undelimited data (dirty, dirty) to
1427 // this field.
1428 if (p > p1)
1429 rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) );
1430 if( *p )
1431 p++;
1433 else // bis zum Trennzeichen
1435 const sal_Unicode* p0 = p;
1436 while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1437 p++;
1438 rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1439 if( *p )
1440 p++;
1442 if ( bMergeSeps ) // folgende Trennzeichen ueberspringen
1444 while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
1445 p++;
1447 return p;
1455 BOOL ScImportExport::Doc2Text( SvStream& rStrm )
1457 SCCOL nCol;
1458 SCROW nRow;
1459 SCCOL nStartCol = aRange.aStart.Col();
1460 SCROW nStartRow = aRange.aStart.Row();
1461 SCCOL nEndCol = aRange.aEnd.Col();
1462 SCROW nEndRow = aRange.aEnd.Row();
1463 String aCell;
1464 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1466 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1468 if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() ))
1470 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1472 CellType eType;
1473 pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType );
1474 switch (eType)
1476 case CELLTYPE_FORMULA:
1478 if (bFormulas)
1480 pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, TRUE );
1481 if( aCell.Search( cSep ) != STRING_NOTFOUND )
1482 lcl_WriteString( rStrm, aCell, cStr, cStr );
1483 else
1484 lcl_WriteSimpleString( rStrm, aCell );
1486 else
1488 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1490 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1491 if( bMultiLineText )
1493 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1494 aCell.SearchAndReplaceAll( _LF, ' ' );
1495 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1496 aCell.ConvertLineEnd();
1499 if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1500 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1502 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1503 lcl_WriteString( rStrm, aCell, cStr, cStr );
1504 else
1505 lcl_WriteSimpleString( rStrm, aCell );
1508 break;
1509 case CELLTYPE_VALUE:
1511 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1512 lcl_WriteSimpleString( rStrm, aCell );
1514 break;
1515 case CELLTYPE_NOTE:
1516 case CELLTYPE_NONE:
1517 break;
1518 default:
1520 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1522 bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1523 if( bMultiLineText )
1525 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1526 aCell.SearchAndReplaceAll( _LF, ' ' );
1527 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1528 aCell.ConvertLineEnd();
1531 if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1532 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1534 if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1535 lcl_WriteString( rStrm, aCell, cStr, cStr );
1536 else
1537 lcl_WriteSimpleString( rStrm, aCell );
1540 if( nCol < nEndCol )
1541 lcl_WriteSimpleString( rStrm, String(cSep) );
1543 // if( nRow < nEndRow )
1544 WriteUnicodeOrByteEndl( rStrm );
1545 if( rStrm.GetError() != SVSTREAM_OK )
1546 break;
1547 if( nSizeLimit && rStrm.Tell() > nSizeLimit )
1548 break;
1552 return BOOL( rStrm.GetError() == SVSTREAM_OK );
1556 BOOL ScImportExport::Sylk2Doc( SvStream& rStrm )
1558 BOOL bOk = TRUE;
1559 BOOL bMyDoc = FALSE;
1560 SylkVersion eVersion = SYLK_OTHER;
1562 // US-English separators for StringToDouble
1563 sal_Unicode cDecSep = '.';
1564 sal_Unicode cGrpSep = ',';
1566 SCCOL nStartCol = aRange.aStart.Col();
1567 SCROW nStartRow = aRange.aStart.Row();
1568 SCCOL nEndCol = aRange.aEnd.Col();
1569 SCROW nEndRow = aRange.aEnd.Row();
1570 ULONG nOldPos = rStrm.Tell();
1571 BOOL bData = BOOL( !bSingle );
1572 SvULongs aFormats;
1574 if( !bSingle)
1575 bOk = StartPaste();
1577 while( bOk )
1579 String aLine;
1580 String aText;
1581 ByteString aByteLine;
1582 SCCOL nCol = nStartCol;
1583 SCROW nRow = nStartRow;
1584 SCCOL nRefCol = 1;
1585 SCROW nRefRow = 1;
1586 rStrm.Seek( nOldPos );
1587 for( ;; )
1589 //! allow unicode
1590 rStrm.ReadLine( aByteLine );
1591 aLine = String( aByteLine, rStrm.GetStreamCharSet() );
1592 if( rStrm.IsEof() )
1593 break;
1594 const sal_Unicode* p = aLine.GetBuffer();
1595 sal_Unicode cTag = *p++;
1596 if( cTag == 'C' ) // Content
1598 if( *p++ != ';' )
1599 return FALSE;
1600 while( *p )
1602 sal_Unicode ch = *p++;
1603 ch = ScGlobal::ToUpperAlpha( ch );
1604 switch( ch )
1606 case 'X':
1607 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1608 break;
1609 case 'Y':
1610 nRow = String( p ).ToInt32() + nStartRow - 1;
1611 break;
1612 case 'C':
1613 nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1614 break;
1615 case 'R':
1616 nRefRow = String( p ).ToInt32() + nStartRow - 1;
1617 break;
1618 case 'K':
1620 if( !bSingle &&
1621 ( nCol < nStartCol || nCol > nEndCol
1622 || nRow < nStartRow || nRow > nEndRow
1623 || nCol > MAXCOL || nRow > MAXROW ) )
1624 break;
1625 if( !bData )
1627 if( nRow > nEndRow )
1628 nEndRow = nRow;
1629 if( nCol > nEndCol )
1630 nEndCol = nCol;
1631 break;
1633 BOOL bText;
1634 if( *p == '"' )
1636 bText = TRUE;
1637 aText.Erase();
1638 p = lcl_ScanSylkString( p, aText, eVersion);
1640 else
1641 bText = FALSE;
1642 const sal_Unicode* q = p;
1643 while( *q && *q != ';' )
1644 q++;
1645 if ( !(*q == ';' && *(q+1) == 'I') )
1646 { // don't ignore value
1647 if( bText )
1649 pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(),
1650 ScBaseCell::CreateTextCell( aText, pDoc),
1651 (BOOL) TRUE);
1653 else
1655 double fVal = rtl_math_uStringToDouble( p,
1656 aLine.GetBuffer() + aLine.Len(),
1657 cDecSep, cGrpSep, NULL, NULL );
1658 pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
1662 break;
1663 case 'E':
1664 case 'M':
1666 if ( ch == 'M' )
1668 if ( nRefCol < nCol )
1669 nRefCol = nCol;
1670 if ( nRefRow < nRow )
1671 nRefRow = nRow;
1672 if ( !bData )
1674 if( nRefRow > nEndRow )
1675 nEndRow = nRefRow;
1676 if( nRefCol > nEndCol )
1677 nEndCol = nRefCol;
1680 if( !bMyDoc || !bData )
1681 break;
1682 aText = '=';
1683 p = lcl_ScanSylkFormula( p, aText, eVersion);
1684 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
1685 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1686 * end it probably should be GRAM_ODFF_R1C1, since
1687 * R1C1 is what Excel writes in SYLK. */
1688 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
1689 ScCompiler aComp( pDoc, aPos);
1690 aComp.SetGrammar(eGrammar);
1691 ScTokenArray* pCode = aComp.CompileString( aText );
1692 if ( ch == 'M' )
1694 ScMarkData aMark;
1695 aMark.SelectTable( aPos.Tab(), TRUE );
1696 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1697 nRefRow, aMark, EMPTY_STRING, pCode );
1699 else
1701 ScFormulaCell* pFCell = new ScFormulaCell(
1702 pDoc, aPos, pCode, eGrammar, MM_NONE);
1703 pDoc->PutCell( aPos, pFCell );
1705 delete pCode; // ctor/InsertMatrixFormula did copy TokenArray
1707 break;
1709 while( *p && *p != ';' )
1710 p++;
1711 if( *p )
1712 p++;
1715 else if( cTag == 'F' ) // Format
1717 if( *p++ != ';' )
1718 return FALSE;
1719 sal_Int32 nFormat = -1;
1720 while( *p )
1722 sal_Unicode ch = *p++;
1723 ch = ScGlobal::ToUpperAlpha( ch );
1724 switch( ch )
1726 case 'X':
1727 nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1728 break;
1729 case 'Y':
1730 nRow = String( p ).ToInt32() + nStartRow - 1;
1731 break;
1732 case 'P' :
1733 if ( bData )
1735 // F;P<n> sets format code of P;P<code> at
1736 // current position, or at ;X;Y if specified.
1737 // Note that ;X;Y may appear after ;P
1738 const sal_Unicode* p0 = p;
1739 while( *p && *p != ';' )
1740 p++;
1741 String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1742 nFormat = aNumber.ToInt32();
1744 break;
1746 while( *p && *p != ';' )
1747 p++;
1748 if( *p )
1749 p++;
1751 if ( !bData )
1753 if( nRow > nEndRow )
1754 nEndRow = nRow;
1755 if( nCol > nEndCol )
1756 nEndCol = nCol;
1758 if ( 0 <= nFormat && nFormat < aFormats.Count() )
1760 ULONG nKey = aFormats[(USHORT)nFormat];
1761 pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
1762 SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
1765 else if( cTag == 'P' )
1767 if ( bData && *p == ';' && *(p+1) == 'P' )
1769 String aCode( p+2 );
1770 // unescape doubled semicolons
1771 xub_StrLen nPos = 0;
1772 String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;"));
1773 while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND )
1774 aCode.Erase( nPos++, 1 );
1775 // get rid of Xcl escape characters
1776 nPos = 0;
1777 while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND )
1778 aCode.Erase( nPos, 1 );
1779 xub_StrLen nCheckPos;
1780 short nType;
1781 sal_uInt32 nKey;
1782 pDoc->GetFormatTable()->PutandConvertEntry(
1783 aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US,
1784 ScGlobal::eLnge );
1785 if ( nCheckPos )
1786 nKey = 0;
1787 aFormats.Insert( nKey, aFormats.Count() );
1790 else if( cTag == 'I' && *p == 'D' )
1792 aLine.Erase( 0, 4 );
1793 if (aLine.EqualsAscii( "CALCOOO32" ))
1794 eVersion = SYLK_OOO32;
1795 else if (aLine.EqualsAscii( "SCALC3" ))
1796 eVersion = SYLK_SCALC3;
1797 bMyDoc = (eVersion <= SYLK_OWN);
1799 else if( cTag == 'E' ) // Ende
1800 break;
1802 if( !bData )
1804 aRange.aEnd.SetCol( nEndCol );
1805 aRange.aEnd.SetRow( nEndRow );
1806 bOk = StartPaste();
1807 bData = TRUE;
1809 else
1810 break;
1813 EndPaste();
1814 return bOk;
1818 BOOL ScImportExport::Doc2Sylk( SvStream& rStrm )
1820 SCCOL nCol;
1821 SCROW nRow;
1822 SCCOL nStartCol = aRange.aStart.Col();
1823 SCROW nStartRow = aRange.aStart.Row();
1824 SCCOL nEndCol = aRange.aEnd.Col();
1825 SCROW nEndRow = aRange.aEnd.Row();
1826 String aCellStr;
1827 String aValStr;
1828 lcl_WriteSimpleString( rStrm,
1829 String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
1830 WriteUnicodeOrByteEndl( rStrm );
1832 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1834 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1836 String aBufStr;
1837 double nVal;
1838 BOOL bForm = FALSE;
1839 SCROW r = nRow - nStartRow + 1;
1840 SCCOL c = nCol - nStartCol + 1;
1841 ScBaseCell* pCell;
1842 pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell );
1843 CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE);
1844 switch( eType )
1846 case CELLTYPE_FORMULA:
1847 bForm = bFormulas;
1848 if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1849 goto hasvalue;
1850 else
1851 goto hasstring;
1853 case CELLTYPE_VALUE:
1854 hasvalue:
1855 pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
1857 aValStr = ::rtl::math::doubleToUString( nVal,
1858 rtl_math_StringFormat_Automatic,
1859 rtl_math_DecimalPlaces_Max, '.', TRUE );
1861 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1862 aBufStr += String::CreateFromInt32( c );
1863 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1864 aBufStr += String::CreateFromInt32( r );
1865 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1866 aBufStr += aValStr;
1867 lcl_WriteSimpleString( rStrm, aBufStr );
1868 goto checkformula;
1870 case CELLTYPE_STRING:
1871 case CELLTYPE_EDIT:
1872 hasstring:
1873 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
1874 aCellStr.SearchAndReplaceAll( _LF, SYLK_LF );
1876 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1877 aBufStr += String::CreateFromInt32( c );
1878 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1879 aBufStr += String::CreateFromInt32( r );
1880 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1881 lcl_WriteSimpleString( rStrm, aBufStr );
1882 lcl_WriteString( rStrm, aCellStr, '"', ';' );
1884 checkformula:
1885 if( bForm )
1887 const ScFormulaCell* pFCell =
1888 static_cast<const ScFormulaCell*>(pCell);
1889 switch ( pFCell->GetMatrixFlag() )
1891 case MM_REFERENCE :
1892 aCellStr.Erase();
1893 break;
1894 default:
1895 pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
1896 /* FIXME: do we want GRAM_ODFF_A1 instead? At
1897 * the end it probably should be
1898 * GRAM_ODFF_R1C1, since R1C1 is what Excel
1899 * writes in SYLK. */
1901 if ( pFCell->GetMatrixFlag() != MM_NONE &&
1902 aCellStr.Len() > 2 &&
1903 aCellStr.GetChar(0) == '{' &&
1904 aCellStr.GetChar(aCellStr.Len()-1) == '}' )
1905 { // cut off matrix {} characters
1906 aCellStr.Erase(aCellStr.Len()-1,1);
1907 aCellStr.Erase(0,1);
1909 if ( aCellStr.GetChar(0) == '=' )
1910 aCellStr.Erase(0,1);
1911 String aPrefix;
1912 switch ( pFCell->GetMatrixFlag() )
1914 case MM_FORMULA :
1915 { // diff expression with 'M' M$-extension
1916 SCCOL nC;
1917 SCROW nR;
1918 pFCell->GetMatColsRows( nC, nR );
1919 nC += c - 1;
1920 nR += r - 1;
1921 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
1922 aPrefix += String::CreateFromInt32( nR );
1923 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1924 aPrefix += String::CreateFromInt32( nC );
1925 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
1927 break;
1928 case MM_REFERENCE :
1929 { // diff expression with 'I' M$-extension
1930 ScAddress aPos;
1931 pFCell->GetMatrixOrigin( aPos );
1932 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
1933 aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 );
1934 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1935 aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 );
1937 break;
1938 default:
1939 // formula Expression
1940 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
1942 lcl_WriteSimpleString( rStrm, aPrefix );
1943 if ( aCellStr.Len() )
1944 lcl_WriteString( rStrm, aCellStr, 0, ';' );
1946 WriteUnicodeOrByteEndl( rStrm );
1947 break;
1949 default:
1951 // added to avoid warnings
1956 lcl_WriteSimpleString( rStrm, String( 'E' ) );
1957 WriteUnicodeOrByteEndl( rStrm );
1958 return BOOL( rStrm.GetError() == SVSTREAM_OK );
1962 BOOL ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL )
1964 // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
1965 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
1966 aStreamPath, aNonConvertibleChars );
1967 return BOOL( rStrm.GetError() == SVSTREAM_OK );
1970 BOOL ScImportExport::Doc2RTF( SvStream& rStrm )
1972 // CharSet is ignored in ScExportRTF
1973 ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
1974 return BOOL( rStrm.GetError() == SVSTREAM_OK );
1978 BOOL ScImportExport::Doc2Dif( SvStream& rStrm )
1980 // for DIF in the clipboard, IBM_850 is always used
1981 ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
1982 return TRUE;
1986 BOOL ScImportExport::Dif2Doc( SvStream& rStrm )
1988 SCTAB nTab = aRange.aStart.Tab();
1989 ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
1990 pImportDoc->InitUndo( pDoc, nTab, nTab );
1992 // for DIF in the clipboard, IBM_850 is always used
1993 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
1995 SCCOL nEndCol;
1996 SCROW nEndRow;
1997 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
1998 // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start
1999 if ( nEndCol < aRange.aStart.Col() )
2000 nEndCol = aRange.aStart.Col();
2001 if ( nEndRow < aRange.aStart.Row() )
2002 nEndRow = aRange.aStart.Row();
2003 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
2005 BOOL bOk = StartPaste();
2006 if (bOk)
2008 USHORT nFlags = IDF_ALL & ~IDF_STYLES;
2009 pDoc->DeleteAreaTab( aRange, nFlags );
2010 pImportDoc->CopyToDocument( aRange, nFlags, FALSE, pDoc );
2011 EndPaste();
2014 delete pImportDoc;
2016 return bOk;
2020 BOOL ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL )
2022 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
2023 if (!pImp)
2024 return false;
2025 pImp->Read( rStrm, rBaseURL );
2026 aRange = pImp->GetRange();
2028 BOOL bOk = StartPaste();
2029 if (bOk)
2031 USHORT nFlags = IDF_ALL & ~IDF_STYLES;
2032 pDoc->DeleteAreaTab( aRange, nFlags );
2033 pImp->WriteToDocument();
2034 EndPaste();
2036 delete pImp;
2037 return bOk;
2041 BOOL ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL )
2043 ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, TRUE);
2044 if (!pImp)
2045 return false;
2046 pImp->Read( rStrm, rBaseURL );
2047 aRange = pImp->GetRange();
2049 BOOL bOk = StartPaste();
2050 if (bOk)
2052 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2053 // a Draw Layer but no Draw View -> create Draw Layer and View here
2054 if (pDocSh)
2055 pDocSh->MakeDrawLayer();
2057 USHORT nFlags = IDF_ALL & ~IDF_STYLES;
2058 pDoc->DeleteAreaTab( aRange, nFlags );
2059 pImp->WriteToDocument();
2060 EndPaste();
2062 delete pImp;
2063 return bOk;
2066 #define RETURN_ERROR { return eERR_INTERN; }
2067 class ScFormatFilterMissing : public ScFormatFilterPlugin {
2068 public:
2069 ScFormatFilterMissing()
2071 OSL_ASSERT ("Missing file filters");
2073 virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR
2074 virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
2075 virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
2076 virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
2077 virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
2078 const CharSet, UINT32 ) RETURN_ERROR
2079 virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR
2080 virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, BOOL, SvNumberFormatter*, bool ) RETURN_ERROR
2082 virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
2083 virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, BOOL ) { return NULL; }
2084 virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); }
2086 #if ENABLE_LOTUS123_EXPORT
2087 virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR
2088 #endif
2089 virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR
2090 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, UINT32 ) RETURN_ERROR
2091 virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, UINT32 ) RETURN_ERROR
2092 virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, BOOL,
2093 const String&, String& ) RETURN_ERROR
2094 virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR
2097 extern "C" { static void SAL_CALL thisModule() {} }
2098 typedef ScFormatFilterPlugin * (*FilterFn)(void);
2099 ScFormatFilterPlugin &ScFormatFilter::Get()
2101 static ScFormatFilterPlugin *plugin;
2103 if (plugin != NULL)
2104 return *plugin;
2106 static ::osl::Module aModule;
2107 if ( aModule.loadRelative( &thisModule,
2108 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) )
2110 oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) );
2111 if (fn != NULL)
2112 plugin = reinterpret_cast<FilterFn>(fn)();
2114 if (plugin == NULL)
2115 plugin = new ScFormatFilterMissing();
2117 return *plugin;