xref: /AOO41X/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