xref: /AOO41X/main/sc/source/ui/docshell/impex.cxx (revision 36795fb31b6150980d77ebea85aeae4434a29853)
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 
ScImportExport(ScDocument * p)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 
ScImportExport(ScDocument * p,const ScAddress & rPt)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 
ScImportExport(ScDocument * p,const ScRange & r)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 
ScImportExport(ScDocument * p,const String & rPos)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 
~ScImportExport()195 ScImportExport::~ScImportExport()
196 {
197     delete pUndoDoc;
198     delete pExtOptions;
199 }
200 
201 
SetExtOptions(const ScAsciiOptions & rOpt)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 
IsFormatSupported(sal_uLong nFormat)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 
StartPaste()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 
EndPaste()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 
ImportData(const String &,const::com::sun::star::uno::Any &)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 
ExportData(const String & rMimeType,::com::sun::star::uno::Any & rValue)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 
ImportString(const::rtl::OUString & rText,sal_uLong nFmt)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 
ExportString(::rtl::OUString & rText,sal_uLong nFmt)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 
ExportByteString(ByteString & rText,rtl_TextEncoding eEnc,sal_uLong nFmt)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 
ImportStream(SvStream & rStrm,const String & rBaseURL,sal_uLong nFmt)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 
ExportStream(SvStream & rStrm,const String & rBaseURL,sal_uLong nFmt)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
WriteUnicodeOrByteString(SvStream & rStrm,const String & rString,sal_Bool bZero)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
WriteUnicodeOrByteEndl(SvStream & rStrm)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 
lcl_ScanString(const sal_Unicode * p,String & rString,sal_Unicode cStr,DoubledQuoteMode eMode)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 
lcl_UnescapeSylk(String & rString,SylkVersion eVersion)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 
lcl_ScanSylkString(const sal_Unicode * p,String & rString,SylkVersion eVersion)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 
lcl_ScanSylkFormula(const sal_Unicode * p,String & rString,SylkVersion eVersion)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 
lcl_DoubleEscapeChar(String & rString,sal_Unicode cStr)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 
lcl_WriteString(SvStream & rStrm,String & rString,sal_Unicode cQuote,sal_Unicode cEsc)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 
lcl_WriteSimpleString(SvStream & rStrm,const String & rString)808 inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString )
809 {
810     ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
811 }
812 
813 //////////////////////////////////////////////////////////////////////////////
814 
815 
Text2Doc(SvStream & rStrm)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 
847                 if( *p == cStr )//cStr = "
848                 {
849                     p = lcl_ScanString( p, aCell, cStr, DQM_KEEP );
850                 }
851 
852                 const sal_Unicode* q = p;
853                 while( *p && *p != cSep )// cSep = tab
854                     p++;
855 
856                 aCell.Append( q, sal::static_int_cast<xub_StrLen>( p - q ) );
857 
858                 if( *p )
859                     p++;
860                 if (ValidCol(nCol) && ValidRow(nRow) )
861                 {
862                     if( bSingle )
863                     {
864                         if (nCol>nEndCol) nEndCol = nCol;
865                         if (nRow>nEndRow) nEndRow = nRow;
866                     }
867                     if( bData && nCol <= nEndCol && nRow <= nEndRow )
868                         pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
869                 }
870                 else                            // zuviele Spalten/Zeilen
871                     bOverflow = sal_True;           // beim Import Warnung ausgeben
872                 ++nCol;
873             }
874             ++nRow;
875         }
876 
877         if( !bData )
878         {
879             aRange.aEnd.SetCol( nEndCol );
880             aRange.aEnd.SetRow( nEndRow );
881             bOk = StartPaste();
882             bData = sal_True;
883         }
884         else
885             break;
886     }
887 
888     EndPaste();
889     return bOk;
890 }
891 
892         //
893         //  erweiterter Ascii-Import
894         //
895 
896 
lcl_PutString(ScDocument * pDoc,SCCOL nCol,SCROW nRow,SCTAB nTab,const String & rStr,sal_uInt8 nColFormat,SvNumberFormatter * pFormatter,bool bDetectNumFormat,::utl::TransliterationWrapper & rTransliteration,CalendarWrapper & rCalendar,::utl::TransliterationWrapper * pSecondTransliteration,CalendarWrapper * pSecondCalendar)897 static bool lcl_PutString(
898     ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat,
899     SvNumberFormatter* pFormatter, bool bDetectNumFormat,
900     ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
901     ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
902 {
903     bool bMultiLine = false;
904     if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) )
905         return bMultiLine;
906 
907     if ( nColFormat == SC_COL_TEXT )
908     {
909         pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) );
910         return bMultiLine;
911     }
912 
913     if ( nColFormat == SC_COL_ENGLISH )
914     {
915         //! SetString mit Extra-Flag ???
916 
917         SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
918         sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
919         double fVal;
920         if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
921         {
922             //  Zahlformat wird nicht auf englisch gesetzt
923             pDoc->SetValue( nCol, nRow, nTab, fVal );
924             return bMultiLine;
925         }
926         //  sonst weiter mit SetString
927     }
928     else if ( nColFormat != SC_COL_STANDARD )                   // Datumsformate
929     {
930         const sal_uInt16 nMaxNumberParts = 7;   // Y-M-D h:m:s.t
931         xub_StrLen nLen = rStr.Len();
932         xub_StrLen nStart[nMaxNumberParts];
933         xub_StrLen nEnd[nMaxNumberParts];
934 
935         sal_uInt16 nDP, nMP, nYP;
936         switch ( nColFormat )
937         {
938             case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
939             case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
940             case SC_COL_DMY:
941             default:         nDP = 0; nMP = 1; nYP = 2; break;
942         }
943 
944         sal_uInt16 nFound = 0;
945         sal_Bool bInNum = sal_False;
946         for ( xub_StrLen nPos=0; nPos<nLen && (bInNum ||
947                     nFound<nMaxNumberParts); nPos++ )
948         {
949             if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
950                     nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T')
951                 bInNum = sal_False;     // ISO-8601: YYYY-MM-DDThh:mm...
952             else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
953                         && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
954                     || ScGlobal::pCharClass->isDigit( rStr, nPos))
955             {
956                 if (!bInNum)
957                 {
958                     bInNum = sal_True;
959                     nStart[nFound] = nPos;
960                     ++nFound;
961                 }
962                 nEnd[nFound-1] = nPos;
963             }
964             else
965                 bInNum = sal_False;
966         }
967 
968         if ( nFound == 1 )
969         {
970             //  try to break one number (without separators) into date fields
971 
972             xub_StrLen nDateStart = nStart[0];
973             xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart;
974 
975             if ( nDateLen >= 5 && nDateLen <= 8 &&
976                     ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) )
977             {
978                 //  6 digits: 2 each for day, month, year
979                 //  8 digits: 4 for year, 2 each for day and month
980                 //  5 or 7 digits: first field is shortened by 1
981 
982                 sal_Bool bLongYear = ( nDateLen >= 7 );
983                 sal_Bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
984 
985                 sal_uInt16 nFieldStart = nDateStart;
986                 for (sal_uInt16 nPos=0; nPos<3; nPos++)
987                 {
988                     sal_uInt16 nFieldEnd = nFieldStart + 1;     // default: 2 digits
989                     if ( bLongYear && nPos == nYP )
990                         nFieldEnd += 2;                     // 2 extra digits for long year
991                     if ( bShortFirst && nPos == 0 )
992                         --nFieldEnd;                        // first field shortened?
993 
994                     nStart[nPos] = nFieldStart;
995                     nEnd[nPos]   = nFieldEnd;
996                     nFieldStart  = nFieldEnd + 1;
997                 }
998                 nFound = 3;
999             }
1000         }
1001 
1002         if ( nFound >= 3 )
1003         {
1004             using namespace ::com::sun::star;
1005             sal_Bool bSecondCal = sal_False;
1006             sal_uInt16 nDay  = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32();
1007             sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32();
1008             String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1009             sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32();
1010             if (!nMonth)
1011             {
1012                 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
1013                 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
1014                 uno::Sequence< i18n::CalendarItem > xMonths;
1015                 sal_Int32 i, nMonthCount;
1016                 //  first test all month names from local international
1017                 xMonths = rCalendar.getMonths();
1018                 nMonthCount = xMonths.getLength();
1019                 for (i=0; i<nMonthCount && !nMonth; i++)
1020                 {
1021                     if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
1022                          rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
1023                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1024                     else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
1025                                 xMonths[i].AbbrevName ) &&
1026                             rTransliteration.isEqual( aMStr, aSepShortened ) )
1027                     {   // #102136# correct English abbreviation is SEPT,
1028                         // but data mostly contains SEP only
1029                         nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1030                     }
1031                 }
1032                 //  if none found, then test english month names
1033                 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
1034                 {
1035                     xMonths = pSecondCalendar->getMonths();
1036                     nMonthCount = xMonths.getLength();
1037                     for (i=0; i<nMonthCount && !nMonth; i++)
1038                     {
1039                         if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
1040                              pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
1041                         {
1042                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1043                             bSecondCal = sal_True;
1044                         }
1045                         else if ( i == 8 && pSecondTransliteration->isEqual(
1046                                     aMStr, aSepShortened ) )
1047                         {   // #102136# correct English abbreviation is SEPT,
1048                             // but data mostly contains SEP only
1049                             nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1050                             bSecondCal = sal_True;
1051                         }
1052                     }
1053                 }
1054             }
1055 
1056             SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1057             if ( nYear < 100 )
1058                 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1059 
1060             CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1061             sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1062             if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
1063             {
1064                 --nMonth;
1065                 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1066                 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1067                 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1068                 sal_Int16 nHour, nMinute, nSecond, nMilli;
1069                 // #i14974# The imported value should have no fractional value, so set the
1070                 // time fields to zero (ICU calendar instance defaults to current date/time)
1071                 nHour = nMinute = nSecond = nMilli = 0;
1072                 if (nFound > 3)
1073                     nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32();
1074                 if (nFound > 4)
1075                     nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32();
1076                 if (nFound > 5)
1077                     nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32();
1078                 if (nFound > 6)
1079                 {
1080                     sal_Unicode cDec = '.';
1081                     rtl::OUString aT( &cDec, 1);
1082                     aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]);
1083                     rtl_math_ConversionStatus eStatus;
1084                     double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
1085                     if (eStatus == rtl_math_ConversionStatus_Ok)
1086                         nMilli = (sal_Int16) (1000.0 * fV + 0.5);
1087                 }
1088                 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1089                 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1090                 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1091                 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
1092                 if ( pCalendar->isValid() )
1093                 {
1094                     double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
1095                         pCalendar->getEpochStart();
1096                     // #i14974# must use getLocalDateTime to get the same
1097                     // date values as set above
1098                     double fDays = pCalendar->getLocalDateTime();
1099                     fDays -= fDiff;
1100 
1101                     LanguageType eLatin, eCjk, eCtl;
1102                     pDoc->GetLanguage( eLatin, eCjk, eCtl );
1103                     LanguageType eDocLang = eLatin;     //! which language for date formats?
1104 
1105                     short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
1106                     sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1107                     // maybe there is a special format including seconds or milliseconds
1108                     if (nFound > 5)
1109                         nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1110 
1111                     pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, sal_False );
1112 
1113                     return bMultiLine;     // success
1114                 }
1115             }
1116         }
1117     }
1118 
1119     // Standard or date not determined -> SetString / EditCell
1120     if( rStr.Search( _LF ) == STRING_NOTFOUND )
1121         pDoc->SetString( nCol, nRow, nTab, rStr, pFormatter, bDetectNumFormat );
1122     else
1123     {
1124         bMultiLine = true;
1125         pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
1126     }
1127     return bMultiLine;
1128 }
1129 
1130 
lcl_GetFixed(const String & rLine,xub_StrLen nStart,xub_StrLen nNext,bool & rbIsQuoted)1131 String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext, bool& rbIsQuoted )
1132 {
1133     xub_StrLen nLen = rLine.Len();
1134     if (nNext > nLen)
1135         nNext = nLen;
1136     if ( nNext <= nStart )
1137         return EMPTY_STRING;
1138 
1139     const sal_Unicode* pStr = rLine.GetBuffer();
1140 
1141     xub_StrLen nSpace = nNext;
1142     while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
1143         --nSpace;
1144 
1145     rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"'));
1146     if (rbIsQuoted)
1147         return rLine.Copy(nStart+1, nSpace-nStart-2);
1148     else
1149         return rLine.Copy(nStart, nSpace-nStart);
1150 }
1151 
ExtText2Doc(SvStream & rStrm)1152 sal_Bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1153 {
1154     if (!pExtOptions)
1155         return Text2Doc( rStrm );
1156 
1157     sal_uLong nOldPos = rStrm.Tell();
1158     rStrm.Seek( STREAM_SEEK_TO_END );
1159     ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1160             ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
1161     rStrm.Seek( nOldPos );
1162     rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
1163 
1164     sal_Bool bOld = ScColumn::bDoubleAlloc;
1165     ScColumn::bDoubleAlloc = sal_True;
1166 
1167     SCCOL nStartCol = aRange.aStart.Col();
1168     SCCOL nEndCol = aRange.aEnd.Col();
1169     SCROW nStartRow = aRange.aStart.Row();
1170     SCTAB nTab = aRange.aStart.Tab();
1171 
1172     sal_Bool    bFixed          = pExtOptions->IsFixedLen();
1173     const String& rSeps     = pExtOptions->GetFieldSeps();
1174     const sal_Unicode* pSeps = rSeps.GetBuffer();
1175     sal_Bool    bMerge          = pExtOptions->IsMergeSeps();
1176     sal_uInt16  nInfoCount      = pExtOptions->GetInfoCount();
1177     const xub_StrLen* pColStart = pExtOptions->GetColStart();
1178     const sal_uInt8* pColFormat  = pExtOptions->GetColFormat();
1179     long nSkipLines = pExtOptions->GetStartRow();
1180 
1181     LanguageType eDocLang = pExtOptions->GetLanguage();
1182     SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang);
1183     bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1184 
1185     // For date recognition
1186     ::utl::TransliterationWrapper aTransliteration(
1187         pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1188     aTransliteration.loadModuleIfNeeded( eDocLang );
1189     CalendarWrapper aCalendar( pDoc->GetServiceManager() );
1190     aCalendar.loadDefaultCalendar(
1191         MsLangId::convertLanguageToLocale( eDocLang ) );
1192     ::utl::TransliterationWrapper* pEnglishTransliteration = NULL;
1193     CalendarWrapper* pEnglishCalendar = NULL;
1194     if ( eDocLang != LANGUAGE_ENGLISH_US )
1195     {
1196         pEnglishTransliteration = new ::utl::TransliterationWrapper (
1197             pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1198         aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1199         pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() );
1200         pEnglishCalendar->loadDefaultCalendar(
1201             MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) );
1202     }
1203 
1204     String aLine, aCell;
1205     sal_uInt16 i;
1206     SCROW nRow = nStartRow;
1207 
1208     while(--nSkipLines>0)
1209     {
1210         rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored
1211         if ( rStrm.IsEof() )
1212             break;
1213     }
1214 
1215     // Determine range for Undo.
1216     // TODO: we don't need this during import of a file to a new sheet or
1217     // document, could set bDetermineRange=false then.
1218     bool bDetermineRange = true;
1219 
1220     // Row heights don't need to be adjusted on the fly if EndPaste() is called
1221     // afterwards, which happens only if bDetermineRange. This variable also
1222     // survives the toggle of bDetermineRange down at the end of the do{} loop.
1223     bool bRangeIsDetermined = bDetermineRange;
1224 
1225     bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1226 
1227     sal_uLong nOriginalStreamPos = rStrm.Tell();
1228 
1229     do
1230     {
1231         for( ;; )
1232         {
1233             rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr);
1234             if ( rStrm.IsEof() && aLine.Len() == 0 )
1235                 break;
1236 
1237             xub_StrLen nLineLen = aLine.Len();
1238             SCCOL nCol = nStartCol;
1239             bool bMultiLine = false;
1240             if ( bFixed )               //  Feste Satzlaenge
1241             {
1242                 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1243                 // overflow if there is really data following to be put behind
1244                 // the last column, which doesn't happen if info is
1245                 // SC_COL_SKIP.
1246                 for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
1247                 {
1248                     sal_uInt8 nFmt = pColFormat[i];
1249                     if (nFmt != SC_COL_SKIP)        // sonst auch nCol nicht hochzaehlen
1250                     {
1251                         if (nCol > MAXCOL)
1252                             bOverflow = sal_True;       // display warning on import
1253                         else if (!bDetermineRange)
1254                         {
1255                             xub_StrLen nStart = pColStart[i];
1256                             xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
1257                             bool bIsQuoted = false;
1258                             aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted );
1259                             if (bIsQuoted && bQuotedAsText)
1260                                 nFmt = SC_COL_TEXT;
1261 
1262                             bMultiLine |= lcl_PutString(
1263                                 pDoc, nCol, nRow, nTab, aCell, nFmt,
1264                                 &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1265                                 pEnglishTransliteration, pEnglishCalendar);
1266                         }
1267                         ++nCol;
1268                     }
1269                 }
1270             }
1271             else                        //  Nach Trennzeichen suchen
1272             {
1273                 SCCOL nSourceCol = 0;
1274                 sal_uInt16 nInfoStart = 0;
1275                 const sal_Unicode* p = aLine.GetBuffer();
1276                 // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1277                 // overflow if there is really data following to be put behind
1278                 // the last column, which doesn't happen if info is
1279                 // SC_COL_SKIP.
1280                 while (*p && nCol <= MAXCOL+1)
1281                 {
1282                     bool bIsQuoted = false;
1283                     p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge, bIsQuoted );
1284 
1285                     sal_uInt8 nFmt = SC_COL_STANDARD;
1286                     for ( i=nInfoStart; i<nInfoCount; i++ )
1287                     {
1288                         if ( pColStart[i] == nSourceCol + 1 )       // pColStart ist 1-basiert
1289                         {
1290                             nFmt = pColFormat[i];
1291                             nInfoStart = i + 1;     // ColInfos sind in Reihenfolge
1292                             break;  // for
1293                         }
1294                     }
1295                     if ( nFmt != SC_COL_SKIP )
1296                     {
1297                         if (nCol > MAXCOL)
1298                             bOverflow = sal_True;       // display warning on import
1299                         else if (!bDetermineRange)
1300                         {
1301                             if (bIsQuoted && bQuotedAsText)
1302                                 nFmt = SC_COL_TEXT;
1303 
1304                             bMultiLine |= lcl_PutString(
1305                                 pDoc, nCol, nRow, nTab, aCell, nFmt,
1306                                 &aNumFormatter, bDetectNumFormat, aTransliteration,
1307                                 aCalendar, pEnglishTransliteration, pEnglishCalendar);
1308                         }
1309                         ++nCol;
1310                     }
1311 
1312                     ++nSourceCol;
1313                 }
1314             }
1315             if (nEndCol < nCol)
1316                 nEndCol = nCol;     //! points to the next free or even MAXCOL+2
1317 
1318             if (!bDetermineRange)
1319             {
1320                 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1321                     pDocSh->AdjustRowHeight( nRow, nRow, nTab);
1322                 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1323             }
1324             ++nRow;
1325             if ( nRow > MAXROW )
1326             {
1327                 bOverflow = sal_True;       // display warning on import
1328                 break;  // for
1329             }
1330         }
1331         // so far nRow/nEndCol pointed to the next free
1332         if (nRow > nStartRow)
1333             --nRow;
1334         if (nEndCol > nStartCol)
1335             nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
1336 
1337         if (bDetermineRange)
1338         {
1339             aRange.aEnd.SetCol( nEndCol );
1340             aRange.aEnd.SetRow( nRow );
1341 
1342             if ( !mbApi && nStartCol != nEndCol &&
1343                  !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
1344             {
1345                 ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
1346                 if ( aBox.Execute() != RET_YES )
1347                 {
1348                     delete pEnglishTransliteration;
1349                     delete pEnglishCalendar;
1350                     return sal_False;
1351                 }
1352             }
1353 
1354             rStrm.Seek( nOriginalStreamPos );
1355             nRow = nStartRow;
1356             if (!StartPaste())
1357             {
1358                 EndPaste();
1359                 return sal_False;
1360             }
1361         }
1362 
1363         bDetermineRange = !bDetermineRange;     // toggle
1364     } while (!bDetermineRange);
1365 
1366     ScColumn::bDoubleAlloc = bOld;
1367     pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
1368 
1369     delete pEnglishTransliteration;
1370     delete pEnglishCalendar;
1371 
1372     xProgress.reset();    // make room for AdjustRowHeight progress
1373     if (bRangeIsDetermined)
1374         EndPaste();
1375 
1376     return sal_True;
1377 }
1378 
1379 
1380 // static
ScanNextFieldFromString(const sal_Unicode * p,String & rField,sal_Unicode cStr,const sal_Unicode * pSeps,bool bMergeSeps,bool & rbIsQuoted)1381 const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
1382         String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted )
1383 {
1384     rbIsQuoted = false;
1385     rField.Erase();
1386     if ( *p == cStr )           // String in Anfuehrungszeichen
1387     {
1388         rbIsQuoted = true;
1389         const sal_Unicode* p1;
1390         p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE );
1391         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1392             p++;
1393         // Append remaining unquoted and undelimited data (dirty, dirty) to
1394         // this field.
1395         if (p > p1)
1396             rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) );
1397         if( *p )
1398             p++;
1399     }
1400     else                        // bis zum Trennzeichen
1401     {
1402         const sal_Unicode* p0 = p;
1403         while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
1404             p++;
1405         rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1406         if( *p )
1407             p++;
1408     }
1409     if ( bMergeSeps )           // folgende Trennzeichen ueberspringen
1410     {
1411         while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
1412             p++;
1413     }
1414     return p;
1415 }
1416 
1417         //
1418         //
1419         //
1420 
1421 
Doc2Text(SvStream & rStrm)1422 sal_Bool ScImportExport::Doc2Text( SvStream& rStrm )
1423 {
1424     SCCOL nCol;
1425     SCROW nRow;
1426     SCCOL nStartCol = aRange.aStart.Col();
1427     SCROW nStartRow = aRange.aStart.Row();
1428     SCCOL nEndCol = aRange.aEnd.Col();
1429     SCROW nEndRow = aRange.aEnd.Row();
1430     String aCell;
1431     bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1432 
1433     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1434     {
1435         if (bIncludeFiltered || !pDoc->RowFiltered( nRow, aRange.aStart.Tab() ))
1436         {
1437             for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1438             {
1439                 CellType eType;
1440                 pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType );
1441                 switch (eType)
1442                 {
1443                     case CELLTYPE_FORMULA:
1444                     {
1445                         if (bFormulas)
1446                         {
1447                             pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, sal_True );
1448                             if( aCell.Search( cSep ) != STRING_NOTFOUND )
1449                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
1450                             else
1451                                 lcl_WriteSimpleString( rStrm, aCell );
1452                         }
1453                         else
1454                         {
1455                             pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1456 
1457                             bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1458                             if( bMultiLineText )
1459                             {
1460                                 if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1461                                     aCell.SearchAndReplaceAll( _LF, ' ' );
1462                                 else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1463                                     aCell.ConvertLineEnd();
1464                             }
1465 
1466                             if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1467                                 aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1468 
1469                             if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1470                                 lcl_WriteString( rStrm, aCell, cStr, cStr );
1471                             else
1472                                 lcl_WriteSimpleString( rStrm, aCell );
1473                         }
1474                     }
1475                     break;
1476                     case CELLTYPE_VALUE:
1477                     {
1478                         pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1479                         lcl_WriteSimpleString( rStrm, aCell );
1480                     }
1481                     break;
1482                     case CELLTYPE_NOTE:
1483                     case CELLTYPE_NONE:
1484                     break;
1485                     default:
1486                     {
1487                         pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1488 
1489                         bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1490                         if( bMultiLineText )
1491                         {
1492                             if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1493                                 aCell.SearchAndReplaceAll( _LF, ' ' );
1494                             else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1495                                 aCell.ConvertLineEnd();
1496                         }
1497 
1498                         if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1499                             aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1500 
1501                         if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1502                             lcl_WriteString( rStrm, aCell, cStr, cStr );
1503                         else
1504                             lcl_WriteSimpleString( rStrm, aCell );
1505                     }
1506                 }
1507                 if( nCol < nEndCol )
1508                     lcl_WriteSimpleString( rStrm, String(cSep) );
1509             }
1510 //          if( nRow < nEndRow )
1511                 WriteUnicodeOrByteEndl( rStrm );
1512             if( rStrm.GetError() != SVSTREAM_OK )
1513                 break;
1514             if( nSizeLimit && rStrm.Tell() > nSizeLimit )
1515                 break;
1516         }
1517     }
1518 
1519     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1520 }
1521 
1522 
Sylk2Doc(SvStream & rStrm)1523 sal_Bool ScImportExport::Sylk2Doc( SvStream& rStrm )
1524 {
1525     sal_Bool bOk = sal_True;
1526     sal_Bool bMyDoc = sal_False;
1527     SylkVersion eVersion = SYLK_OTHER;
1528 
1529     // US-English separators for StringToDouble
1530     sal_Unicode cDecSep = '.';
1531     sal_Unicode cGrpSep = ',';
1532 
1533     SCCOL nStartCol = aRange.aStart.Col();
1534     SCROW nStartRow = aRange.aStart.Row();
1535     SCCOL nEndCol = aRange.aEnd.Col();
1536     SCROW nEndRow = aRange.aEnd.Row();
1537     sal_uLong nOldPos = rStrm.Tell();
1538     sal_Bool bData = sal_Bool( !bSingle );
1539     SvULongs aFormats;
1540 
1541     if( !bSingle)
1542         bOk = StartPaste();
1543 
1544     while( bOk )
1545     {
1546         String aLine;
1547         String aText;
1548         ByteString aByteLine;
1549         SCCOL nCol = nStartCol;
1550         SCROW nRow = nStartRow;
1551         SCCOL nRefCol = 1;
1552         SCROW nRefRow = 1;
1553         rStrm.Seek( nOldPos );
1554         for( ;; )
1555         {
1556             //! allow unicode
1557             rStrm.ReadLine( aByteLine );
1558             aLine = String( aByteLine, rStrm.GetStreamCharSet() );
1559             if( rStrm.IsEof() )
1560                 break;
1561             const sal_Unicode* p = aLine.GetBuffer();
1562             sal_Unicode cTag = *p++;
1563             if( cTag == 'C' )       // Content
1564             {
1565                 if( *p++ != ';' )
1566                     return sal_False;
1567                 while( *p )
1568                 {
1569                     sal_Unicode ch = *p++;
1570                     ch = ScGlobal::ToUpperAlpha( ch );
1571                     switch( ch )
1572                     {
1573                         case 'X':
1574                             nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1575                             break;
1576                         case 'Y':
1577                             nRow = String( p ).ToInt32() + nStartRow - 1;
1578                             break;
1579                         case 'C':
1580                             nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1581                             break;
1582                         case 'R':
1583                             nRefRow = String( p ).ToInt32() + nStartRow - 1;
1584                             break;
1585                         case 'K':
1586                         {
1587                             if( !bSingle &&
1588                                     ( nCol < nStartCol || nCol > nEndCol
1589                                       || nRow < nStartRow || nRow > nEndRow
1590                                       || nCol > MAXCOL || nRow > MAXROW ) )
1591                                 break;
1592                             if( !bData )
1593                             {
1594                                 if( nRow > nEndRow )
1595                                     nEndRow = nRow;
1596                                 if( nCol > nEndCol )
1597                                     nEndCol = nCol;
1598                                 break;
1599                             }
1600                             sal_Bool bText;
1601                             if( *p == '"' )
1602                             {
1603                                 bText = sal_True;
1604                                 aText.Erase();
1605                                 p = lcl_ScanSylkString( p, aText, eVersion);
1606                             }
1607                             else
1608                                 bText = sal_False;
1609                             const sal_Unicode* q = p;
1610                             while( *q && *q != ';' )
1611                                 q++;
1612                             if ( !(*q == ';' && *(q+1) == 'I') )
1613                             {   // don't ignore value
1614                                 if( bText )
1615                                 {
1616                                     pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(),
1617                                             ScBaseCell::CreateTextCell( aText, pDoc),
1618                                             (sal_Bool) sal_True);
1619                                 }
1620                                 else
1621                                 {
1622                                     double fVal = rtl_math_uStringToDouble( p,
1623                                             aLine.GetBuffer() + aLine.Len(),
1624                                             cDecSep, cGrpSep, NULL, NULL );
1625                                     pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
1626                                 }
1627                             }
1628                         }
1629                         break;
1630                         case 'E':
1631                         case 'M':
1632                         {
1633                             if ( ch == 'M' )
1634                             {
1635                                 if ( nRefCol < nCol )
1636                                     nRefCol = nCol;
1637                                 if ( nRefRow < nRow )
1638                                     nRefRow = nRow;
1639                                 if ( !bData )
1640                                 {
1641                                     if( nRefRow > nEndRow )
1642                                         nEndRow = nRefRow;
1643                                     if( nRefCol > nEndCol )
1644                                         nEndCol = nRefCol;
1645                                 }
1646                             }
1647                             if( !bMyDoc || !bData )
1648                                 break;
1649                             aText = '=';
1650                             p = lcl_ScanSylkFormula( p, aText, eVersion);
1651                             ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
1652                             /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1653                              * end it probably should be GRAM_ODFF_R1C1, since
1654                              * R1C1 is what Excel writes in SYLK. */
1655                             const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
1656                             ScCompiler aComp( pDoc, aPos);
1657                             aComp.SetGrammar(eGrammar);
1658                             ScTokenArray* pCode = aComp.CompileString( aText );
1659                             if ( ch == 'M' )
1660                             {
1661                                 ScMarkData aMark;
1662                                 aMark.SelectTable( aPos.Tab(), sal_True );
1663                                 pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1664                                     nRefRow, aMark, EMPTY_STRING, pCode );
1665                             }
1666                             else
1667                             {
1668                                 ScFormulaCell* pFCell = new ScFormulaCell(
1669                                         pDoc, aPos, pCode, eGrammar, MM_NONE);
1670                                 pDoc->PutCell( aPos, pFCell );
1671                             }
1672                             delete pCode;   // ctor/InsertMatrixFormula did copy TokenArray
1673                         }
1674                         break;
1675                     }
1676                     while( *p && *p != ';' )
1677                         p++;
1678                     if( *p )
1679                         p++;
1680                 }
1681             }
1682             else if( cTag == 'F' )      // Format
1683             {
1684                 if( *p++ != ';' )
1685                     return sal_False;
1686                 sal_Int32 nFormat = -1;
1687                 while( *p )
1688                 {
1689                     sal_Unicode ch = *p++;
1690                     ch = ScGlobal::ToUpperAlpha( ch );
1691                     switch( ch )
1692                     {
1693                         case 'X':
1694                             nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1;
1695                             break;
1696                         case 'Y':
1697                             nRow = String( p ).ToInt32() + nStartRow - 1;
1698                             break;
1699                         case 'P' :
1700                             if ( bData )
1701                             {
1702                                 // F;P<n> sets format code of P;P<code> at
1703                                 // current position, or at ;X;Y if specified.
1704                                 // Note that ;X;Y may appear after ;P
1705                                 const sal_Unicode* p0 = p;
1706                                 while( *p && *p != ';' )
1707                                     p++;
1708                                 String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) );
1709                                 nFormat = aNumber.ToInt32();
1710                             }
1711                             break;
1712                     }
1713                     while( *p && *p != ';' )
1714                         p++;
1715                     if( *p )
1716                         p++;
1717                 }
1718                 if ( !bData )
1719                 {
1720                     if( nRow > nEndRow )
1721                         nEndRow = nRow;
1722                     if( nCol > nEndCol )
1723                         nEndCol = nCol;
1724                 }
1725                 if ( 0 <= nFormat && nFormat < aFormats.Count() )
1726                 {
1727                     sal_uLong nKey = aFormats[(sal_uInt16)nFormat];
1728                     pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
1729                             SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
1730                 }
1731             }
1732             else if( cTag == 'P' )
1733             {
1734                 if ( bData && *p == ';' && *(p+1) == 'P' )
1735                 {
1736                     String aCode( p+2 );
1737                     // unescape doubled semicolons
1738                     xub_StrLen nPos = 0;
1739                     String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;"));
1740                     while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND )
1741                         aCode.Erase( nPos++, 1 );
1742                     // get rid of Xcl escape characters
1743                     nPos = 0;
1744                     while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND )
1745                         aCode.Erase( nPos, 1 );
1746                     xub_StrLen nCheckPos;
1747                     short nType;
1748                     sal_uInt32 nKey;
1749                     pDoc->GetFormatTable()->PutandConvertEntry(
1750                         aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US,
1751                         ScGlobal::eLnge );
1752                     if ( nCheckPos )
1753                         nKey = 0;
1754                     aFormats.Insert( nKey, aFormats.Count() );
1755                 }
1756             }
1757             else if( cTag == 'I' && *p == 'D' )
1758             {
1759                 aLine.Erase( 0, 4 );
1760                 if (aLine.EqualsAscii( "CALCOOO32" ))
1761                     eVersion = SYLK_OOO32;
1762                 else if (aLine.EqualsAscii( "SCALC3" ))
1763                     eVersion = SYLK_SCALC3;
1764                 bMyDoc = (eVersion <= SYLK_OWN);
1765             }
1766             else if( cTag == 'E' )                      // Ende
1767                 break;
1768         }
1769         if( !bData )
1770         {
1771             aRange.aEnd.SetCol( nEndCol );
1772             aRange.aEnd.SetRow( nEndRow );
1773             bOk = StartPaste();
1774             bData = sal_True;
1775         }
1776         else
1777             break;
1778     }
1779 
1780     EndPaste();
1781     return bOk;
1782 }
1783 
1784 
Doc2Sylk(SvStream & rStrm)1785 sal_Bool ScImportExport::Doc2Sylk( SvStream& rStrm )
1786 {
1787     SCCOL nCol;
1788     SCROW nRow;
1789     SCCOL nStartCol = aRange.aStart.Col();
1790     SCROW nStartRow = aRange.aStart.Row();
1791     SCCOL nEndCol = aRange.aEnd.Col();
1792     SCROW nEndRow = aRange.aEnd.Row();
1793     String aCellStr;
1794     String aValStr;
1795     lcl_WriteSimpleString( rStrm,
1796             String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
1797     WriteUnicodeOrByteEndl( rStrm );
1798 
1799     for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1800     {
1801         for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1802         {
1803             String aBufStr;
1804             double nVal;
1805             sal_Bool bForm = sal_False;
1806             SCROW r = nRow - nStartRow + 1;
1807             SCCOL c = nCol - nStartCol + 1;
1808             ScBaseCell* pCell;
1809             pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell );
1810             CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE);
1811             switch( eType )
1812             {
1813                 case CELLTYPE_FORMULA:
1814                     bForm = bFormulas;
1815                     if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1816                         goto hasvalue;
1817                     else
1818                         goto hasstring;
1819 
1820                 case CELLTYPE_VALUE:
1821                 hasvalue:
1822                     pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
1823 
1824                     aValStr = ::rtl::math::doubleToUString( nVal,
1825                             rtl_math_StringFormat_Automatic,
1826                             rtl_math_DecimalPlaces_Max, '.', sal_True );
1827 
1828                     aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1829                     aBufStr += String::CreateFromInt32( c );
1830                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1831                     aBufStr += String::CreateFromInt32( r );
1832                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1833                     aBufStr += aValStr;
1834                     lcl_WriteSimpleString( rStrm, aBufStr );
1835                     goto checkformula;
1836 
1837                 case CELLTYPE_STRING:
1838                 case CELLTYPE_EDIT:
1839                 hasstring:
1840                     pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
1841                     aCellStr.SearchAndReplaceAll( _LF, SYLK_LF );
1842 
1843                     aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1844                     aBufStr += String::CreateFromInt32( c );
1845                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1846                     aBufStr += String::CreateFromInt32( r );
1847                     aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1848                     lcl_WriteSimpleString( rStrm, aBufStr );
1849                     lcl_WriteString( rStrm, aCellStr, '"', ';' );
1850 
1851                 checkformula:
1852                     if( bForm )
1853                     {
1854                         const ScFormulaCell* pFCell =
1855                             static_cast<const ScFormulaCell*>(pCell);
1856                         switch ( pFCell->GetMatrixFlag() )
1857                         {
1858                             case MM_REFERENCE :
1859                                 aCellStr.Erase();
1860                             break;
1861                             default:
1862                                 pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
1863                                 /* FIXME: do we want GRAM_ODFF_A1 instead? At
1864                                  * the end it probably should be
1865                                  * GRAM_ODFF_R1C1, since R1C1 is what Excel
1866                                  * writes in SYLK. */
1867                         }
1868                         if ( pFCell->GetMatrixFlag() != MM_NONE &&
1869                                 aCellStr.Len() > 2 &&
1870                                 aCellStr.GetChar(0) == '{' &&
1871                                 aCellStr.GetChar(aCellStr.Len()-1) == '}' )
1872                         {   // cut off matrix {} characters
1873                             aCellStr.Erase(aCellStr.Len()-1,1);
1874                             aCellStr.Erase(0,1);
1875                         }
1876                         if ( aCellStr.GetChar(0) == '=' )
1877                             aCellStr.Erase(0,1);
1878                         String aPrefix;
1879                         switch ( pFCell->GetMatrixFlag() )
1880                         {
1881                             case MM_FORMULA :
1882                             {   // diff expression with 'M' M$-extension
1883                                 SCCOL nC;
1884                                 SCROW nR;
1885                                 pFCell->GetMatColsRows( nC, nR );
1886                                 nC += c - 1;
1887                                 nR += r - 1;
1888                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
1889                                 aPrefix += String::CreateFromInt32( nR );
1890                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1891                                 aPrefix += String::CreateFromInt32( nC );
1892                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
1893                             }
1894                             break;
1895                             case MM_REFERENCE :
1896                             {   // diff expression with 'I' M$-extension
1897                                 ScAddress aPos;
1898                                 pFCell->GetMatrixOrigin( aPos );
1899                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
1900                                 aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 );
1901                                 aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
1902                                 aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 );
1903                             }
1904                             break;
1905                             default:
1906                                 // formula Expression
1907                                 aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
1908                         }
1909                         lcl_WriteSimpleString( rStrm, aPrefix );
1910                         if ( aCellStr.Len() )
1911                             lcl_WriteString( rStrm, aCellStr, 0, ';' );
1912                     }
1913                     WriteUnicodeOrByteEndl( rStrm );
1914                     break;
1915 
1916                 default:
1917                 {
1918                     // added to avoid warnings
1919                 }
1920             }
1921         }
1922     }
1923     lcl_WriteSimpleString( rStrm, String( 'E' ) );
1924     WriteUnicodeOrByteEndl( rStrm );
1925     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1926 }
1927 
1928 
Doc2HTML(SvStream & rStrm,const String & rBaseURL)1929 sal_Bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL )
1930 {
1931     // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
1932     ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
1933         aStreamPath, aNonConvertibleChars );
1934     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1935 }
1936 
Doc2RTF(SvStream & rStrm)1937 sal_Bool ScImportExport::Doc2RTF( SvStream& rStrm )
1938 {
1939     //  CharSet is ignored in ScExportRTF
1940     ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
1941     return sal_Bool( rStrm.GetError() == SVSTREAM_OK );
1942 }
1943 
1944 
Doc2Dif(SvStream & rStrm)1945 sal_Bool ScImportExport::Doc2Dif( SvStream& rStrm )
1946 {
1947     // for DIF in the clipboard, IBM_850 is always used
1948     ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
1949     return sal_True;
1950 }
1951 
1952 
Dif2Doc(SvStream & rStrm)1953 sal_Bool ScImportExport::Dif2Doc( SvStream& rStrm )
1954 {
1955     SCTAB nTab = aRange.aStart.Tab();
1956     ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
1957     pImportDoc->InitUndo( pDoc, nTab, nTab );
1958 
1959     // for DIF in the clipboard, IBM_850 is always used
1960     ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
1961 
1962     SCCOL nEndCol;
1963     SCROW nEndRow;
1964     pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
1965     // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start
1966     if ( nEndCol < aRange.aStart.Col() )
1967         nEndCol = aRange.aStart.Col();
1968     if ( nEndRow < aRange.aStart.Row() )
1969         nEndRow = aRange.aStart.Row();
1970     aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
1971 
1972     sal_Bool bOk = StartPaste();
1973     if (bOk)
1974     {
1975         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
1976         pDoc->DeleteAreaTab( aRange, nFlags );
1977         pImportDoc->CopyToDocument( aRange, nFlags, sal_False, pDoc );
1978         EndPaste();
1979     }
1980 
1981     delete pImportDoc;
1982 
1983     return bOk;
1984 }
1985 
1986 
RTF2Doc(SvStream & rStrm,const String & rBaseURL)1987 sal_Bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL )
1988 {
1989     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
1990     if (!pImp)
1991         return false;
1992     pImp->Read( rStrm, rBaseURL );
1993     aRange = pImp->GetRange();
1994 
1995     sal_Bool bOk = StartPaste();
1996     if (bOk)
1997     {
1998         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
1999         pDoc->DeleteAreaTab( aRange, nFlags );
2000         pImp->WriteToDocument();
2001         EndPaste();
2002     }
2003     delete pImp;
2004     return bOk;
2005 }
2006 
2007 
HTML2Doc(SvStream & rStrm,const String & rBaseURL)2008 sal_Bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL )
2009 {
2010     ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, sal_True);
2011     if (!pImp)
2012         return false;
2013     pImp->Read( rStrm, rBaseURL );
2014     aRange = pImp->GetRange();
2015 
2016     sal_Bool bOk = StartPaste();
2017     if (bOk)
2018     {
2019         // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2020         // a Draw Layer but no Draw View -> create Draw Layer and View here
2021         if (pDocSh)
2022             pDocSh->MakeDrawLayer();
2023 
2024         sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2025         pDoc->DeleteAreaTab( aRange, nFlags );
2026         pImp->WriteToDocument();
2027         EndPaste();
2028     }
2029     delete pImp;
2030     return bOk;
2031 }
2032 
2033 #define RETURN_ERROR { return eERR_INTERN; }
2034 class ScFormatFilterMissing : public ScFormatFilterPlugin {
2035   public:
ScFormatFilterMissing()2036     ScFormatFilterMissing()
2037     {
2038       OSL_ASSERT ("Missing file filters");
2039     }
ScImportLotus123(SfxMedium &,ScDocument *,CharSet)2040     virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR
2041     virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
2042     virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
2043     virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
2044     virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
2045                  const CharSet, sal_uInt32 ) RETURN_ERROR
2046     virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR
2047     virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, sal_Bool, SvNumberFormatter*, bool ) RETURN_ERROR
2048 
2049     virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
CreateHTMLImport(ScDocument *,const String &,const ScRange &,sal_Bool)2050     virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, sal_Bool ) { return NULL; }
GetHTMLRangeNameList(ScDocument *,const String &)2051     virtual String         GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); }
2052 
2053 #if ENABLE_LOTUS123_EXPORT
2054     virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR
2055 #endif
2056     virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR
2057     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR
2058     virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR
2059     virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, sal_Bool,
2060                   const String&, String& ) RETURN_ERROR
2061     virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR
2062 };
2063 
thisModule()2064 extern "C" { static void SAL_CALL thisModule() {} }
2065 typedef ScFormatFilterPlugin * (*FilterFn)(void);
Get()2066 ScFormatFilterPlugin &ScFormatFilter::Get()
2067 {
2068     static ScFormatFilterPlugin *plugin;
2069 
2070     if (plugin != NULL)
2071         return *plugin;
2072 
2073     static ::osl::Module aModule;
2074     if ( aModule.loadRelative( &thisModule,
2075                    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) )
2076     {
2077     oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) );
2078     if (fn != NULL)
2079         plugin = reinterpret_cast<FilterFn>(fn)();
2080     }
2081     if (plugin == NULL)
2082         plugin = new ScFormatFilterMissing();
2083 
2084     return *plugin;
2085 }
2086