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