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