xref: /trunk/main/sc/source/ui/docshell/impex.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // System - Includes -----------------------------------------------------
32 
33 class StarBASIC;
34 
35 
36 
37 #ifndef PCH
38 #include "sc.hrc"
39 #define GLOBALOVERFLOW
40 #endif
41 
42 // INCLUDE ---------------------------------------------------------------
43 
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <osl/endian.h>
48 #include <i18npool/mslangid.hxx>
49 #include <tools/list.hxx>
50 #include <tools/string.hxx>
51 #include <rtl/math.hxx>
52 #include <svtools/htmlout.hxx>
53 #include <svl/zforlist.hxx>
54 #define _SVSTDARR_ULONGS
55 #include <svl/svstdarr.hxx>
56 #include <sot/formats.hxx>
57 #include <sfx2/mieclip.hxx>
58 #include <unotools/charclass.hxx>
59 #include <unotools/collatorwrapper.hxx>
60 #include <unotools/calendarwrapper.hxx>
61 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
62 #include <unotools/transliterationwrapper.hxx>
63 
64 #include "global.hxx"
65 #include "scerrors.hxx"
66 #include "docsh.hxx"
67 #include "undoblk.hxx"
68 #include "rangenam.hxx"
69 #include "viewdata.hxx"
70 #include "tabvwsh.hxx"
71 #include "filter.hxx"
72 #include "asciiopt.hxx"
73 #include "cell.hxx"
74 #include "docoptio.hxx"
75 #include "progress.hxx"
76 #include "scitems.hxx"
77 #include "editable.hxx"
78 #include "compiler.hxx"
79 #include "warnbox.hxx"
80 
81 #include "impex.hxx"
82 
83 // ause
84 #include "editutil.hxx"
85 
86 #include "globstr.hrc"
87 #include <vcl/msgbox.hxx>
88 #include <vcl/svapp.hxx>
89 #include <osl/module.hxx>
90 
91 //========================================================================
92 
93 namespace
94 {
95     const String SYLK_LF = String::CreateFromAscii("\x1b :");
96     const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;");
97     const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\"");
98 }
99 
100 enum SylkVersion
101 {
102     SYLK_SCALC3,    // Wrote wrongly quoted strings and unescaped semicolons.
103     SYLK_OOO32,     // Correct strings, plus multiline content.
104     SYLK_OWN,       // Place our new versions, if any, before this value.
105     SYLK_OTHER      // Assume that aliens wrote correct strings.
106 };
107 
108 
109 // Gesamtdokument ohne Undo
110 
111 
112 ScImportExport::ScImportExport( ScDocument* p )
113     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
114       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
115       bFormulas( sal_False ), bIncludeFiltered( sal_True ),
116       bAll( sal_True ), bSingle( sal_True ), bUndo( sal_False ),
117       bOverflow( sal_False ), mbApi( true ), mExportTextOptions()
118 {
119     pUndoDoc = NULL;
120     pExtOptions = NULL;
121 }
122 
123 // Insert am Punkt ohne Bereichschecks
124 
125 
126 ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
127     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
128       aRange( rPt ),
129       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
130       bFormulas( sal_False ), bIncludeFiltered( sal_True ),
131       bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ),
132       bOverflow( sal_False ), mbApi( true ), mExportTextOptions()
133 {
134     pUndoDoc = NULL;
135     pExtOptions = NULL;
136 }
137 
138 
139 //  ctor with a range is only used for export
140 //! ctor with a string (and bSingle=sal_True) is also used for DdeSetData
141 
142 ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
143     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
144       aRange( r ),
145       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
146       bFormulas( sal_False ), bIncludeFiltered( sal_True ),
147       bAll( sal_False ), bSingle( sal_False ), bUndo( sal_Bool( pDocSh != NULL ) ),
148       bOverflow( sal_False ), mbApi( true ), mExportTextOptions()
149 {
150     pUndoDoc = NULL;
151     pExtOptions = NULL;
152     // Zur Zeit nur in einer Tabelle!
153     aRange.aEnd.SetTab( aRange.aStart.Tab() );
154 }
155 
156 // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
157 // Falls eine View existiert, wird die TabNo der View entnommen!
158 
159 
160 ScImportExport::ScImportExport( ScDocument* p, const String& rPos )
161     : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
162       nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
163       bFormulas( sal_False ), bIncludeFiltered( sal_True ),
164       bAll( sal_False ), bSingle( sal_True ), bUndo( sal_Bool( pDocSh != NULL ) ),
165       bOverflow( sal_False ), mbApi( true ), mExportTextOptions()
166 {
167     pUndoDoc = NULL;
168     pExtOptions = NULL;
169 
170     SCTAB nTab = ScDocShell::GetCurTab();
171     aRange.aStart.SetTab( nTab );
172     String aPos( rPos );
173     //  Benannter Bereich?
174     ScRangeName* pRange = pDoc->GetRangeName();
175     if( pRange )
176     {
177         sal_uInt16 nPos;
178         if( pRange->SearchName( aPos, nPos ) )
179         {
180             ScRangeData* pData = (*pRange)[ nPos ];
181             if( pData->HasType( RT_REFAREA )
182                 || pData->HasType( RT_ABSAREA )
183                 || pData->HasType( RT_ABSPOS ) )
184                 pData->GetSymbol( aPos );                   // mit dem Inhalt weitertesten
185         }
186     }
187     formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
188     // Bereich?
189     if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID )
190         bSingle = sal_False;
191     // Zelle?
192     else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID )
193         aRange.aEnd = aRange.aStart;
194     else
195         bAll = sal_True;
196 }
197 
198 
199 ScImportExport::~ScImportExport()
200 {
201     delete pUndoDoc;
202     delete pExtOptions;
203 }
204 
205 
206 void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
207 {
208     if ( pExtOptions )
209         *pExtOptions = rOpt;
210     else
211         pExtOptions = new ScAsciiOptions( rOpt );
212 
213     //  "normale" Optionen uebernehmen
214 
215     cSep = rOpt.GetFieldSeps().GetChar(0);
216     cStr = rOpt.GetTextSep();
217 }
218 
219 
220 sal_Bool ScImportExport::IsFormatSupported( sal_uLong nFormat )
221 {
222     return sal_Bool( nFormat == FORMAT_STRING
223               || nFormat == SOT_FORMATSTR_ID_SYLK
224               || nFormat == SOT_FORMATSTR_ID_LINK
225               || nFormat == SOT_FORMATSTR_ID_HTML
226               || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE
227               || nFormat == SOT_FORMATSTR_ID_DIF );
228 }
229 
230 
231 //////////////////////////////////////////////////////////////////////////////
232 
233 // Vorbereitung fuer Undo: Undo-Dokument erzeugen
234 
235 
236 sal_Bool ScImportExport::StartPaste()
237 {
238     if ( !bAll )
239     {
240         ScEditableTester aTester( pDoc, aRange );
241         if ( !aTester.IsEditable() )
242         {
243             InfoBox aInfoBox(Application::GetDefDialogParent(),
244                                 ScGlobal::GetRscString( aTester.GetMessageId() ) );
245             aInfoBox.Execute();
246             return sal_False;
247         }
248     }
249     if( bUndo && pDocSh && pDoc->IsUndoEnabled())
250     {
251         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
252         pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
253         pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, sal_False, pUndoDoc );
254     }
255     return sal_True;
256 }
257 
258 // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
259 
260 
261 void ScImportExport::EndPaste()
262 {
263     sal_Bool bHeight = pDocSh && pDocSh->AdjustRowHeight(
264                     aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
265 
266     if( pUndoDoc && pDoc->IsUndoEnabled() )
267     {
268         ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
269         pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
270         pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, sal_False, pRedoDoc );
271         ScMarkData aDestMark;
272         aDestMark.SelectOneTable( aRange.aStart.Tab() );
273         pDocSh->GetUndoManager()->AddUndoAction(
274             new ScUndoPaste( pDocSh,
275                 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(),
276                 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), aDestMark,
277                 pUndoDoc, pRedoDoc, IDF_ALL, NULL,NULL,NULL,NULL ) );
278     }
279     pUndoDoc = NULL;
280     if( pDocSh )
281     {
282         if (!bHeight)
283             pDocSh->PostPaint( aRange, PAINT_GRID );    // AdjustRowHeight paintet evtl. selber
284         pDocSh->SetDocumentModified();
285     }
286     ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
287     if ( pViewSh )
288         pViewSh->UpdateInputHandler();
289 
290 }
291 
292 /////////////////////////////////////////////////////////////////////////////
293 
294 
295 #if 0
296 sal_Bool ScImportExport::ImportData( SvData& rData )
297 {
298     sal_uLong nFmt = rData.GetFormat();
299     if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
300     {
301         MSE40HTMLClipFormatObj aMSE40ClpObj;
302         if ( aMSE40ClpObj.GetData( rData ) )
303         {
304             SvStream* pStream = aMSE40ClpObj.GetStream();
305             return ImportStream( *pStream, nFmt );
306         }
307         return sal_False;
308     }
309     else
310     {
311         void* pMem;
312         sal_uLong nSize = rData.GetMinMemorySize();
313         rData.GetData( &pMem, TRANSFER_REFERENCE );
314         if( nFmt == FORMAT_STRING
315                 || nFmt == FORMAT_RTF
316                 || nFmt == SOT_FORMATSTR_ID_SYLK
317                 || nFmt == SOT_FORMATSTR_ID_HTML
318                 || nFmt == SOT_FORMATSTR_ID_DIF )
319         {
320             //! String? Unicode??
321 
322             // Stringende ermitteln!
323             sal_Char* pBegin = (sal_Char*) pMem;
324             sal_Char* pEnd   = (sal_Char*) pMem + nSize;
325 
326             nSize = 0;
327             while( pBegin != pEnd && *pBegin != '\0' )
328                 pBegin++, nSize++;
329             // #72909# MT says only STRING has to be zero-terminated
330             DBG_ASSERT( pBegin != pEnd || nFmt != FORMAT_STRING, "non zero-terminated String" )
331         }
332         SvMemoryStream aStrm( pMem, nSize, STREAM_READ );
333         return ImportStream( aStrm, nFmt );
334     }
335 }
336 
337 #endif
338 
339 sal_Bool ScImportExport::ImportData( const String& /* rMimeType */,
340                      const ::com::sun::star::uno::Any & /* rValue */ )
341 {
342     DBG_ASSERT( !this, "Implementation is missing" );
343     return sal_False;
344 }
345 
346 sal_Bool ScImportExport::ExportData( const String& rMimeType,
347                                  ::com::sun::star::uno::Any & rValue )
348 {
349     SvMemoryStream aStrm;
350     // mba: no BaseURL for data exchange
351     if( ExportStream( aStrm, String(),
352                 SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
353     {
354         aStrm << (sal_uInt8) 0;
355         rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
356                                         (sal_Int8*)aStrm.GetData(),
357                                         aStrm.Seek( STREAM_SEEK_TO_END ) );
358         return sal_True;
359     }
360     return sal_False;
361 }
362 
363 
364 sal_Bool ScImportExport::ImportString( const ::rtl::OUString& rText, sal_uLong nFmt )
365 {
366     switch ( nFmt )
367     {
368         // formats supporting unicode
369         case FORMAT_STRING :
370         {
371             ScImportStringStream aStrm( rText);
372             return ImportStream( aStrm, String(), nFmt );
373             // ImportStream must handle RTL_TEXTENCODING_UNICODE
374         }
375         //break;
376         default:
377         {
378             rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
379             ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc );
380             SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ );
381             aStrm.SetStreamCharSet( eEnc );
382             SetNoEndianSwap( aStrm );       //! no swapping in memory
383             return ImportStream( aStrm, String(), nFmt );
384         }
385     }
386 }
387 
388 
389 sal_Bool ScImportExport::ExportString( ::rtl::OUString& rText, sal_uLong nFmt )
390 {
391     DBG_ASSERT( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
392     if ( nFmt != FORMAT_STRING )
393     {
394         rtl_TextEncoding eEnc = gsl_getSystemTextEncoding();
395         ByteString aTmp;
396         sal_Bool bOk = ExportByteString( aTmp, eEnc, nFmt );
397         rText = UniString( aTmp, eEnc );
398         return bOk;
399     }
400     //  nSizeLimit not needed for OUString
401 
402     SvMemoryStream aStrm;
403     aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
404     SetNoEndianSwap( aStrm );       //! no swapping in memory
405     // mba: no BaseURL for data exc
406     if( ExportStream( aStrm, String(), nFmt ) )
407     {
408         aStrm << (sal_Unicode) 0;
409         aStrm.Seek( STREAM_SEEK_TO_END );
410 
411         rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() );
412         return sal_True;
413     }
414     rText = rtl::OUString();
415     return sal_False;
416 
417     // ExportStream must handle RTL_TEXTENCODING_UNICODE
418 }
419 
420 
421 sal_Bool ScImportExport::ExportByteString( ByteString& rText, rtl_TextEncoding eEnc, sal_uLong nFmt )
422 {
423     DBG_ASSERT( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
424     if ( eEnc == RTL_TEXTENCODING_UNICODE )
425         eEnc = gsl_getSystemTextEncoding();
426 
427     if (!nSizeLimit)
428         nSizeLimit = STRING_MAXLEN;
429 
430     SvMemoryStream aStrm;
431     aStrm.SetStreamCharSet( eEnc );
432     SetNoEndianSwap( aStrm );       //! no swapping in memory
433     // mba: no BaseURL for data exchange
434     if( ExportStream( aStrm, String(), nFmt ) )
435     {
436         aStrm << (sal_Char) 0;
437         aStrm.Seek( STREAM_SEEK_TO_END );
438         // Sicherheits-Check:
439         if( aStrm.Tell() <= (sal_uLong) STRING_MAXLEN )
440         {
441             rText = (const sal_Char*) aStrm.GetData();
442             return sal_True;
443         }
444     }
445     rText.Erase();
446     return sal_False;
447 }
448 
449 
450 sal_Bool ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
451 {
452     if( nFmt == FORMAT_STRING )
453     {
454         if( ExtText2Doc( rStrm ) )      // pExtOptions auswerten
455             return sal_True;
456     }
457     if( nFmt == SOT_FORMATSTR_ID_SYLK )
458     {
459         if( Sylk2Doc( rStrm ) )
460             return sal_True;
461     }
462     if( nFmt == SOT_FORMATSTR_ID_DIF )
463     {
464         if( Dif2Doc( rStrm ) )
465             return sal_True;
466     }
467     if( nFmt == FORMAT_RTF )
468     {
469         if( RTF2Doc( rStrm, rBaseURL ) )
470             return sal_True;
471     }
472     if( nFmt == SOT_FORMATSTR_ID_LINK )
473         return sal_True;            // Link-Import?
474     if ( nFmt == SOT_FORMATSTR_ID_HTML )
475     {
476         if( HTML2Doc( rStrm, rBaseURL ) )
477             return sal_True;
478     }
479     if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
480     {
481         MSE40HTMLClipFormatObj aMSE40ClpObj;                // needed to skip the header data
482         SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
483         if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
484             return sal_True;
485     }
486 
487     return sal_False;
488 }
489 
490 
491 sal_Bool ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
492 {
493     if( nFmt == FORMAT_STRING )
494     {
495         if( Doc2Text( rStrm ) )
496             return sal_True;
497     }
498     if( nFmt == SOT_FORMATSTR_ID_SYLK )
499     {
500         if( Doc2Sylk( rStrm ) )
501             return sal_True;
502     }
503     if( nFmt == SOT_FORMATSTR_ID_DIF )
504     {
505         if( Doc2Dif( rStrm ) )
506             return sal_True;
507     }
508     if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll )
509     {
510         String aDocName;
511         if ( pDoc->IsClipboard() )
512             aDocName = ScGlobal::GetClipDocName();
513         else
514         {
515             SfxObjectShell* pShell = pDoc->GetDocumentShell();
516             if (pShell)
517                 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
518         }
519 
520         DBG_ASSERT( aDocName.Len(), "ClipBoard document has no name! :-/" );
521         if( aDocName.Len() )
522         {
523             String aRefName;
524             sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
525             if( bSingle )
526                 aRange.aStart.Format( aRefName, nFlags, pDoc, pDoc->GetAddressConvention() );
527             else
528             {
529                 if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
530                     nFlags |= SCA_TAB2_3D;
531                 aRange.Format( aRefName, nFlags, pDoc );
532             }
533             String aAppName = Application::GetAppName();
534 
535             WriteUnicodeOrByteString( rStrm, aAppName, sal_True );
536             WriteUnicodeOrByteString( rStrm, aDocName, sal_True );
537             WriteUnicodeOrByteString( rStrm, aRefName, sal_True );
538             if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
539                 rStrm << sal_Unicode(0);
540             else
541                 rStrm << sal_Char(0);
542             return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
543         }
544     }
545     if( nFmt == SOT_FORMATSTR_ID_HTML )
546     {
547         if( Doc2HTML( rStrm, rBaseURL ) )
548             return sal_True;
549     }
550     if( nFmt == FORMAT_RTF )
551     {
552         if( Doc2RTF( rStrm ) )
553             return sal_True;
554     }
555 
556     return sal_False;
557 }
558 
559 
560 //static
561 void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, sal_Bool bZero )
562 {
563     rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
564     if ( eEnc == RTL_TEXTENCODING_UNICODE )
565     {
566         if ( !IsEndianSwap( rStrm ) )
567             rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) );
568         else
569         {
570             const sal_Unicode* p = rString.GetBuffer();
571             const sal_Unicode* const pStop = p + rString.Len();
572             while ( p < pStop )
573             {
574                 rStrm << *p;
575             }
576         }
577         if ( bZero )
578             rStrm << sal_Unicode(0);
579     }
580     else
581     {
582         ByteString aByteStr( rString, eEnc );
583         rStrm << aByteStr.GetBuffer();
584         if ( bZero )
585             rStrm << sal_Char(0);
586     }
587 }
588 
589 
590 // This function could be replaced by endlub()
591 // static
592 void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
593 {
594     if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
595     {   // same as endl() but unicode
596         switch ( rStrm.GetLineDelimiter() )
597         {
598             case LINEEND_CR :
599                 rStrm << sal_Unicode(_CR);
600             break;
601             case LINEEND_LF :
602                 rStrm << sal_Unicode(_LF);
603             break;
604             default:
605                 rStrm << sal_Unicode(_CR) << sal_Unicode(_LF);
606         }
607     }
608     else
609         endl( rStrm );
610 }
611 
612 
613 enum DoubledQuoteMode
614 {
615     DQM_KEEP,       // both are taken
616     DQM_ESCAPE,     // escaped quote, one is taken, one ignored
617     DQM_CONCAT,     // first is end, next is start, both ignored => strings combined
618     DQM_SEPARATE    // end one string and begin next
619 };
620 
621 static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
622             sal_Unicode cStr, DoubledQuoteMode eMode )
623 {
624     p++;    //! jump over opening quote
625     sal_Bool bCont;
626     do
627     {
628         bCont = sal_False;
629         const sal_Unicode* p0 = p;
630         for( ;; )
631         {
632             if( !*p )
633                 break;
634             if( *p == cStr )
635             {
636                 if ( *++p != cStr )
637                     break;
638                 // doubled quote char
639                 switch ( eMode )
640                 {
641                     case DQM_KEEP :
642                         p++;            // both for us (not breaking for-loop)
643                     break;
644                     case DQM_ESCAPE :
645                         p++;            // one for us (breaking for-loop)
646                         bCont = sal_True;   // and more
647                     break;
648                     case DQM_CONCAT :
649                         if ( p0+1 < p )
650                             rString.Append( p0, sal::static_int_cast<xub_StrLen>( (p-1) - p0 ) );  // first part
651                         p0 = ++p;       // text of next part starts here
652                     break;
653                     case DQM_SEPARATE :
654                                         // positioned on next opening quote
655                     break;
656                 }
657                 if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
658                     break;
659             }
660             else
661                 p++;
662         }
663         if ( p0 < p )
664             rString.Append( p0, sal::static_int_cast<xub_StrLen>( ((*p || *(p-1) == cStr) ? p-1 : p) - p0 ) );
665     } while ( bCont );
666     return p;
667 }
668 
669 void lcl_UnescapeSylk( String & rString, SylkVersion eVersion )
670 {
671     // Older versions didn't escape the semicolon.
672     // Older versions quoted the string and doubled embedded quotes, but not
673     // the semicolons, which was plain wrong.
674     if (eVersion >= SYLK_OOO32)
675         rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' );
676     else
677         rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' );
678 
679     rString.SearchAndReplaceAll( SYLK_LF, _LF );
680 }
681 
682 static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
683         String& rString, SylkVersion eVersion )
684 {
685     const sal_Unicode* pStartQuote = p;
686     const sal_Unicode* pEndQuote = 0;
687     while( *(++p) )
688     {
689         if( *p == '"' )
690         {
691             pEndQuote = p;
692             if (eVersion >= SYLK_OOO32)
693             {
694                 if (*(p+1) == ';')
695                 {
696                     if (*(p+2) == ';')
697                     {
698                         p += 2;     // escaped ';'
699                         pEndQuote = 0;
700                     }
701                     else
702                         break;      // end field
703                 }
704             }
705             else
706             {
707                 if (*(p+1) == '"')
708                 {
709                     ++p;            // escaped '"'
710                     pEndQuote = 0;
711                 }
712                 else if (*(p+1) == ';')
713                     break;          // end field
714             }
715         }
716     }
717     if (!pEndQuote)
718         pEndQuote = p;  // Take all data as string.
719     rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) );
720     lcl_UnescapeSylk( rString, eVersion);
721     return p;
722 }
723 
724 static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
725         String& rString, SylkVersion eVersion )
726 {
727     const sal_Unicode* pStart = p;
728     if (eVersion >= SYLK_OOO32)
729     {
730         while (*p)
731         {
732             if (*p == ';')
733             {
734                 if (*(p+1) == ';')
735                     ++p;        // escaped ';'
736                 else
737                     break;      // end field
738             }
739             ++p;
740         }
741         rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
742         lcl_UnescapeSylk( rString, eVersion);
743     }
744     else
745     {
746         // Nasty. If in old versions the formula contained a semicolon, it was
747         // quoted and embedded quotes were doubled, but semicolons were not. If
748         // there was no semicolon, it could still contain quotes and doubled
749         // embedded quotes if it was something like ="a""b", which was saved as
750         // E"a""b" as is and has to be preserved, even if older versions
751         // couldn't even load it correctly. However, theoretically another
752         // field might follow and thus the line contain a semicolon again, such
753         // as ...;E"a""b";...
754         bool bQuoted = false;
755         if (*p == '"')
756         {
757             // May be a quoted expression or just a string constant expression
758             // with quotes.
759             while (*(++p))
760             {
761                 if (*p == '"')
762                 {
763                     if (*(p+1) == '"')
764                         ++p;            // escaped '"'
765                     else
766                         break;          // closing '"', had no ';' yet
767                 }
768                 else if (*p == ';')
769                 {
770                     bQuoted = true;     // ';' within quoted expression
771                     break;
772                 }
773             }
774             p = pStart;
775         }
776         if (bQuoted)
777             p = lcl_ScanSylkString( p, rString, eVersion);
778         else
779         {
780             while (*p && *p != ';')
781                 ++p;
782             rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
783         }
784     }
785     return p;
786 }
787 
788 static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr )
789 {
790     xub_StrLen n = 0;
791     while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND )
792     {
793         rString.Insert( cStr, n );
794         n += 2;
795     }
796 }
797 
798 static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc )
799 {
800     if (cEsc)
801         lcl_DoubleEscapeChar( rString, cEsc );
802 
803     if (cQuote)
804     {
805         rString.Insert( cQuote, 0 );
806         rString.Append( cQuote );
807     }
808 
809     ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
810 }
811 
812 inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString )
813 {
814     ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
815 }
816 
817 //////////////////////////////////////////////////////////////////////////////
818 
819 
820 sal_Bool ScImportExport::Text2Doc( SvStream& rStrm )
821 {
822     sal_Bool bOk = sal_True;
823 
824     SCCOL nStartCol = aRange.aStart.Col();
825     SCROW nStartRow = aRange.aStart.Row();
826     SCCOL nEndCol = aRange.aEnd.Col();
827     SCROW nEndRow = aRange.aEnd.Row();
828     sal_uLong  nOldPos = rStrm.Tell();
829     rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
830     sal_Bool   bData = sal_Bool( !bSingle );
831     if( !bSingle)
832         bOk = StartPaste();
833 
834     while( bOk )
835     {
836         ByteString aByteLine;
837         String aLine, aCell;
838         SCROW nRow = nStartRow;
839         rStrm.Seek( nOldPos );
840         for( ;; )
841         {
842             rStrm.ReadUniOrByteStringLine( aLine );
843             if( rStrm.IsEof() )
844                 break;
845             SCCOL nCol = nStartCol;
846             const sal_Unicode* p = aLine.GetBuffer();
847             while( *p )
848             {
849                 aCell.Erase();
850                 if( *p == cStr )
851                 {
852                     p = lcl_ScanString( p, aCell, cStr, DQM_KEEP );
853                     while( *p && *p != cSep )
854                         p++;
855                     if( *p )
856                         p++;
857                 }
858                 else
859                 {
860                     const sal_Unicode* q = p;
861                     while( *p && *p != cSep )
862                         p++;
863                     aCell.Assign( q, sal::static_int_cast<xub_StrLen>( p - q ) );
864                     if( *p )
865                         p++;
866                 }
867                 if (ValidCol(nCol) && ValidRow(nRow) )
868                 {
869                     if( bSingle )
870                     {
871                         if (nCol>nEndCol) nEndCol = nCol;
872                         if (nRow>nEndRow) nEndRow = nRow;
873                     }
874                     if( bData && nCol <= nEndCol && nRow <= nEndRow )
875                         pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
876                 }
877                 else                            // zuviele Spalten/Zeilen
878                     bOverflow = sal_True;           // beim Import Warnung ausgeben
879                 ++nCol;
880             }
881             ++nRow;
882         }
883 
884         if( !bData )
885         {
886             aRange.aEnd.SetCol( nEndCol );
887             aRange.aEnd.SetRow( nEndRow );
888             bOk = StartPaste();
889             bData = sal_True;
890         }
891         else
892             break;
893     }
894 
895     EndPaste();
896     return bOk;
897 }
898 
899         //
900         //  erweiterter Ascii-Import
901         //
902 
903 
904 static bool lcl_PutString(
905     ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat,
906     SvNumberFormatter* pFormatter, bool bDetectNumFormat,
907     ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
908     ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
909 {
910     bool bMultiLine = false;
911     if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) )
912         return bMultiLine;
913 
914     if ( nColFormat == SC_COL_TEXT )
915     {
916         pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) );
917         return bMultiLine;
918     }
919 
920     if ( nColFormat == SC_COL_ENGLISH )
921     {
922         //! SetString mit Extra-Flag ???
923 
924         SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
925         sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
926         double fVal;
927         if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
928         {
929             //  Zahlformat wird nicht auf englisch gesetzt
930             pDoc->SetValue( nCol, nRow, nTab, fVal );
931             return bMultiLine;
932         }
933         //  sonst weiter mit SetString
934     }
935     else if ( nColFormat != SC_COL_STANDARD )                   // Datumsformate
936     {
937         const sal_uInt16 nMaxNumberParts = 7;   // Y-M-D h:m:s.t
938         xub_StrLen nLen = rStr.Len();
939         xub_StrLen nStart[nMaxNumberParts];
940         xub_StrLen nEnd[nMaxNumberParts];
941 
942         sal_uInt16 nDP, nMP, nYP;
943         switch ( nColFormat )
944         {
945             case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
946             case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
947             case SC_COL_DMY:
948             default:         nDP = 0; nMP = 1; nYP = 2; break;
949         }
950 
951         sal_uInt16 nFound = 0;
952         sal_Bool bInNum = sal_False;
953         for ( xub_StrLen nPos=0; nPos<nLen && (bInNum ||
954                     nFound<nMaxNumberParts); nPos++ )
955         {
956             if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
957                     nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T')
958                 bInNum = sal_False;     // ISO-8601: YYYY-MM-DDThh:mm...
959             else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
960                         && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
961                     || ScGlobal::pCharClass->isDigit( rStr, nPos))
962             {
963                 if (!bInNum)
964                 {
965                     bInNum = sal_True;
966                     nStart[nFound] = nPos;
967                     ++nFound;
968                 }
969                 nEnd[nFound-1] = nPos;
970             }
971             else
972                 bInNum = sal_False;
973         }
974 
975         if ( nFound == 1 )
976         {
977             //  try to break one number (without separators) into date fields
978 
979             xub_StrLen nDateStart = nStart[0];
980             xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart;
981 
982             if ( nDateLen >= 5 && nDateLen <= 8 &&
983                     ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) )
984             {
985                 //  6 digits: 2 each for day, month, year
986                 //  8 digits: 4 for year, 2 each for day and month
987                 //  5 or 7 digits: first field is shortened by 1
988 
989                 sal_Bool bLongYear = ( nDateLen >= 7 );
990                 sal_Bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
991 
992                 sal_uInt16 nFieldStart = nDateStart;
993                 for (sal_uInt16 nPos=0; nPos<3; nPos++)
994                 {
995                     sal_uInt16 nFieldEnd = nFieldStart + 1;     // default: 2 digits
996                     if ( bLongYear && nPos == nYP )
997                         nFieldEnd += 2;                     // 2 extra digits for long year
998                     if ( bShortFirst && nPos == 0 )
999                         --nFieldEnd;                        // first field shortened?
1000 
1001                     nStart[nPos] = nFieldStart;
1002                     nEnd[nPos]   = nFieldEnd;
1003                     nFieldStart  = nFieldEnd + 1;
1004                 }
1005                 nFound = 3;
1006             }
1007         }
1008 
1009         if ( nFound >= 3 )
1010         {
1011             using namespace ::com::sun::star;
1012             sal_Bool bSecondCal = sal_False;
1013             sal_uInt16 nDay  = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32();
1014             sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32();
1015             String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1016             sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32();
1017             if (!nMonth)
1018             {
1019                 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
1020                 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
1021                 uno::Sequence< i18n::CalendarItem > xMonths;
1022                 sal_Int32 i, nMonthCount;
1023                 //  first test all month names from local international
1024                 xMonths = rCalendar.getMonths();
1025                 nMonthCount = xMonths.getLength();
1026                 for (i=0; i<nMonthCount && !nMonth; i++)
1027                 {
1028                     if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
1029                          rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
1030                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1031                     else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
1032                                 xMonths[i].AbbrevName ) &&
1033                             rTransliteration.isEqual( aMStr, aSepShortened ) )
1034                     {   // #102136# correct English abbreviation is SEPT,
1035                         // but data mostly contains SEP only
1036                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1037                     }
1038                 }
1039                 //  if none found, then test english month names
1040                 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
1041                 {
1042                     xMonths = pSecondCalendar->getMonths();
1043                     nMonthCount = xMonths.getLength();
1044                     for (i=0; i<nMonthCount && !nMonth; i++)
1045                     {
1046                         if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
1047                              pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
1048                         {
1049                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1050                             bSecondCal = sal_True;
1051                         }
1052                         else if ( i == 8 && pSecondTransliteration->isEqual(
1053                                     aMStr, aSepShortened ) )
1054                         {   // #102136# correct English abbreviation is SEPT,
1055                             // but data mostly contains SEP only
1056                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1057                             bSecondCal = sal_True;
1058                         }
1059                     }
1060                 }
1061             }
1062 
1063             SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1064             if ( nYear < 100 )
1065                 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1066 
1067             CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1068             sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1069             if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
1070             {
1071                 --nMonth;
1072                 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1073                 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1074                 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1075                 sal_Int16 nHour, nMinute, nSecond, nMilli;
1076                 // #i14974# The imported value should have no fractional value, so set the
1077                 // time fields to zero (ICU calendar instance defaults to current date/time)
1078                 nHour = nMinute = nSecond = nMilli = 0;
1079                 if (nFound > 3)
1080                     nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32();
1081                 if (nFound > 4)
1082                     nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32();
1083                 if (nFound > 5)
1084                     nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32();
1085                 if (nFound > 6)
1086                 {
1087                     sal_Unicode cDec = '.';
1088                     rtl::OUString aT( &cDec, 1);
1089                     aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]);
1090                     rtl_math_ConversionStatus eStatus;
1091                     double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
1092                     if (eStatus == rtl_math_ConversionStatus_Ok)
1093                         nMilli = (sal_Int16) (1000.0 * fV + 0.5);
1094                 }
1095                 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1096                 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1097                 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1098                 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
1099                 if ( pCalendar->isValid() )
1100                 {
1101                     double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
1102                         pCalendar->getEpochStart();
1103                     // #i14974# must use getLocalDateTime to get the same
1104                     // date values as set above
1105                     double fDays = pCalendar->getLocalDateTime();
1106                     fDays -= fDiff;
1107 
1108                     LanguageType eLatin, eCjk, eCtl;
1109                     pDoc->GetLanguage( eLatin, eCjk, eCtl );
1110                     LanguageType eDocLang = eLatin;     //! which language for date formats?
1111 
1112                     short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
1113                     sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1114                     // maybe there is a special format including seconds or milliseconds
1115                     if (nFound > 5)
1116                         nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1117 
1118                     pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, sal_False );
1119 
1120                     return bMultiLine;     // success
1121                 }
1122             }
1123         }
1124     }
1125 
1126     // Standard or date not determined -> SetString / EditCell
1127     if( rStr.Search( _LF ) == STRING_NOTFOUND )
1128         pDoc->SetString( nCol, nRow, nTab, rStr, pFormatter, bDetectNumFormat );
1129     else
1130     {
1131         bMultiLine = true;
1132         pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
1133     }
1134     return bMultiLine;
1135 }
1136 
1137 
1138 String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted )
1139 {
1140     xub_StrLen nLen = rLine.Len();
1141     if (nNext > nLen)
1142         nNext = nLen;
1143     if ( nNext <= nStart )
1144         return EMPTY_STRING;
1145 
1146     const sal_Unicode* pStr = rLine.GetBuffer();
1147 
1148     xub_StrLen nSpace = nNext;
1149     while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
1150         --nSpace;
1151 
1152     rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"'));
1153     if (rbIsQuoted)
1154         return rLine.Copy(nStart+1, nSpace-nStart-2);
1155     else
1156         return rLine.Copy(nStart, nSpace-nStart);
1157 }
1158 
1159 sal_Bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1160 {
1161     if (!pExtOptions)
1162         return Text2Doc( rStrm );
1163 
1164     sal_uLong nOldPos = rStrm.Tell();
1165     rStrm.Seek( STREAM_SEEK_TO_END );
1166     ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1167             ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
1168     rStrm.Seek( nOldPos );
1169     rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
1170 
1171     sal_Bool bOld = ScColumn::bDoubleAlloc;
1172     ScColumn::bDoubleAlloc = sal_True;
1173 
1174     SCCOL nStartCol = aRange.aStart.Col();
1175     SCCOL nEndCol = aRange.aEnd.Col();
1176     SCROW nStartRow = aRange.aStart.Row();
1177     SCTAB nTab = aRange.aStart.Tab();
1178 
1179     sal_Bool    bFixed          = pExtOptions->IsFixedLen();
1180     const String& rSeps     = pExtOptions->GetFieldSeps();
1181     const sal_Unicode* pSeps = rSeps.GetBuffer();
1182     sal_Bool    bMerge          = pExtOptions->IsMergeSeps();
1183     sal_uInt16  nInfoCount      = pExtOptions->GetInfoCount();
1184     const xub_StrLen* pColStart = pExtOptions->GetColStart();
1185     const sal_uInt8* pColFormat  = pExtOptions->GetColFormat();
1186     long nSkipLines = pExtOptions->GetStartRow();
1187 
1188     LanguageType eDocLang = pExtOptions->GetLanguage();
1189     SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang);
1190     bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1191 
1192     // For date recognition
1193     ::utl::TransliterationWrapper aTransliteration(
1194         pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1195     aTransliteration.loadModuleIfNeeded( eDocLang );
1196     CalendarWrapper aCalendar( pDoc->GetServiceManager() );
1197     aCalendar.loadDefaultCalendar(
1198         MsLangId::convertLanguageToLocale( eDocLang ) );
1199     ::utl::TransliterationWrapper* pEnglishTransliteration = NULL;
1200     CalendarWrapper* pEnglishCalendar = NULL;
1201     if ( eDocLang != LANGUAGE_ENGLISH_US )
1202     {
1203         pEnglishTransliteration = new ::utl::TransliterationWrapper (
1204             pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1205         aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1206         pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() );
1207         pEnglishCalendar->loadDefaultCalendar(
1208             MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) );
1209     }
1210 
1211     String aLine, aCell;
1212     sal_uInt16 i;
1213     SCROW nRow = nStartRow;
1214 
1215     while(--nSkipLines>0)
1216     {
1217         rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored
1218         if ( rStrm.IsEof() )
1219             break;
1220     }
1221 
1222     // Determine range for Undo.
1223     // TODO: we don't need this during import of a file to a new sheet or
1224     // document, could set bDetermineRange=false then.
1225     bool bDetermineRange = true;
1226 
1227     // Row heights don't need to be adjusted on the fly if EndPaste() is called
1228     // afterwards, which happens only if bDetermineRange. This variable also
1229     // survives the toggle of bDetermineRange down at the end of the do{} loop.
1230     bool bRangeIsDetermined = bDetermineRange;
1231 
1232     bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1233 
1234     sal_uLong nOriginalStreamPos = rStrm.Tell();
1235 
1236     do
1237     {
1238         for( ;; )
1239         {
1240             rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr);
1241             if ( rStrm.IsEof() )
1242                 break;
1243 
1244             xub_StrLen nLineLen = aLine.Len();
1245             SCCOL nCol = nStartCol;
1246             bool bMultiLine = false;
1247             if ( bFixed )               //  Feste Satzlaenge
1248             {
1249                 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1250                 // overflow if there is really data following to be put behind
1251                 // the last column, which doesn't happen if info is
1252                 // SC_COL_SKIP.
1253                 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
1254                 {
1255                     sal_uInt8 nFmt = pColFormat[i];
1256                     if (nFmt != SC_COL_SKIP)        // sonst auch nCol nicht hochzaehlen
1257                     {
1258                         if (nCol > MAXCOL)
1259                             bOverflow = sal_True;       // display warning on import
1260                         else if (!bDetermineRange)
1261                         {
1262                             xub_StrLen nStart = pColStart[i];
1263                             xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
1264                             bool bIsQuoted = false;
1265                             aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted );
1266                             if (bIsQuoted && bQuotedAsText)
1267                                 nFmt = SC_COL_TEXT;
1268 
1269                             bMultiLine |= lcl_PutString(
1270                                 pDoc, nCol, nRow, nTab, aCell, nFmt,
1271                                 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1272                                 pEnglishTransliteration, pEnglishCalendar);
1273                         }
1274                         ++nCol;
1275                     }
1276                 }
1277             }
1278             else                        //  Nach Trennzeichen suchen
1279             {
1280                 SCCOL nSourceCol = 0;
1281                 sal_uInt16 nInfoStart = 0;
1282                 const sal_Unicode* p = aLine.GetBuffer();
1283                 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1284                 // overflow if there is really data following to be put behind
1285                 // the last column, which doesn't happen if info is
1286                 // SC_COL_SKIP.
1287                 while (*p && nCol <= MAXCOL+1)
1288                 {
1289                     bool bIsQuoted = false;
1290                     p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted );
1291 
1292                     sal_uInt8 nFmt = SC_COL_STANDARD;
1293                     for ( i=nInfoStart; i<nInfoCount; i++ )
1294                     {
1295                         if ( pColStart[i] == nSourceCol + 1 )       // pColStart ist 1-basiert
1296                         {
1297                             nFmt = pColFormat[i];
1298                             nInfoStart = i + 1;     // ColInfos sind in Reihenfolge
1299                             break;  // for
1300                         }
1301                     }
1302                     if ( nFmt != SC_COL_SKIP )
1303                     {
1304                         if (nCol > MAXCOL)
1305                             bOverflow = sal_True;       // display warning on import
1306                         else if (!bDetermineRange)
1307                         {
1308                             if (bIsQuoted && bQuotedAsText)
1309                                 nFmt = SC_COL_TEXT;
1310 
1311                             bMultiLine |= lcl_PutString(
1312                                 pDoc, nCol, nRow, nTab, aCell, nFmt,
1313                                 &aNumFormatter, bDetectNumFormat, aTransliteration,
1314                                 aCalendar, pEnglishTransliteration, pEnglishCalendar);
1315                         }
1316                         ++nCol;
1317                     }
1318 
1319                     ++nSourceCol;
1320                 }
1321             }
1322             if (nEndCol < nCol)
1323                 nEndCol = nCol;     //! points to the next free or even MAXCOL+2
1324 
1325             if (!bDetermineRange)
1326             {
1327                 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1328                     pDocSh->AdjustRowHeight( nRow, nRow, nTab);
1329                 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1330             }
1331             ++nRow;
1332             if ( nRow > MAXROW )
1333             {
1334                 bOverflow = sal_True;       // display warning on import
1335                 break;  // for
1336             }
1337         }
1338         // so far nRow/nEndCol pointed to the next free
1339         if (nRow > nStartRow)
1340             --nRow;
1341         if (nEndCol > nStartCol)
1342             nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
1343 
1344         if (bDetermineRange)
1345         {
1346             aRange.aEnd.SetCol( nEndCol );
1347             aRange.aEnd.SetRow( nRow );
1348 
1349             if ( !mbApi && nStartCol != nEndCol &&
1350                  !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
1351             {
1352                 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
1353                 if ( aBox.Execute() != RET_YES )
1354                 {
1355                     delete pEnglishTransliteration;
1356                     delete pEnglishCalendar;
1357                     return sal_False;
1358                 }
1359             }
1360 
1361             rStrm.Seek( nOriginalStreamPos );
1362             nRow = nStartRow;
1363             if (!StartPaste())
1364             {
1365                 EndPaste();
1366                 return sal_False;
1367             }
1368         }
1369 
1370         bDetermineRange = !bDetermineRange;     // toggle
1371     } while (!bDetermineRange);
1372 
1373     ScColumn::bDoubleAlloc = bOld;
1374     pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
1375 
1376     delete pEnglishTransliteration;
1377     delete pEnglishCalendar;
1378 
1379     xProgress.reset();    // make room for AdjustRowHeight progress
1380     if (bRangeIsDetermined)
1381         EndPaste();
1382 
1383     return sal_True;
1384 }
1385 
1386 
1387 // static
1388 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
1389         String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted )
1390 {
1391     rbIsQuoted = false;
1392     rField.Erase();
1393     if ( *p == cStr )           // String in Anfuehrungszeichen
1394     {
1395         rbIsQuoted = true;
1396         const sal_Unicode* p1;
1397         p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE );
1398         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1399             p++;
1400         // Append remaining unquoted and undelimited data (dirty, dirty) to
1401         // this field.
1402         if (p > p1)
1403             rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) );
1404         if( *p )
1405             p++;
1406     }
1407     else                        // bis zum Trennzeichen
1408     {
1409         const sal_Unicode* p0 = p;
1410         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1411             p++;
1412         rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1413         if( *p )
1414             p++;
1415     }
1416     if ( bMergeSeps )           // folgende Trennzeichen ueberspringen
1417     {
1418         while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
1419             p++;
1420     }
1421     return p;
1422 }
1423 
1424         //
1425         //
1426         //
1427 
1428 
1429 sal_Bool ScImportExport::Doc2Text( SvStream& rStrm )
1430 {
1431     SCCOL nCol;
1432     SCROW nRow;
1433     SCCOL nStartCol = aRange.aStart.Col();
1434     SCROW nStartRow = aRange.aStart.Row();
1435     SCCOL nEndCol = aRange.aEnd.Col();
1436     SCROW nEndRow = aRange.aEnd.Row();
1437     String aCell;
1438     bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1439 
1440     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1441     {
1442         if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() ))
1443         {
1444             for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1445             {
1446                 CellType eType;
1447                 pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType );
1448                 switch (eType)
1449                 {
1450                     case CELLTYPE_FORMULA:
1451                     {
1452                         if (bFormulas)
1453                         {
1454                             pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, sal_True );
1455                             if( aCell.Search( cSep ) != STRING_NOTFOUND )
1456                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
1457                             else
1458                                 lcl_WriteSimpleString( rStrm, aCell );
1459                         }
1460                         else
1461                         {
1462                             pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1463 
1464                             bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1465                             if( bMultiLineText )
1466                             {
1467                                 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1468                                     aCell.SearchAndReplaceAll( _LF, ' ' );
1469                                 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1470                                     aCell.ConvertLineEnd();
1471                             }
1472 
1473                             if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1474                                 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1475 
1476                             if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1477                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
1478                             else
1479                                 lcl_WriteSimpleString( rStrm, aCell );
1480                         }
1481                     }
1482                     break;
1483                     case CELLTYPE_VALUE:
1484                     {
1485                         pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1486                         lcl_WriteSimpleString( rStrm, aCell );
1487                     }
1488                     break;
1489                     case CELLTYPE_NOTE:
1490                     case CELLTYPE_NONE:
1491                     break;
1492                     default:
1493                     {
1494                         pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1495 
1496                         bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1497                         if( bMultiLineText )
1498                         {
1499                             if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1500                                 aCell.SearchAndReplaceAll( _LF, ' ' );
1501                             else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1502                                 aCell.ConvertLineEnd();
1503                         }
1504 
1505                         if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1506                             aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1507 
1508                         if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1509                             lcl_WriteString( rStrm, aCell, cStr, cStr );
1510                         else
1511                             lcl_WriteSimpleString( rStrm, aCell );
1512                     }
1513                 }
1514                 if( nCol < nEndCol )
1515                     lcl_WriteSimpleString( rStrm, String(cSep) );
1516             }
1517 //          if( nRow < nEndRow )
1518                 WriteUnicodeOrByteEndl( rStrm );
1519             if( rStrm.GetError() != SVSTREAM_OK )
1520                 break;
1521             if( nSizeLimit && rStrm.Tell() > nSizeLimit )
1522                 break;
1523         }
1524     }
1525 
1526     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1527 }
1528 
1529 
1530 sal_Bool ScImportExport::Sylk2Doc( SvStream& rStrm )
1531 {
1532     sal_Bool bOk = sal_True;
1533     sal_Bool bMyDoc = sal_False;
1534     SylkVersion eVersion = SYLK_OTHER;
1535 
1536     // US-English separators for StringToDouble
1537     sal_Unicode cDecSep = '.';
1538     sal_Unicode cGrpSep = ',';
1539 
1540     SCCOL nStartCol = aRange.aStart.Col();
1541     SCROW nStartRow = aRange.aStart.Row();
1542     SCCOL nEndCol = aRange.aEnd.Col();
1543     SCROW nEndRow = aRange.aEnd.Row();
1544     sal_uLong nOldPos = rStrm.Tell();
1545     sal_Bool bData = sal_Bool( !bSingle );
1546     SvULongs aFormats;
1547 
1548     if( !bSingle)
1549         bOk = StartPaste();
1550 
1551     while( bOk )
1552     {
1553         String aLine;
1554         String aText;
1555         ByteString aByteLine;
1556         SCCOL nCol = nStartCol;
1557         SCROW nRow = nStartRow;
1558         SCCOL nRefCol = 1;
1559         SCROW nRefRow = 1;
1560         rStrm.Seek( nOldPos );
1561         for( ;; )
1562         {
1563             //! allow unicode
1564             rStrm.ReadLine( aByteLine );
1565             aLine = String( aByteLine, rStrm.GetStreamCharSet() );
1566             if( rStrm.IsEof() )
1567                 break;
1568             const sal_Unicode* p = aLine.GetBuffer();
1569             sal_Unicode cTag = *p++;
1570             if( cTag == 'C' )       // Content
1571             {
1572                 if( *p++ != ';' )
1573                     return sal_False;
1574                 while( *p )
1575                 {
1576                     sal_Unicode ch = *p++;
1577                     ch = ScGlobal::ToUpperAlpha( ch );
1578                     switch( ch )
1579                     {
1580                         case 'X':
1581                             nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1582                             break;
1583                         case 'Y':
1584                             nRow = String( p ).ToInt32() + nStartRow - 1;
1585                             break;
1586                         case 'C':
1587                             nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1588                             break;
1589                         case 'R':
1590                             nRefRow = String( p ).ToInt32() + nStartRow - 1;
1591                             break;
1592                         case 'K':
1593                         {
1594                             if( !bSingle &&
1595                                     ( nCol < nStartCol || nCol > nEndCol
1596                                       || nRow < nStartRow || nRow > nEndRow
1597                                       || nCol > MAXCOL || nRow > MAXROW ) )
1598                                 break;
1599                             if( !bData )
1600                             {
1601                                 if( nRow > nEndRow )
1602                                     nEndRow = nRow;
1603                                 if( nCol > nEndCol )
1604                                     nEndCol = nCol;
1605                                 break;
1606                             }
1607                             sal_Bool bText;
1608                             if( *p == '"' )
1609                             {
1610                                 bText = sal_True;
1611                                 aText.Erase();
1612                                 p = lcl_ScanSylkString( p, aText, eVersion);
1613                             }
1614                             else
1615                                 bText = sal_False;
1616                             const sal_Unicode* q = p;
1617                             while( *q && *q != ';' )
1618                                 q++;
1619                             if ( !(*q == ';' && *(q+1) == 'I') )
1620                             {   // don't ignore value
1621                                 if( bText )
1622                                 {
1623                                     pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(),
1624                                             ScBaseCell::CreateTextCell( aText, pDoc),
1625                                             (sal_Bool) sal_True);
1626                                 }
1627                                 else
1628                                 {
1629                                     double fVal = rtl_math_uStringToDouble( p,
1630                                             aLine.GetBuffer() + aLine.Len(),
1631                                             cDecSep, cGrpSep, NULL, NULL );
1632                                     pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
1633                                 }
1634                             }
1635                         }
1636                         break;
1637                         case 'E':
1638                         case 'M':
1639                         {
1640                             if ( ch == 'M' )
1641                             {
1642                                 if ( nRefCol < nCol )
1643                                     nRefCol = nCol;
1644                                 if ( nRefRow < nRow )
1645                                     nRefRow = nRow;
1646                                 if ( !bData )
1647                                 {
1648                                     if( nRefRow > nEndRow )
1649                                         nEndRow = nRefRow;
1650                                     if( nRefCol > nEndCol )
1651                                         nEndCol = nRefCol;
1652                                 }
1653                             }
1654                             if( !bMyDoc || !bData )
1655                                 break;
1656                             aText = '=';
1657                             p = lcl_ScanSylkFormula( p, aText, eVersion);
1658                             ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
1659                             /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1660                              * end it probably should be GRAM_ODFF_R1C1, since
1661                              * R1C1 is what Excel writes in SYLK. */
1662                             const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
1663                             ScCompiler aComp( pDoc, aPos);
1664                             aComp.SetGrammar(eGrammar);
1665                             ScTokenArray* pCode = aComp.CompileString( aText );
1666                             if ( ch == 'M' )
1667                             {
1668                                 ScMarkData aMark;
1669                                 aMark.SelectTable( aPos.Tab(), sal_True );
1670                                 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1671                                     nRefRow, aMark, EMPTY_STRING, pCode );
1672                             }
1673                             else
1674                             {
1675                                 ScFormulaCell* pFCell = new ScFormulaCell(
1676                                         pDoc, aPos, pCode, eGrammar, MM_NONE);
1677                                 pDoc->PutCell( aPos, pFCell );
1678                             }
1679                             delete pCode;   // ctor/InsertMatrixFormula did copy TokenArray
1680                         }
1681                         break;
1682                     }
1683                     while( *p && *p != ';' )
1684                         p++;
1685                     if( *p )
1686                         p++;
1687                 }
1688             }
1689             else if( cTag == 'F' )      // Format
1690             {
1691                 if( *p++ != ';' )
1692                     return sal_False;
1693                 sal_Int32 nFormat = -1;
1694                 while( *p )
1695                 {
1696                     sal_Unicode ch = *p++;
1697                     ch = ScGlobal::ToUpperAlpha( ch );
1698                     switch( ch )
1699                     {
1700                         case 'X':
1701                             nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1702                             break;
1703                         case 'Y':
1704                             nRow = String( p ).ToInt32() + nStartRow - 1;
1705                             break;
1706                         case 'P' :
1707                             if ( bData )
1708                             {
1709                                 // F;P<n> sets format code of P;P<code> at
1710                                 // current position, or at ;X;Y if specified.
1711                                 // Note that ;X;Y may appear after ;P
1712                                 const sal_Unicode* p0 = p;
1713                                 while( *p && *p != ';' )
1714                                     p++;
1715                                 String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1716                                 nFormat = aNumber.ToInt32();
1717                             }
1718                             break;
1719                     }
1720                     while( *p && *p != ';' )
1721                         p++;
1722                     if( *p )
1723                         p++;
1724                 }
1725                 if ( !bData )
1726                 {
1727                     if( nRow > nEndRow )
1728                         nEndRow = nRow;
1729                     if( nCol > nEndCol )
1730                         nEndCol = nCol;
1731                 }
1732                 if ( 0 <= nFormat && nFormat < aFormats.Count() )
1733                 {
1734                     sal_uLong nKey = aFormats[(sal_uInt16)nFormat];
1735                     pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
1736                             SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
1737                 }
1738             }
1739             else if( cTag == 'P' )
1740             {
1741                 if ( bData && *p == ';' && *(p+1) == 'P' )
1742                 {
1743                     String aCode( p+2 );
1744                     // unescape doubled semicolons
1745                     xub_StrLen nPos = 0;
1746                     String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;"));
1747                     while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND )
1748                         aCode.Erase( nPos++, 1 );
1749                     // get rid of Xcl escape characters
1750                     nPos = 0;
1751                     while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND )
1752                         aCode.Erase( nPos, 1 );
1753                     xub_StrLen nCheckPos;
1754                     short nType;
1755                     sal_uInt32 nKey;
1756                     pDoc->GetFormatTable()->PutandConvertEntry(
1757                         aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US,
1758                         ScGlobal::eLnge );
1759                     if ( nCheckPos )
1760                         nKey = 0;
1761                     aFormats.Insert( nKey, aFormats.Count() );
1762                 }
1763             }
1764             else if( cTag == 'I' && *p == 'D' )
1765             {
1766                 aLine.Erase( 0, 4 );
1767                 if (aLine.EqualsAscii( "CALCOOO32" ))
1768                     eVersion = SYLK_OOO32;
1769                 else if (aLine.EqualsAscii( "SCALC3" ))
1770                     eVersion = SYLK_SCALC3;
1771                 bMyDoc = (eVersion <= SYLK_OWN);
1772             }
1773             else if( cTag == 'E' )                      // Ende
1774                 break;
1775         }
1776         if( !bData )
1777         {
1778             aRange.aEnd.SetCol( nEndCol );
1779             aRange.aEnd.SetRow( nEndRow );
1780             bOk = StartPaste();
1781             bData = sal_True;
1782         }
1783         else
1784             break;
1785     }
1786 
1787     EndPaste();
1788     return bOk;
1789 }
1790 
1791 
1792 sal_Bool ScImportExport::Doc2Sylk( SvStream& rStrm )
1793 {
1794     SCCOL nCol;
1795     SCROW nRow;
1796     SCCOL nStartCol = aRange.aStart.Col();
1797     SCROW nStartRow = aRange.aStart.Row();
1798     SCCOL nEndCol = aRange.aEnd.Col();
1799     SCROW nEndRow = aRange.aEnd.Row();
1800     String aCellStr;
1801     String aValStr;
1802     lcl_WriteSimpleString( rStrm,
1803             String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
1804     WriteUnicodeOrByteEndl( rStrm );
1805 
1806     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1807     {
1808         for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1809         {
1810             String aBufStr;
1811             double nVal;
1812             sal_Bool bForm = sal_False;
1813             SCROW r = nRow - nStartRow + 1;
1814             SCCOL c = nCol - nStartCol + 1;
1815             ScBaseCell* pCell;
1816             pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell );
1817             CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE);
1818             switch( eType )
1819             {
1820                 case CELLTYPE_FORMULA:
1821                     bForm = bFormulas;
1822                     if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1823                         goto hasvalue;
1824                     else
1825                         goto hasstring;
1826 
1827                 case CELLTYPE_VALUE:
1828                 hasvalue:
1829                     pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
1830 
1831                     aValStr = ::rtl::math::doubleToUString( nVal,
1832                             rtl_math_StringFormat_Automatic,
1833                             rtl_math_DecimalPlaces_Max, '.', sal_True );
1834 
1835                     aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1836                     aBufStr += String::CreateFromInt32( c );
1837                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1838                     aBufStr += String::CreateFromInt32( r );
1839                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1840                     aBufStr += aValStr;
1841                     lcl_WriteSimpleString( rStrm, aBufStr );
1842                     goto checkformula;
1843 
1844                 case CELLTYPE_STRING:
1845                 case CELLTYPE_EDIT:
1846                 hasstring:
1847                     pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
1848                     aCellStr.SearchAndReplaceAll( _LF, SYLK_LF );
1849 
1850                     aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1851                     aBufStr += String::CreateFromInt32( c );
1852                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1853                     aBufStr += String::CreateFromInt32( r );
1854                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1855                     lcl_WriteSimpleString( rStrm, aBufStr );
1856                     lcl_WriteString( rStrm, aCellStr, '"', ';' );
1857 
1858                 checkformula:
1859                     if( bForm )
1860                     {
1861                         const ScFormulaCell* pFCell =
1862                             static_cast<const ScFormulaCell*>(pCell);
1863                         switch ( pFCell->GetMatrixFlag() )
1864                         {
1865                             case MM_REFERENCE :
1866                                 aCellStr.Erase();
1867                             break;
1868                             default:
1869                                 pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
1870                                 /* FIXME: do we want GRAM_ODFF_A1 instead? At
1871                                  * the end it probably should be
1872                                  * GRAM_ODFF_R1C1, since R1C1 is what Excel
1873                                  * writes in SYLK. */
1874                         }
1875                         if ( pFCell->GetMatrixFlag() != MM_NONE &&
1876                                 aCellStr.Len() > 2 &&
1877                                 aCellStr.GetChar(0) == '{' &&
1878                                 aCellStr.GetChar(aCellStr.Len()-1) == '}' )
1879                         {   // cut off matrix {} characters
1880                             aCellStr.Erase(aCellStr.Len()-1,1);
1881                             aCellStr.Erase(0,1);
1882                         }
1883                         if ( aCellStr.GetChar(0) == '=' )
1884                             aCellStr.Erase(0,1);
1885                         String aPrefix;
1886                         switch ( pFCell->GetMatrixFlag() )
1887                         {
1888                             case MM_FORMULA :
1889                             {   // diff expression with 'M' M$-extension
1890                                 SCCOL nC;
1891                                 SCROW nR;
1892                                 pFCell->GetMatColsRows( nC, nR );
1893                                 nC += c - 1;
1894                                 nR += r - 1;
1895                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
1896                                 aPrefix += String::CreateFromInt32( nR );
1897                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1898                                 aPrefix += String::CreateFromInt32( nC );
1899                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
1900                             }
1901                             break;
1902                             case MM_REFERENCE :
1903                             {   // diff expression with 'I' M$-extension
1904                                 ScAddress aPos;
1905                                 pFCell->GetMatrixOrigin( aPos );
1906                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
1907                                 aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 );
1908                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1909                                 aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 );
1910                             }
1911                             break;
1912                             default:
1913                                 // formula Expression
1914                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
1915                         }
1916                         lcl_WriteSimpleString( rStrm, aPrefix );
1917                         if ( aCellStr.Len() )
1918                             lcl_WriteString( rStrm, aCellStr, 0, ';' );
1919                     }
1920                     WriteUnicodeOrByteEndl( rStrm );
1921                     break;
1922 
1923                 default:
1924                 {
1925                     // added to avoid warnings
1926                 }
1927             }
1928         }
1929     }
1930     lcl_WriteSimpleString( rStrm, String( 'E' ) );
1931     WriteUnicodeOrByteEndl( rStrm );
1932     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1933 }
1934 
1935 
1936 sal_Bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL )
1937 {
1938     // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
1939     ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
1940         aStreamPath, aNonConvertibleChars );
1941     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1942 }
1943 
1944 sal_Bool ScImportExport::Doc2RTF( SvStream& rStrm )
1945 {
1946     //  CharSet is ignored in ScExportRTF
1947     ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
1948     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1949 }
1950 
1951 
1952 sal_Bool ScImportExport::Doc2Dif( SvStream& rStrm )
1953 {
1954     // for DIF in the clipboard, IBM_850 is always used
1955     ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
1956     return sal_True;
1957 }
1958 
1959 
1960 sal_Bool ScImportExport::Dif2Doc( SvStream& rStrm )
1961 {
1962     SCTAB nTab = aRange.aStart.Tab();
1963     ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
1964     pImportDoc->InitUndo( pDoc, nTab, nTab );
1965 
1966     // for DIF in the clipboard, IBM_850 is always used
1967     ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
1968 
1969     SCCOL nEndCol;
1970     SCROW nEndRow;
1971     pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
1972     // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start
1973     if ( nEndCol < aRange.aStart.Col() )
1974         nEndCol = aRange.aStart.Col();
1975     if ( nEndRow < aRange.aStart.Row() )
1976         nEndRow = aRange.aStart.Row();
1977     aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
1978 
1979     sal_Bool bOk = StartPaste();
1980     if (bOk)
1981     {
1982         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
1983         pDoc->DeleteAreaTab( aRange, nFlags );
1984         pImportDoc->CopyToDocument( aRange, nFlags, sal_False, pDoc );
1985         EndPaste();
1986     }
1987 
1988     delete pImportDoc;
1989 
1990     return bOk;
1991 }
1992 
1993 
1994 sal_Bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL )
1995 {
1996     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
1997     if (!pImp)
1998         return false;
1999     pImp->Read( rStrm, rBaseURL );
2000     aRange = pImp->GetRange();
2001 
2002     sal_Bool bOk = StartPaste();
2003     if (bOk)
2004     {
2005         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2006         pDoc->DeleteAreaTab( aRange, nFlags );
2007         pImp->WriteToDocument();
2008         EndPaste();
2009     }
2010     delete pImp;
2011     return bOk;
2012 }
2013 
2014 
2015 sal_Bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL )
2016 {
2017     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, sal_True);
2018     if (!pImp)
2019         return false;
2020     pImp->Read( rStrm, rBaseURL );
2021     aRange = pImp->GetRange();
2022 
2023     sal_Bool bOk = StartPaste();
2024     if (bOk)
2025     {
2026         // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2027         // a Draw Layer but no Draw View -> create Draw Layer and View here
2028         if (pDocSh)
2029             pDocSh->MakeDrawLayer();
2030 
2031         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2032         pDoc->DeleteAreaTab( aRange, nFlags );
2033         pImp->WriteToDocument();
2034         EndPaste();
2035     }
2036     delete pImp;
2037     return bOk;
2038 }
2039 
2040 #define RETURN_ERROR { return eERR_INTERN; }
2041 class ScFormatFilterMissing : public ScFormatFilterPlugin {
2042   public:
2043     ScFormatFilterMissing()
2044     {
2045       OSL_ASSERT ("Missing file filters");
2046     }
2047     virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR
2048     virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
2049     virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
2050     virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
2051     virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
2052                  const CharSet, sal_uInt32 ) RETURN_ERROR
2053     virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR
2054     virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, sal_Bool, SvNumberFormatter*, bool ) RETURN_ERROR
2055 
2056     virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
2057     virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, sal_Bool ) { return NULL; }
2058     virtual String         GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); }
2059 
2060 #if ENABLE_LOTUS123_EXPORT
2061     virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR
2062 #endif
2063     virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR
2064     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR
2065     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR
2066     virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, sal_Bool,
2067                   const String&, String& ) RETURN_ERROR
2068     virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR
2069 };
2070 
2071 extern "C" { static void SAL_CALL thisModule() {} }
2072 typedef ScFormatFilterPlugin * (*FilterFn)(void);
2073 ScFormatFilterPlugin &ScFormatFilter::Get()
2074 {
2075     static ScFormatFilterPlugin *plugin;
2076 
2077     if (plugin != NULL)
2078         return *plugin;
2079 
2080     static ::osl::Module aModule;
2081     if ( aModule.loadRelative( &thisModule,
2082                    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) )
2083     {
2084     oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) );
2085     if (fn != NULL)
2086         plugin = reinterpret_cast<FilterFn>(fn)();
2087     }
2088     if (plugin == NULL)
2089         plugin = new ScFormatFilterMissing();
2090 
2091     return *plugin;
2092 }
2093