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