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