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