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