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() )
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