LibreOffice Module sc (master) 1
impex.cxx
Go to the documentation of this file.
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
22#include <i18nutil/unicode.hxx>
23#include <sot/formats.hxx>
24#include <sfx2/mieclip.hxx>
25#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
26#include <sal/log.hxx>
28#include <osl/module.hxx>
29#include <o3tl/string_view.hxx>
30
31#include <global.hxx>
32#include <docsh.hxx>
33#include <undoblk.hxx>
34#include <rangenam.hxx>
35#include <tabvwsh.hxx>
36#include <filter.hxx>
37#include <asciiopt.hxx>
38#include <formulacell.hxx>
39#include <cellform.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#include <cellvalue.hxx>
52#include <tokenarray.hxx>
53#include <documentimport.hxx>
54#include <refundo.hxx>
55#include <mtvelements.hxx>
56
57#include <globstr.hrc>
58#include <scresid.hxx>
59#include <o3tl/safeint.hxx>
60#include <tools/svlibrary.h>
62#include <vcl/svapp.hxx>
63#include <vcl/weld.hxx>
64#include <editeng/editobj.hxx>
65#include <svl/numformat.hxx>
66#include <rtl/character.hxx>
67#include <rtl/math.hxx>
69
70#include <memory>
71#include <string_view>
72
73#include <unicode/uchar.h>
74
75#include <osl/endian.h>
76
77// We don't want to end up with 2GB read in one line just because of malformed
78// multiline fields, so chop it _somewhere_, which is twice supported columns
79// times arbitrary maximum cell content length, 2*1024*64K=128M, and because
80// it's sal_Unicode that's 256MB. If it's 2GB of data without LF we're out of
81// luck anyway.
84
85namespace
86{
87 const char SYLK_LF[] = "\x1b :";
88
89 bool lcl_IsEndianSwap( const SvStream& rStrm )
90 {
91 #ifdef OSL_BIGENDIAN
92 return rStrm.GetEndian() != SvStreamEndian::BIG;
93 #else
94 return rStrm.GetEndian() != SvStreamEndian::LITTLE;
95 #endif
96 }
97}
98
99namespace {
100
101enum class SylkVersion
102{
103 SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
104 OOO32, // Correct strings, plus multiline content.
105 OWN, // Place our new versions, if any, before this value.
106 OTHER // Assume that aliens wrote correct strings.
107};
108
109}
110
111// Whole document without Undo
113 : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
114 nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
115 cSep( '\t' ), cStr( '"' ),
116 bFormulas( false ), bIncludeFiltered( true ),
117 bAll( true ), bSingle( true ), bUndo( false ),
118 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
119 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ), mbIncludeBOM(false)
120{
121 pUndoDoc = nullptr;
122 pExtOptions = nullptr;
123}
124
125// Insert am current cell without range(es)
127 : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
128 aRange( rPt ),
129 nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
130 cSep( '\t' ), cStr( '"' ),
131 bFormulas( false ), bIncludeFiltered( true ),
132 bAll( false ), bSingle( true ), bUndo( pDocSh != nullptr ),
133 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
134 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ), mbIncludeBOM(false)
135{
136 pUndoDoc = nullptr;
137 pExtOptions = nullptr;
138}
139
140// ctor with a range is only used for export
143 : pDocSh( dynamic_cast<ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
144 aRange( rRange ),
145 nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
146 cSep( '\t' ), cStr( '"' ),
147 bFormulas( false ), bIncludeFiltered( true ),
148 bAll( false ), bSingle( false ), bUndo( pDocSh != nullptr ),
149 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
150 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ), mbIncludeBOM(false)
151{
152 pUndoDoc = nullptr;
153 pExtOptions = nullptr;
154 // Only one sheet (table) supported
156}
157
158// Evaluate input string - either range, cell or the whole document (when error)
159// If a View exists, the TabNo of the view will be used.
160ScImportExport::ScImportExport( ScDocument& r, const OUString& rPos )
161 : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
162 nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
163 cSep( '\t' ), cStr( '"' ),
164 bFormulas( false ), bIncludeFiltered( true ),
165 bAll( false ), bSingle( true ), bUndo( pDocSh != nullptr ),
166 bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
167 mbApi( true ), mbImportBroadcast(false), mbOverwriting( false ), mbIncludeBOM(false)
168{
169 pUndoDoc = nullptr;
170 pExtOptions = nullptr;
171
173 aRange.aStart.SetTab( nTab );
174 OUString aPos( rPos );
175 // Named range?
176 ScRangeName* pRange = rDoc.GetRangeName();
177 if (pRange)
178 {
179 const ScRangeData* pData = pRange->findByUpperName(ScGlobal::getCharClass().uppercase(aPos));
180 if (pData)
181 {
182 if( pData->HasType( ScRangeData::Type::RefArea )
183 || pData->HasType( ScRangeData::Type::AbsArea )
184 || pData->HasType( ScRangeData::Type::AbsPos ) )
185 {
186 aPos = pData->GetSymbol();
187 }
188 }
189 }
191 // Range?
192 if (aRange.Parse(aPos, rDoc, eConv) & ScRefFlags::VALID)
193 bSingle = false;
194 // Cell?
195 else if (aRange.aStart.Parse(aPos, rDoc, eConv) & ScRefFlags::VALID)
197 else
198 bAll = true;
199}
200
201ScImportExport::~ScImportExport() COVERITY_NOEXCEPT_FALSE
202{
203 pUndoDoc.reset();
204 pExtOptions.reset();
205}
206
208{
209 if ( pExtOptions )
210 *pExtOptions = rOpt;
211 else
212 pExtOptions.reset(new ScAsciiOptions( rOpt ));
213
214 // "normal" Options
215
217 cStr = rOpt.GetTextSep();
218}
219
220void ScImportExport::SetFilterOptions(const OUString& rFilterOptions)
221{
222 maFilterOptions = rFilterOptions;
223}
224
226{
227 return nFormat == SotClipboardFormatId::STRING
228 || nFormat == SotClipboardFormatId::STRING_TSVC
229 || nFormat == SotClipboardFormatId::SYLK
230 || nFormat == SotClipboardFormatId::LINK
231 || nFormat == SotClipboardFormatId::HTML
232 || nFormat == SotClipboardFormatId::HTML_SIMPLE
233 || nFormat == SotClipboardFormatId::DIF;
234}
235
236// Prepare for Undo
238{
239 if ( !bAll )
240 {
241 ScEditableTester aTester( rDoc, aRange );
242 if ( !aTester.IsEditable() )
243 {
244 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
245 VclMessageType::Info, VclButtonsType::Ok,
246 ScResId(aTester.GetMessageId())));
247 xInfoBox->run();
248 return false;
249 }
250 }
251 if( bUndo && pDocSh && rDoc.IsUndoEnabled())
252 {
253 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
254 pUndoDoc->InitUndo( rDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
256 }
257 return true;
258}
259
260// Create Undo/Redo actions, Invalidate/Repaint
261void ScImportExport::EndPaste(bool bAutoRowHeight)
262{
263 bool bHeight = bAutoRowHeight && pDocSh && pDocSh->AdjustRowHeight(
265
266 if( pUndoDoc && rDoc.IsUndoEnabled() && pDocSh )
267 {
269 pRedoDoc->InitUndo( rDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
271 ScMarkData aDestMark(pRedoDoc->GetSheetLimits());
272 aDestMark.SetMarkArea(aRange);
274 std::make_unique<ScUndoPaste>(pDocSh, aRange, aDestMark, std::move(pUndoDoc), std::move(pRedoDoc), InsertDeleteFlags::ALL, nullptr));
275 }
276 pUndoDoc.reset();
277 if( pDocSh )
278 {
279 if (!bHeight)
282 }
284 if ( pViewSh )
285 pViewSh->UpdateInputHandler();
286
287}
288
289bool ScImportExport::ExportData( std::u16string_view rMimeType,
290 css::uno::Any & rValue )
291{
292 SvMemoryStream aStrm;
294 if (fmtId == SotClipboardFormatId::STRING)
295 aStrm.SetStreamCharSet(RTL_TEXTENCODING_UNICODE);
296 // mba: no BaseURL for data exchange
297 if (ExportStream(aStrm, OUString(), fmtId))
298 {
299 if (fmtId == SotClipboardFormatId::STRING)
300 {
301 assert(aStrm.TellEnd() % sizeof(sal_Unicode) == 0);
302 rValue <<= OUString(static_cast<const sal_Unicode*>(aStrm.GetData()),
303 aStrm.TellEnd() / sizeof(sal_Unicode));
304 }
305 else
306 {
307 aStrm.WriteUChar(0);
308 rValue <<= css::uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(aStrm.GetData()),
309 aStrm.TellEnd());
310 }
311 return true;
312 }
313 return false;
314}
315
316bool ScImportExport::ImportString( const OUString& rText, SotClipboardFormatId nFmt )
317{
318 switch ( nFmt )
319 {
320 // formats supporting unicode
321 case SotClipboardFormatId::STRING :
322 case SotClipboardFormatId::STRING_TSVC :
323 {
324 ScImportStringStream aStrm( rText);
325 return ImportStream( aStrm, OUString(), nFmt );
326 // ImportStream must handle RTL_TEXTENCODING_UNICODE
327 }
328 default:
329 {
330 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
331 OString aTmp( rText.getStr(), rText.getLength(), eEnc );
332 SvMemoryStream aStrm( const_cast<char *>(aTmp.getStr()), aTmp.getLength() * sizeof(char), StreamMode::READ );
333 aStrm.SetStreamCharSet( eEnc );
334 SetNoEndianSwap( aStrm );
335 return ImportStream( aStrm, OUString(), nFmt );
336 }
337 }
338}
339
341{
342 if ( nFmt != SotClipboardFormatId::STRING && nFmt != SotClipboardFormatId::STRING_TSVC )
343 {
344 SAL_WARN("sc.ui", "ScImportExport::ExportString: Unicode not supported for other formats than SotClipboardFormatId::STRING[_TSV]");
345 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
346 OString aTmp;
347 bool bOk = ExportByteString( aTmp, eEnc, nFmt );
348 rText = OStringToOUString( aTmp, eEnc );
349 return bOk;
350 }
351 // nSizeLimit not needed for OUString
352
353 SvMemoryStream aStrm;
354 aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
355 SetNoEndianSwap( aStrm );
356 // mba: no BaseURL for data exc
357 if( ExportStream( aStrm, OUString(), nFmt ) )
358 {
359 aStrm.WriteUInt16( 0 );
360 rText = OUString( static_cast<const sal_Unicode*>(aStrm.GetData()) );
361 return true;
362 }
363 rText.clear();
364 return false;
365
366 // ExportStream must handle RTL_TEXTENCODING_UNICODE
367}
368
369bool ScImportExport::ExportByteString( OString& rText, rtl_TextEncoding eEnc, SotClipboardFormatId nFmt )
370{
371 OSL_ENSURE( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
372 if ( eEnc == RTL_TEXTENCODING_UNICODE )
373 eEnc = osl_getThreadTextEncoding();
374
375 if (!nSizeLimit)
377
378 SvMemoryStream aStrm;
379 aStrm.SetStreamCharSet( eEnc );
380 SetNoEndianSwap( aStrm );
381 // mba: no BaseURL for data exchange
382 if( ExportStream( aStrm, OUString(), nFmt ) )
383 {
384 aStrm.WriteChar( 0 );
385 if( aStrm.TellEnd() <= nSizeLimit )
386 {
387 rText = static_cast<const char*>(aStrm.GetData());
388 return true;
389 }
390 }
391 rText.clear();
392 return false;
393}
394
395bool ScImportExport::ImportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
396{
397 if( nFmt == SotClipboardFormatId::STRING || nFmt == SotClipboardFormatId::STRING_TSVC )
398 {
399 if( ExtText2Doc( rStrm ) ) // evaluate pExtOptions
400 return true;
401 }
402 if( nFmt == SotClipboardFormatId::SYLK )
403 {
404 if( Sylk2Doc( rStrm ) )
405 return true;
406 }
407 if( nFmt == SotClipboardFormatId::DIF )
408 {
409 if( Dif2Doc( rStrm ) )
410 return true;
411 }
412 if( nFmt == SotClipboardFormatId::RTF || nFmt == SotClipboardFormatId::RICHTEXT )
413 {
414 if( RTF2Doc( rStrm, rBaseURL ) )
415 return true;
416 }
417 if( nFmt == SotClipboardFormatId::LINK )
418 return true; // Link-Import?
419 if ( nFmt == SotClipboardFormatId::HTML )
420 {
421 if( HTML2Doc( rStrm, rBaseURL ) )
422 return true;
423 }
424 if ( nFmt == SotClipboardFormatId::HTML_SIMPLE )
425 {
426 MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
427 SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
428 if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
429 return true;
430 }
431
432 return false;
433}
434
435bool ScImportExport::ExportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
436{
437 if( nFmt == SotClipboardFormatId::STRING || nFmt == SotClipboardFormatId::STRING_TSVC )
438 {
439 if( Doc2Text( rStrm ) )
440 return true;
441 }
442 if( nFmt == SotClipboardFormatId::SYLK )
443 {
444 if( Doc2Sylk( rStrm ) )
445 return true;
446 }
447 if( nFmt == SotClipboardFormatId::DIF )
448 {
449 if( Doc2Dif( rStrm ) )
450 return true;
451 }
452 if( nFmt == SotClipboardFormatId::LINK && !bAll )
453 {
454 OUString aDocName;
455 if ( rDoc.IsClipboard() )
456 aDocName = ScGlobal::GetClipDocName();
457 else
458 {
460 if (pShell)
461 aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
462 }
463
464 OSL_ENSURE( !aDocName.isEmpty(), "ClipBoard document has no name! :-/" );
465 if( !aDocName.isEmpty() )
466 {
467 // Always use Calc A1 syntax for paste link.
468 OUString aRefName;
470 if( bSingle )
472 else
473 {
474 if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
475 nFlags |= ScRefFlags::TAB2_3D;
477 }
478 OUString aAppName = Application::GetAppName();
479
480 // extra bits are used to tell the client to prefer external
481 // reference link.
482
483 WriteUnicodeOrByteString( rStrm, aAppName, true );
484 WriteUnicodeOrByteString( rStrm, aDocName, true );
485 WriteUnicodeOrByteString( rStrm, aRefName, true );
486 WriteUnicodeOrByteString( rStrm, u"calc:extref", true );
487 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
488 rStrm.WriteUInt16( 0 );
489 else
490 rStrm.WriteChar( 0 );
491 return rStrm.GetError() == ERRCODE_NONE;
492 }
493 }
494 if( nFmt == SotClipboardFormatId::HTML )
495 {
496 if( Doc2HTML( rStrm, rBaseURL ) )
497 return true;
498 }
499 if( nFmt == SotClipboardFormatId::RTF || nFmt == SotClipboardFormatId::RICHTEXT )
500 {
501 if( Doc2RTF( rStrm ) )
502 return true;
503 }
504
505 return false;
506}
507
508void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, std::u16string_view rString, bool bZero )
509{
510 rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
511 if ( eEnc == RTL_TEXTENCODING_UNICODE )
512 {
513 if ( !lcl_IsEndianSwap( rStrm ) )
514 rStrm.WriteBytes(rString.data(), rString.size() * sizeof(sal_Unicode));
515 else
516 {
517 const sal_Unicode* p = rString.data();
518 const sal_Unicode* const pStop = p + rString.size();
519 while ( p < pStop )
520 {
521 rStrm.WriteUInt16( *p );
522 }
523 }
524 if ( bZero )
525 rStrm.WriteUInt16( 0 );
526 }
527 else
528 {
529 OString aByteStr(OUStringToOString(rString, eEnc));
530 rStrm.WriteOString( aByteStr );
531 if ( bZero )
532 rStrm.WriteChar( 0 );
533 }
534}
535
536// This function could be replaced by endlub()
538{
539 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
540 { // same as endl() but unicode
541 switch ( rStrm.GetLineDelimiter() )
542 {
543 case LINEEND_CR :
544 rStrm.WriteUInt16( '\r' );
545 break;
546 case LINEEND_LF :
547 rStrm.WriteUInt16( '\n' );
548 break;
549 default:
550 rStrm.WriteUInt16( '\r' ).WriteUInt16( '\n' );
551 }
552 }
553 else
554 endl( rStrm );
555}
556
557// tdf#104927
558// http://www.unicode.org/reports/tr11/
559sal_Int32 ScImportExport::CountVisualWidth(const OUString& rStr, sal_Int32& nIdx, sal_Int32 nMaxWidth)
560{
561 sal_Int32 nWidth = 0;
562 while(nIdx < rStr.getLength() && nWidth < nMaxWidth)
563 {
564 sal_uInt32 nCode = rStr.iterateCodePoints(&nIdx);
565
566 auto nEaWidth = u_getIntPropertyValue(nCode, UCHAR_EAST_ASIAN_WIDTH);
567 if (nEaWidth == U_EA_FULLWIDTH || nEaWidth == U_EA_WIDE)
568 nWidth += 2;
569 else if (!u_getIntPropertyValue(nCode, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
570 nWidth += 1;
571 }
572
573 if (nIdx < rStr.getLength())
574 {
575 sal_Int32 nTmpIdx = nIdx;
576 sal_uInt32 nCode = rStr.iterateCodePoints(&nTmpIdx);
577
578 if (u_getIntPropertyValue(nCode, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
579 nIdx = nTmpIdx;
580 }
581 return nWidth;
582}
583
584sal_Int32 ScImportExport::CountVisualWidth(const OUString& rStr)
585{
586 sal_Int32 nIdx = 0;
587 return CountVisualWidth(rStr, nIdx, SAL_MAX_INT32);
588}
589
591{
592#ifdef OSL_BIGENDIAN
593 rStrm.SetEndian( SvStreamEndian::BIG );
594#else
595 rStrm.SetEndian( SvStreamEndian::LITTLE );
596#endif
597}
598
599static inline bool lcl_isFieldEnd( sal_Unicode c, const sal_Unicode* pSeps )
600{
601 return !c || ScGlobal::UnicodeStrChr( pSeps, c);
602}
603
604namespace {
605
606enum QuoteType
607{
608 FIELDSTART_QUOTE,
609 FIRST_QUOTE,
610 SECOND_QUOTE,
611 FIELDEND_QUOTE,
612 DONTKNOW_QUOTE
613};
614
615}
616
625static QuoteType lcl_isFieldEndQuote( const sal_Unicode* p, const sal_Unicode* pSeps, sal_Unicode& rcDetectSep )
626{
627 // Due to broken CSV generators that don't double embedded quotes check if
628 // a field separator immediately or with trailing spaces follows the quote,
629 // only then end the field, or at end of string.
630 constexpr sal_Unicode cBlank = ' ';
631 if (p[1] == cBlank && ScGlobal::UnicodeStrChr( pSeps, cBlank))
632 return FIELDEND_QUOTE;
633 // Detect a possible blank separator if it's not already in the list (which
634 // was checked right above for p[1]==cBlank).
635 const bool bBlankSep = (p[1] == cBlank && !rcDetectSep && p[2] && p[2] != cBlank);
636 while (p[1] == cBlank)
637 ++p;
638 if (lcl_isFieldEnd( p[1], pSeps))
639 return FIELDEND_QUOTE;
640 // Extended separator detection after a closing quote (with or without
641 // blanks). Note that nQuotes is incremented *after* the call so is not yet
642 // even here, and that with separator detection we reach here only if
643 // lcl_isEscapedOrFieldEndQuote() did not already detect FIRST_QUOTE or
644 // SECOND_QUOTE for an escaped embedded quote, thus nQuotes does not have
645 // to be checked.
646 if (!rcDetectSep)
647 {
648 constexpr sal_Unicode vSep[] = { ',', '\t', ';' };
649 for (const sal_Unicode c : vSep)
650 {
651 if (p[1] == c)
652 {
653 rcDetectSep = c;
654 return FIELDEND_QUOTE;
655 }
656 }
657 }
658 // Blank separator is least significant, after others.
659 if (bBlankSep)
660 {
661 rcDetectSep = cBlank;
662 return FIELDEND_QUOTE;
663 }
664 return DONTKNOW_QUOTE;
665}
666
688static QuoteType lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes, const sal_Unicode* p,
689 const sal_Unicode* pSeps, sal_Unicode cStr, sal_Unicode& rcDetectSep )
690{
691 if ((nQuotes & 1) == 0)
692 {
693 if (p[-1] == cStr)
694 return SECOND_QUOTE;
695 else
696 {
697 SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
698 return FIELDSTART_QUOTE;
699 }
700 }
701 if (p[1] == cStr)
702 return FIRST_QUOTE;
703 return lcl_isFieldEndQuote( p, pSeps, rcDetectSep);
704}
705
710static bool lcl_appendLineData( OUString& rField, const sal_Unicode* p1, const sal_Unicode* p2 )
711{
712 if (rField.getLength() + (p2 - p1) <= nArbitraryCellLengthLimit)
713 {
714 rField += std::u16string_view( p1, p2 - p1 );
715 return true;
716 }
717 else
718 {
719 SAL_WARN( "sc", "lcl_appendLineData: data overflow");
720 rField += std::u16string_view( p1, nArbitraryCellLengthLimit - rField.getLength() );
721 return false;
722 }
723}
724
725namespace {
726
727enum class DoubledQuoteMode
728{
729 KEEP_ALL, // both are taken, additionally start and end quote are included in string
730 ESCAPE, // escaped quote, one is taken, one ignored
731};
732
733}
734
753static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rField,
754 const sal_Unicode* pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool& rbOverflowCell )
755{
756 OUString aString;
757 bool bClosingQuote = (eMode == DoubledQuoteMode::KEEP_ALL);
758 const sal_Unicode* const pStart = p;
759 if (eMode != DoubledQuoteMode::KEEP_ALL)
760 p++;
761 bool bCont;
762 do
763 {
764 bCont = false;
765 const sal_Unicode* p0 = p;
766 for( ;; )
767 {
768 if (!*p)
769 {
770 // Encountering end of data after an opening quote is not a
771 // quoted string, ReadCsvLine() concatenated lines with '\n'
772 // for a properly quoted embedded linefeed.
773 if (eMode == DoubledQuoteMode::KEEP_ALL)
774 // Caller would append that data anyway, so we can do it
775 // already here.
776 break;
777
778 return pStart;
779 }
780
781 if( *p == cStr )
782 {
783 if ( *++p != cStr )
784 {
785 // break or continue for loop
786 if (eMode == DoubledQuoteMode::ESCAPE)
787 {
788 sal_Unicode cDetectSep = 0xffff; // No separator detection here.
789 if (lcl_isFieldEndQuote( p-1, pSeps, cDetectSep) == FIELDEND_QUOTE)
790 {
791 bClosingQuote = true;
792 break;
793 }
794 else
795 continue;
796 }
797 else
798 break;
799 }
800 // doubled quote char
801 switch ( eMode )
802 {
803 case DoubledQuoteMode::KEEP_ALL :
804 p++; // both for us (not breaking for-loop)
805 break;
806 case DoubledQuoteMode::ESCAPE :
807 p++; // one for us (breaking for-loop)
808 bCont = true; // and more
809 break;
810 }
811 if ( eMode == DoubledQuoteMode::ESCAPE )
812 break;
813 }
814 else
815 p++;
816 }
817 if ( p0 < p )
818 {
819 if (!lcl_appendLineData( aString, p0, ((eMode != DoubledQuoteMode::KEEP_ALL && (*p || *(p-1) == cStr)) ? p-1 : p)))
820 rbOverflowCell = true;
821 }
822 } while ( bCont );
823
824 if (!bClosingQuote)
825 return pStart;
826
827 if (!aString.isEmpty())
828 rField += aString;
829
830 return p;
831}
832
833static void lcl_UnescapeSylk( OUString & rString, SylkVersion eVersion )
834{
835 // Older versions didn't escape the semicolon.
836 // Older versions quoted the string and doubled embedded quotes, but not
837 // the semicolons, which was plain wrong.
838 if (eVersion >= SylkVersion::OOO32)
839 rString = rString.replaceAll(";;", ";");
840 else
841 rString = rString.replaceAll("\"\"", "\"");
842
843 rString = rString.replaceAll(SYLK_LF, "\n");
844}
845
847 OUString& rString, SylkVersion eVersion )
848{
849 const sal_Unicode* pStartQuote = p;
850 const sal_Unicode* pEndQuote = nullptr;
851 while( *(++p) )
852 {
853 if( *p == '"' )
854 {
855 pEndQuote = p;
856 if (eVersion >= SylkVersion::OOO32)
857 {
858 if (*(p+1) == ';')
859 {
860 if (*(p+2) == ';')
861 {
862 p += 2; // escaped ';'
863 pEndQuote = nullptr;
864 }
865 else
866 break; // end field
867 }
868 }
869 else
870 {
871 if (*(p+1) == '"')
872 {
873 ++p; // escaped '"'
874 pEndQuote = nullptr;
875 }
876 else if (*(p+1) == ';')
877 break; // end field
878 }
879 }
880 }
881 if (!pEndQuote)
882 pEndQuote = p; // Take all data as string.
883 rString += std::u16string_view(pStartQuote + 1, pEndQuote - pStartQuote - 1 );
884 lcl_UnescapeSylk( rString, eVersion);
885 return p;
886}
887
889 OUString& rString, SylkVersion eVersion )
890{
891 const sal_Unicode* pStart = p;
892 if (eVersion >= SylkVersion::OOO32)
893 {
894 while (*p)
895 {
896 if (*p == ';')
897 {
898 if (*(p+1) == ';')
899 ++p; // escaped ';'
900 else
901 break; // end field
902 }
903 ++p;
904 }
905 rString += std::u16string_view( pStart, p - pStart);
906 lcl_UnescapeSylk( rString, eVersion);
907 }
908 else
909 {
910 // Nasty. If in old versions the formula contained a semicolon, it was
911 // quoted and embedded quotes were doubled, but semicolons were not. If
912 // there was no semicolon, it could still contain quotes and doubled
913 // embedded quotes if it was something like ="a""b", which was saved as
914 // E"a""b" as is and has to be preserved, even if older versions
915 // couldn't even load it correctly. However, theoretically another
916 // field might follow and thus the line contain a semicolon again, such
917 // as ...;E"a""b";...
918 bool bQuoted = false;
919 if (*p == '"')
920 {
921 // May be a quoted expression or just a string constant expression
922 // with quotes.
923 while (*(++p))
924 {
925 if (*p == '"')
926 {
927 if (*(p+1) == '"')
928 ++p; // escaped '"'
929 else
930 break; // closing '"', had no ';' yet
931 }
932 else if (*p == ';')
933 {
934 bQuoted = true; // ';' within quoted expression
935 break;
936 }
937 }
938 p = pStart;
939 }
940 if (bQuoted)
941 p = lcl_ScanSylkString( p, rString, eVersion);
942 else
943 {
944 while (*p && *p != ';')
945 ++p;
946 rString += std::u16string_view( pStart, p - pStart);
947 }
948 }
949 return p;
950}
951
952static void lcl_WriteString( SvStream& rStrm, OUString& rString, sal_Unicode cQuote, sal_Unicode cEsc )
953{
954 if (cEsc)
955 {
956 // the goal is to replace cStr by cStr+cStr
957 OUString strFrom(cEsc);
958 OUString strTo = strFrom + strFrom;
959 rString = rString.replaceAll(strFrom, strTo);
960 }
961
962 if (cQuote)
963 {
964 rString = OUStringChar(cQuote) + rString + OUStringChar(cQuote);
965 }
966
968}
969
970static void lcl_WriteSimpleString( SvStream& rStrm, std::u16string_view rString )
971{
973}
974
976{
977 bool bOk = true;
978
979 sal_Unicode pSeps[2];
980 pSeps[0] = cSep;
981 pSeps[1] = 0;
982
983 ScSetStringParam aSetStringParam;
984 aSetStringParam.mbCheckLinkFormula = true;
985
986 SCCOL nStartCol = aRange.aStart.Col();
987 SCROW nStartRow = aRange.aStart.Row();
988 SCCOL nEndCol = aRange.aEnd.Col();
989 SCROW nEndRow = aRange.aEnd.Row();
990 sal_uInt64 nOldPos = rStrm.Tell();
992 bool bData = !bSingle;
993 if( !bSingle)
994 bOk = StartPaste();
995
996 while( bOk )
997 {
998 OUString aLine;
999 OUString aCell;
1000 SCROW nRow = nStartRow;
1001 rStrm.Seek( nOldPos );
1002 for( ;; )
1003 {
1005 // tdf#125440 When inserting tab separated string, consider quotes as field markers
1006 DoubledQuoteMode mode = aLine.indexOf("\t") >= 0 ? DoubledQuoteMode::ESCAPE : DoubledQuoteMode::KEEP_ALL;
1007 if( rStrm.eof() )
1008 break;
1009 SCCOL nCol = nStartCol;
1010 const sal_Unicode* p = aLine.getStr();
1011 while( *p )
1012 {
1013 aCell.clear();
1014 const sal_Unicode* q = p;
1015 if (*p == cStr)
1016 {
1017 // Look for a pairing quote.
1018 q = p = lcl_ScanString( p, aCell, pSeps, cStr, mode, bOverflowCell );
1019 }
1020 // All until next separator.
1021 while (*p && *p != cSep)
1022 ++p;
1023 if (!lcl_appendLineData( aCell, q, p))
1024 bOverflowCell = true; // display warning on import
1025 if (*p)
1026 ++p;
1027 if (rDoc.ValidCol(nCol) && rDoc.ValidRow(nRow) )
1028 {
1029 if( bSingle )
1030 {
1031 if (nCol>nEndCol) nEndCol = nCol;
1032 if (nRow>nEndRow) nEndRow = nRow;
1033 }
1034 if( bData && nCol <= nEndCol && nRow <= nEndRow )
1035 rDoc.SetString( nCol, nRow, aRange.aStart.Tab(), aCell, &aSetStringParam );
1036 }
1037 else // too many columns/rows
1038 {
1039 if (!rDoc.ValidRow(nRow))
1040 bOverflowRow = true; // display warning on import
1041 if (!rDoc.ValidCol(nCol))
1042 bOverflowCol = true; // display warning on import
1043 }
1044 ++nCol;
1045 }
1046 ++nRow;
1047 }
1048
1049 if( !bData )
1050 {
1051 aRange.aEnd.SetCol( nEndCol );
1052 aRange.aEnd.SetRow( nEndRow );
1053 bOk = StartPaste();
1054 bData = true;
1055 }
1056 else
1057 break;
1058 }
1059
1060 EndPaste();
1061 if (bOk && mbImportBroadcast)
1062 {
1063 rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
1065 }
1066
1067 return bOk;
1068}
1069
1070// Extended Ascii-Import
1071
1072static bool lcl_PutString(
1073 ScDocumentImport& rDocImport, bool bUseDocImport,
1074 SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rStr, sal_uInt8 nColFormat,
1075 SvNumberFormatter* pFormatter, bool bDetectNumFormat, bool bDetectSciNumFormat, bool bEvaluateFormulas, bool bSkipEmptyCells,
1076 const ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
1077 const ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
1078{
1079 ScDocument& rDoc = rDocImport.getDoc();
1080 bool bMultiLine = false;
1081 if ( nColFormat == SC_COL_SKIP || !rDoc.ValidCol(nCol) || !rDoc.ValidRow(nRow) )
1082 return bMultiLine;
1083 if ( rStr.isEmpty() )
1084 {
1085 if ( !bSkipEmptyCells )
1086 { // delete destination cell
1087 if ( bUseDocImport )
1088 rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr );
1089 else
1090 rDoc.SetString( nCol, nRow, nTab, rStr );
1091 }
1092 return false;
1093 }
1094
1095 const bool bForceFormulaText = (!bEvaluateFormulas && rStr[0] == '=');
1096 if (nColFormat == SC_COL_TEXT || bForceFormulaText)
1097 {
1098 if ( bUseDocImport )
1099 {
1100 double fDummy;
1101 sal_uInt32 nIndex = 0;
1102 if (bForceFormulaText || rDoc.GetFormatTable()->IsNumberFormat(rStr, nIndex, fDummy))
1103 {
1104 // Set the format of this cell to Text.
1105 // This is only necessary for ScDocumentImport,
1106 // ScDocument::SetTextCell() forces it by ScSetStringParam.
1107 sal_uInt32 nFormat = rDoc.GetFormatTable()->GetStandardFormat(SvNumFormatType::TEXT);
1108 ScPatternAttr aNewAttrs(rDoc.GetPool());
1109 SfxItemSet& rSet = aNewAttrs.GetItemSet();
1111 rDoc.ApplyPattern(nCol, nRow, nTab, aNewAttrs);
1112 }
1113 if (ScStringUtil::isMultiline(rStr))
1114 {
1115 ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
1116 rEngine.SetTextCurrentDefaults(rStr);
1117 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
1118 return true;
1119 }
1120 else
1121 {
1122 rDocImport.setStringCell(ScAddress(nCol, nRow, nTab), rStr);
1123 return false;
1124 }
1125 }
1126 else
1127 {
1128 rDoc.SetTextCell(ScAddress(nCol, nRow, nTab), rStr);
1129 return bMultiLine;
1130 }
1131 }
1132
1133 if ( nColFormat == SC_COL_ENGLISH )
1134 {
1136
1137 SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
1138 sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
1139 double fVal;
1140 if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
1141 {
1142 // Numberformat will not be set to English
1143 if ( bUseDocImport )
1144 rDocImport.setNumericCell( ScAddress( nCol, nRow, nTab ), fVal );
1145 else
1146 rDoc.SetValue( nCol, nRow, nTab, fVal );
1147 return bMultiLine;
1148 }
1149 // else, continue with SetString
1150 }
1151 else if ( nColFormat != SC_COL_STANDARD ) // Datumformats
1152 {
1153 const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
1154 const sal_Int32 nLen = rStr.getLength();
1155 sal_Int32 nStart[nMaxNumberParts];
1156 sal_Int32 nEnd[nMaxNumberParts];
1157
1158 bool bIso;
1159 sal_uInt16 nDP, nMP, nYP;
1160 switch ( nColFormat )
1161 {
1162 case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; bIso = true; break;
1163 case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; bIso = false; break;
1164 case SC_COL_DMY:
1165 default: nDP = 0; nMP = 1; nYP = 2; bIso = false; break;
1166 }
1167
1168 sal_uInt16 nFound = 0;
1169 bool bInNum = false;
1170 for (sal_Int32 nPos = 0; nPos < nLen && (bInNum || nFound < nMaxNumberParts); ++nPos)
1171 {
1172 bool bLetter = false;
1173 if (rtl::isAsciiDigit(rStr[nPos]) ||
1174 (((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
1175 && (bLetter = ScGlobal::getCharClass().isLetterNumeric( rStr, nPos))))
1176 {
1177 if (!bInNum)
1178 {
1179 bInNum = true;
1180 nStart[nFound] = nPos;
1181 ++nFound;
1182 }
1183 nEnd[nFound-1] = nPos;
1184 if (bIso && (bLetter || (2 <= nFound && nFound <= 6 && nPos > nStart[nFound-1] + 1)))
1185 // Each M,D,h,m,s at most 2 digits.
1186 bIso = false;
1187 }
1188 else
1189 {
1190 bInNum = false;
1191 if (bIso)
1192 {
1193 // ([+-])YYYY-MM-DD([T ]hh:mm(:ss(.fff)))(([+-])TZ)
1194 // XXX NOTE: timezone is accepted here, but number
1195 // formatter parser will not, so the end result will be
1196 // type Text to preserve timezone information.
1197 switch (rStr[nPos])
1198 {
1199 case '+':
1200 if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
1201 // Accept timezone offset.
1202 ;
1203 else if (nPos > 0)
1204 // Accept one leading sign.
1205 bIso = false;
1206 break;
1207 case '-':
1208 if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
1209 // Accept timezone offset.
1210 ;
1211 else if (nFound == 0 && nPos > 0)
1212 // Accept one leading sign.
1213 bIso = false;
1214 else if (nFound < 1 || 2 < nFound || nPos != nEnd[nFound-1] + 1)
1215 // Not immediately after 1 or 1-2
1216 bIso = false;
1217 break;
1218 case 'T':
1219 case ' ':
1220 if (nFound != 3 || nPos != nEnd[nFound-1] + 1)
1221 // Not immediately after 1-2-3
1222 bIso = false;
1223 break;
1224 case ':':
1225 if (nFound < 4 || 5 < nFound || nPos != nEnd[nFound-1] + 1)
1226 // Not at 1-2-3T4:5:
1227 bIso = false;
1228 break;
1229 case '.':
1230 case ',':
1231 if (nFound != 6 || nPos != nEnd[nFound-1] + 1)
1232 // Not at 1-2-3T4:5:6.
1233 bIso = false;
1234 break;
1235 case 'Z':
1236 if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
1237 // Accept Zero timezone.
1238 ;
1239 else
1240 bIso = false;
1241 break;
1242 default:
1243 bIso = false;
1244 }
1245 }
1246 }
1247 }
1248
1249 if (nFound < 3)
1250 bIso = false;
1251
1252 if (bIso)
1253 {
1254 // Leave conversion and detection of various possible number
1255 // formats to the number formatter. ISO is recognized in any locale
1256 // so we can directly use the document's formatter.
1257 sal_uInt32 nFormat = 0;
1258 double fVal = 0.0;
1259 SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
1260 if (pDocFormatter->IsNumberFormat( rStr, nFormat, fVal))
1261 {
1262 if (pDocFormatter->GetType(nFormat) & SvNumFormatType::DATE)
1263 {
1264 ScAddress aPos(nCol,nRow,nTab);
1265 if (bUseDocImport)
1266 rDocImport.setNumericCell(aPos, fVal);
1267 else
1268 rDoc.SetValue(aPos, fVal);
1269 rDoc.SetNumberFormat(aPos, nFormat);
1270
1271 return bMultiLine; // success
1272 }
1273 }
1274 // If we reach here it is type Text (e.g. timezone or trailing
1275 // characters). Handled below.
1276 }
1277
1278 if ( nFound == 1 )
1279 {
1280 // try to break one number (without separators) into date fields
1281
1282 sal_Int32 nDateStart = nStart[0];
1283 sal_Int32 nDateLen = nEnd[0] + 1 - nDateStart;
1284
1285 if ( nDateLen >= 5 && nDateLen <= 8 &&
1286 ScGlobal::getCharClass().isNumeric( rStr.copy( nDateStart, nDateLen ) ) )
1287 {
1288 // 6 digits: 2 each for day, month, year
1289 // 8 digits: 4 for year, 2 each for day and month
1290 // 5 or 7 digits: first field is shortened by 1
1291
1292 bool bLongYear = ( nDateLen >= 7 );
1293 bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
1294
1295 sal_uInt16 nFieldStart = nDateStart;
1296 for (sal_uInt16 nPos=0; nPos<3; nPos++)
1297 {
1298 sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits
1299 if ( bLongYear && nPos == nYP )
1300 nFieldEnd += 2; // 2 extra digits for long year
1301 if ( bShortFirst && nPos == 0 )
1302 --nFieldEnd; // first field shortened?
1303
1304 nStart[nPos] = nFieldStart;
1305 nEnd[nPos] = nFieldEnd;
1306 nFieldStart = nFieldEnd + 1;
1307 }
1308 nFound = 3;
1309 }
1310 }
1311
1312 if (!bIso && nFound >= 3)
1313 {
1314 using namespace ::com::sun::star;
1315 bool bSecondCal = false;
1316 sal_uInt16 nDay = static_cast<sal_uInt16>(o3tl::toInt32(rStr.subView( nStart[nDP], nEnd[nDP]+1-nStart[nDP] )));
1317 sal_uInt16 nYear = static_cast<sal_uInt16>(o3tl::toInt32(rStr.subView( nStart[nYP], nEnd[nYP]+1-nStart[nYP] )));
1318 OUString aMStr = rStr.copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1319 sal_Int16 nMonth = static_cast<sal_Int16>(aMStr.toInt32());
1320 if (!nMonth)
1321 {
1322 static constexpr OUStringLiteral aSepShortened = u"SEP";
1323 uno::Sequence< i18n::CalendarItem2 > xMonths;
1324 sal_Int32 i, nMonthCount;
1325 // first test all month names from local international
1326 xMonths = rCalendar.getMonths();
1327 nMonthCount = xMonths.getLength();
1328 for (i=0; i<nMonthCount && !nMonth; i++)
1329 {
1330 if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
1331 rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
1332 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1333 else if ( i == 8 && rTransliteration.isEqual( "SEPT",
1334 xMonths[i].AbbrevName ) &&
1335 rTransliteration.isEqual( aMStr, aSepShortened ) )
1336 { // correct English abbreviation is SEPT,
1337 // but data mostly contains SEP only
1338 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1339 }
1340 }
1341 // if none found, then test english month names
1342 if ( !nMonth && pSecondCalendar && pSecondTransliteration )
1343 {
1344 xMonths = pSecondCalendar->getMonths();
1345 nMonthCount = xMonths.getLength();
1346 for (i=0; i<nMonthCount && !nMonth; i++)
1347 {
1348 if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
1349 pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
1350 {
1351 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1352 bSecondCal = true;
1353 }
1354 else if ( i == 8 && pSecondTransliteration->isEqual(
1355 aMStr, aSepShortened ) )
1356 { // correct English abbreviation is SEPT,
1357 // but data mostly contains SEP only
1358 nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1359 bSecondCal = true;
1360 }
1361 }
1362 }
1363 }
1364
1365 SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
1366 if ( nYear < 100 )
1367 nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1368
1369 CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1370 sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1371 if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
1372 {
1373 --nMonth;
1374 pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1375 pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1376 pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1377 sal_Int16 nHour, nMinute, nSecond;
1378 // #i14974# The imported value should have no fractional value, so set the
1379 // time fields to zero (ICU calendar instance defaults to current date/time)
1380 nHour = nMinute = nSecond = 0;
1381 if (nFound > 3)
1382 nHour = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[3], nEnd[3]+1-nStart[3])));
1383 if (nFound > 4)
1384 nMinute = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[4], nEnd[4]+1-nStart[4])));
1385 if (nFound > 5)
1386 nSecond = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[5], nEnd[5]+1-nStart[5])));
1387 // do not use calendar's milliseconds, to avoid fractional part truncation
1388 double fFrac = 0.0;
1389 if (nFound > 6)
1390 {
1391 sal_Unicode cDec = '.';
1392 OUString aT = OUStringChar(cDec) + rStr.subView( nStart[6], nEnd[6]+1-nStart[6]);
1393 rtl_math_ConversionStatus eStatus;
1394 double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus );
1395 if (eStatus == rtl_math_ConversionStatus_Ok)
1396 fFrac = fV / 86400.0;
1397 }
1398 sal_Int32 nPos;
1399 if (nFound > 3 && 1 <= nHour && nHour <= 12 // nHour 0 and >=13 can't be AM/PM
1400 && (nPos = nEnd[nFound-1] + 1) < nLen)
1401 {
1402 // Dreaded AM/PM may be following.
1403 while (nPos < nLen && rStr[nPos] == ' ')
1404 ++nPos;
1405 if (nPos < nLen)
1406 {
1407 sal_Int32 nStop = nPos;
1408 while (nStop < nLen && rStr[nStop] != ' ')
1409 ++nStop;
1410 OUString aAmPm = rStr.copy( nPos, nStop - nPos);
1411 // For AM only 12 needs to be treated, whereas for PM
1412 // it must not. Check both, locale and second/English
1413 // strings.
1414 if (nHour == 12 &&
1415 (rTransliteration.isEqual( aAmPm, pFormatter->GetLocaleData()->getTimeAM()) ||
1416 (pSecondTransliteration && pSecondTransliteration->isEqual( aAmPm, "AM"))))
1417 {
1418 nHour = 0;
1419 }
1420 else if (nHour < 12 &&
1421 (rTransliteration.isEqual( aAmPm, pFormatter->GetLocaleData()->getTimePM()) ||
1422 (pSecondTransliteration && pSecondTransliteration->isEqual( aAmPm, "PM"))))
1423 {
1424 nHour += 12;
1425 }
1426 }
1427 }
1428 pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1429 pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1430 pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1431 pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, 0 );
1432 if ( pCalendar->isValid() )
1433 {
1434 // Whole days diff.
1435 double fDiff = DateTime::Sub( DateTime(pDocFormatter->GetNullDate()),
1436 pCalendar->getEpochStart());
1437 // #i14974# must use getLocalDateTime to get the same
1438 // date values as set above
1439 double fDays = pCalendar->getLocalDateTime() + fFrac;
1440 fDays -= fDiff;
1441
1442 LanguageType eLatin, eCjk, eCtl;
1443 rDoc.GetLanguage( eLatin, eCjk, eCtl );
1444 LanguageType eDocLang = eLatin; //! which language for date formats?
1445
1446 SvNumFormatType nType = (nFound > 3 ? SvNumFormatType::DATETIME : SvNumFormatType::DATE);
1447 sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1448 // maybe there is a special format including seconds or milliseconds
1449 if (nFound > 5)
1450 nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1451
1452 ScAddress aPos(nCol,nRow,nTab);
1453 if ( bUseDocImport )
1454 rDocImport.setNumericCell(aPos, fDays);
1455 else
1456 rDoc.SetValue( aPos, fDays );
1457 rDoc.SetNumberFormat(aPos, nFormat);
1458
1459 return bMultiLine; // success
1460 }
1461 }
1462 }
1463 }
1464
1465 // Standard or date not determined -> SetString / EditCell
1466 if( rStr.indexOf( '\n' ) == -1 )
1467 {
1468 if (!bDetectNumFormat && nColFormat == SC_COL_STANDARD)
1469 {
1470 // Import a strict ISO 8601 date(+time) string even without
1471 // "Detect special numbers" or "Date (YMD)".
1472 do
1473 {
1474 // Simple pre-check before calling more expensive parser.
1475 // ([+-])(Y)YYYY-MM-DD
1476 if (rStr.getLength() < 10)
1477 break;
1478 const sal_Int32 n1 = rStr.indexOf('-', 1);
1479 if (n1 < 4)
1480 break;
1481 const sal_Int32 n2 = rStr.indexOf('-', n1 + 1);
1482 if (n2 < 7 || n1 + 3 < n2)
1483 break;
1484
1485 css::util::DateTime aDateTime;
1486 if (!sax::Converter::parseDateTime( aDateTime, rStr))
1487 break;
1488
1489 sal_uInt32 nFormat = 0;
1490 double fVal = 0.0;
1491 SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
1492 if (pDocFormatter->IsNumberFormat( rStr, nFormat, fVal))
1493 {
1494 if (pDocFormatter->GetType(nFormat) & SvNumFormatType::DATE)
1495 {
1496 ScAddress aPos(nCol,nRow,nTab);
1497 if (bUseDocImport)
1498 rDocImport.setNumericCell(aPos, fVal);
1499 else
1500 rDoc.SetValue(aPos, fVal);
1501 rDoc.SetNumberFormat(aPos, nFormat);
1502
1503 return bMultiLine; // success
1504 }
1505 }
1506 }
1507 while(false);
1508 }
1509
1510 ScSetStringParam aParam;
1511 aParam.mpNumFormatter = pFormatter;
1512 aParam.mbDetectNumberFormat = bDetectNumFormat;
1513 aParam.mbDetectScientificNumberFormat = bDetectSciNumFormat;
1514 aParam.meSetTextNumFormat = ScSetStringParam::SpecialNumberOnly;
1515 aParam.mbHandleApostrophe = false;
1516 aParam.mbCheckLinkFormula = true;
1517 if ( bUseDocImport )
1518 rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr, &aParam);
1519 else
1520 rDoc.SetString( nCol, nRow, nTab, rStr, &aParam );
1521 }
1522 else
1523 {
1524 bMultiLine = true;
1525 ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
1526 rEngine.SetTextCurrentDefaults(rStr);
1527 if ( bUseDocImport )
1528 rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
1529 else
1530 rDoc.SetEditText( ScAddress( nCol, nRow, nTab ), rEngine.CreateTextObject() );
1531 }
1532 return bMultiLine;
1533}
1534
1535static OUString lcl_GetFixed( const OUString& rLine, sal_Int32 nStart, sal_Int32 nNext,
1536 bool& rbIsQuoted, bool& rbOverflowCell )
1537{
1538 sal_Int32 nLen = rLine.getLength();
1539 if (nNext > nLen)
1540 nNext = nLen;
1541 if ( nNext <= nStart )
1542 return OUString();
1543
1544 const sal_Unicode* pStr = rLine.getStr();
1545
1546 sal_Int32 nSpace = nNext;
1547 while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
1548 --nSpace;
1549
1550 rbIsQuoted = (pStr[nStart] == '"' && pStr[nSpace-1] == '"');
1551 if (rbIsQuoted)
1552 {
1553 bool bFits = (nSpace - nStart - 3 <= nArbitraryCellLengthLimit);
1554 if (bFits)
1555 return rLine.copy(nStart+1, std::max< sal_Int32 >(0, nSpace-nStart-2));
1556 else
1557 {
1558 SAL_WARN( "sc", "lcl_GetFixed: line doesn't fit into data");
1559 rbOverflowCell = true;
1560 return rLine.copy(nStart+1, nArbitraryCellLengthLimit);
1561 }
1562 }
1563 else
1564 {
1565 bool bFits = (nSpace - nStart <= nArbitraryCellLengthLimit);
1566 if (bFits)
1567 return rLine.copy(nStart, nSpace-nStart);
1568 else
1569 {
1570 SAL_WARN( "sc", "lcl_GetFixed: line doesn't fit into data");
1571 rbOverflowCell = true;
1572 return rLine.copy(nStart, nArbitraryCellLengthLimit);
1573 }
1574 }
1575}
1576
1577bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1578{
1579 if (!pExtOptions)
1580 return Text2Doc( rStrm );
1581
1582 sal_uInt64 const nOldPos = rStrm.Tell();
1583 sal_uInt64 const nRemaining = rStrm.remainingSize();
1584 std::unique_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1585 ScResId( STR_LOAD_DOC ), nRemaining, true ));
1586 rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
1587 // tdf#82254 - check whether to include a byte-order-mark in the output
1588 if (nOldPos != rStrm.Tell())
1589 mbIncludeBOM = true;
1590
1591 SCCOL nStartCol = aRange.aStart.Col();
1592 SCCOL nEndCol = aRange.aEnd.Col();
1593 SCROW nStartRow = aRange.aStart.Row();
1594 const SCTAB nTab = aRange.aStart.Tab();
1595
1596 bool bFixed = pExtOptions->IsFixedLen();
1597 OUString aSeps = pExtOptions->GetFieldSeps(); // Need non-const for ReadCsvLine(),
1598 const sal_Unicode* pSeps = aSeps.getStr(); // but it will be const anyway (asserted below).
1599 bool bMerge = pExtOptions->IsMergeSeps();
1600 bool bRemoveSpace = pExtOptions->IsRemoveSpace();
1601 sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
1602 const sal_Int32* pColStart = pExtOptions->GetColStart();
1603 const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
1604 tools::Long nSkipLines = pExtOptions->GetStartRow();
1605
1606 LanguageType eDocLang = pExtOptions->GetLanguage();
1607 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eDocLang);
1608 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1609 bool bDetectSciNumFormat = pExtOptions->IsDetectScientificNumber();
1610 bool bEvaluateFormulas = pExtOptions->IsEvaluateFormulas();
1611 bool bSkipEmptyCells = pExtOptions->IsSkipEmptyCells();
1612
1613 // For date recognition
1614 ::utl::TransliterationWrapper aTransliteration(
1615 comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE );
1616 aTransliteration.loadModuleIfNeeded( eDocLang );
1617 CalendarWrapper aCalendar( comphelper::getProcessComponentContext() );
1618 aCalendar.loadDefaultCalendar(
1619 LanguageTag::convertToLocale( eDocLang ) );
1620 std::unique_ptr< ::utl::TransliterationWrapper > pEnglishTransliteration;
1621 std::unique_ptr< CalendarWrapper > pEnglishCalendar;
1622 if ( eDocLang != LANGUAGE_ENGLISH_US )
1623 {
1624 pEnglishTransliteration.reset(new ::utl::TransliterationWrapper (
1625 comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE ));
1626 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1627 pEnglishCalendar.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
1628 pEnglishCalendar->loadDefaultCalendar(
1629 LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) );
1630 }
1631
1632 OUString aLine;
1633 OUString aCell;
1634 sal_uInt16 i;
1635 SCROW nRow = nStartRow;
1636 sal_Unicode cDetectSep = 0xffff; // No separator detection here.
1637
1638 while(--nSkipLines>0)
1639 {
1640 aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep); // content is ignored
1641 if ( rStrm.eof() )
1642 break;
1643 }
1644
1645 // Determine range for Undo.
1646 // We don't need this during import of a file to a new sheet or document...
1647 bool bDetermineRange = bUndo;
1648 bool bColumnsAreDetermined = false;
1649
1650 // Row heights don't need to be adjusted on the fly if EndPaste() is called
1651 // afterwards, which happens only if bDetermineRange. This variable also
1652 // survives the toggle of bDetermineRange down at the end of the do{} loop.
1653 bool bRangeIsDetermined = bDetermineRange;
1654
1655 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1656
1657 sal_uInt64 nOriginalStreamPos = rStrm.Tell();
1658
1659 SCROW nFirstUpdateRowHeight = SCROW_MAX;
1660 SCROW nLastUpdateRowHeight = -1;
1661
1662 ScDocumentImport aDocImport(rDoc);
1663 do
1664 {
1665 for( ;; )
1666 {
1667 aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep);
1668 if ( rStrm.eof() && aLine.isEmpty() )
1669 break;
1670
1671 assert(pSeps == aSeps.getStr());
1672
1673 if ( nRow > rDoc.MaxRow() )
1674 {
1675 bOverflowRow = true; // display warning on import
1676 break; // for
1677 }
1678
1679 if (!bDetermineRange)
1680 EmbeddedNullTreatment( aLine);
1681
1682 sal_Int32 nLineLen = aLine.getLength();
1683 SCCOL nCol = nStartCol;
1684 bool bMultiLine = false;
1685 if ( bFixed ) // Fixed line length
1686 {
1687 if (bDetermineRange)
1688 {
1689 if (!bColumnsAreDetermined)
1690 {
1691 // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it
1692 // is only an overflow if there is really data following to
1693 // be put behind the last column, which doesn't happen if
1694 // info is SC_COL_SKIP.
1695 for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
1696 {
1697 const sal_uInt8 nFmt = pColFormat[i];
1698 if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
1699 {
1700 if (nCol > rDoc.MaxCol())
1701 bOverflowCol = true; // display warning on import
1702 ++nCol;
1703 }
1704 }
1705 bColumnsAreDetermined = true;
1706 }
1707 }
1708 else
1709 {
1710 sal_Int32 nStartIdx = 0;
1711 // Same maxcol+1 check reason as above.
1712 for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
1713 {
1714 sal_Int32 nNextIdx = nStartIdx;
1715 if (i + 1 < nInfoCount)
1716 CountVisualWidth( aLine, nNextIdx, pColStart[i+1] - pColStart[i] );
1717 else
1718 nNextIdx = nLineLen;
1719 sal_uInt8 nFmt = pColFormat[i];
1720 if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
1721 {
1722 if (nCol > rDoc.MaxCol())
1723 bOverflowCol = true; // display warning on import
1724 else
1725 {
1726 bool bIsQuoted = false;
1727 aCell = lcl_GetFixed( aLine, nStartIdx, nNextIdx, bIsQuoted, bOverflowCell );
1728 if (bIsQuoted && bQuotedAsText)
1729 nFmt = SC_COL_TEXT;
1730
1731 bMultiLine |= lcl_PutString(
1732 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1733 &aNumFormatter, bDetectNumFormat, bDetectSciNumFormat, bEvaluateFormulas, bSkipEmptyCells,
1734 aTransliteration, aCalendar,
1735 pEnglishTransliteration.get(), pEnglishCalendar.get());
1736 }
1737 ++nCol;
1738 }
1739 nStartIdx = nNextIdx;
1740 }
1741 }
1742 }
1743 else // Search for the separator
1744 {
1745 SCCOL nSourceCol = 0;
1746 sal_uInt16 nInfoStart = 0;
1747 const sal_Unicode* p = aLine.getStr();
1748 // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it is only an
1749 // overflow if there is really data following to be put behind
1750 // the last column, which doesn't happen if info is
1751 // SC_COL_SKIP.
1752 while (*p && nCol <= rDoc.MaxCol()+1)
1753 {
1754 bool bIsQuoted = false;
1756 cStr, pSeps, bMerge, bIsQuoted, bOverflowCell, bRemoveSpace );
1757
1759 for ( i=nInfoStart; i<nInfoCount; i++ )
1760 {
1761 if ( pColStart[i] == nSourceCol + 1 ) // pColStart is 1-based
1762 {
1763 nFmt = pColFormat[i];
1764 nInfoStart = i + 1; // ColInfos are in succession
1765 break; // for
1766 }
1767 }
1768 if ( nFmt != SC_COL_SKIP )
1769 {
1770 if (nCol > rDoc.MaxCol())
1771 bOverflowCol = true; // display warning on import
1772 else if (!bDetermineRange)
1773 {
1774 if (bIsQuoted && bQuotedAsText)
1775 nFmt = SC_COL_TEXT;
1776
1777 bMultiLine |= lcl_PutString(
1778 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1779 &aNumFormatter, bDetectNumFormat, bDetectSciNumFormat, bEvaluateFormulas, bSkipEmptyCells,
1780 aTransliteration, aCalendar,
1781 pEnglishTransliteration.get(), pEnglishCalendar.get());
1782 }
1783 ++nCol;
1784 }
1785
1786 ++nSourceCol;
1787 }
1788 }
1789 if (nEndCol < nCol)
1790 nEndCol = nCol;
1791
1792 if (!bDetermineRange)
1793 {
1794 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1795 { // Adjust just once at the end for a whole range.
1796 nFirstUpdateRowHeight = std::min( nFirstUpdateRowHeight, nRow );
1797 nLastUpdateRowHeight = std::max( nLastUpdateRowHeight, nRow );
1798 }
1799 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1800 }
1801 ++nRow;
1802 }
1803 // so far nRow/nEndCol pointed to the next free
1804 if (nRow > nStartRow)
1805 --nRow;
1806 if (nEndCol > nStartCol)
1807 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), rDoc.MaxCol());
1808
1809 if (bDetermineRange)
1810 {
1811 aRange.aEnd.SetCol( nEndCol );
1812 aRange.aEnd.SetRow( nRow );
1813
1814 if ( !mbApi && nStartCol != nEndCol &&
1815 !rDoc.IsBlockEmpty( nStartCol + 1, nStartRow, nEndCol, nRow, nTab ) )
1816 {
1818 if (aBox.run() != RET_YES)
1819 {
1820 return false;
1821 }
1822 }
1823
1824 rStrm.Seek( nOriginalStreamPos );
1825 nRow = nStartRow;
1826 if (!StartPaste())
1827 {
1828 EndPaste(false);
1829 return false;
1830 }
1831 }
1832
1833 bDetermineRange = !bDetermineRange; // toggle
1834 } while (!bDetermineRange);
1835
1836 if ( !mbOverwriting )
1837 aDocImport.finalize();
1838
1839 xProgress.reset(); // make room for AdjustRowHeight progress
1840
1841 if( nFirstUpdateRowHeight < nLastUpdateRowHeight && pDocSh )
1842 pDocSh->AdjustRowHeight( nFirstUpdateRowHeight, nLastUpdateRowHeight, nTab);
1843
1844 if (bRangeIsDetermined)
1845 EndPaste(false);
1846
1847 if (mbImportBroadcast && !mbOverwriting)
1848 {
1849 rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
1850 pDocSh->PostDataChanged();
1851 }
1852 return true;
1853}
1854
1856{
1857 // A nasty workaround for data with embedded NULL characters. As long as we
1858 // can't handle them properly as cell content (things assume 0-terminated
1859 // strings at too many places) simply strip all NULL characters from raw
1860 // data. Excel does the same. See fdo#57841 for sample data.
1861
1862 // The normal case is no embedded NULL, check first before de-/allocating
1863 // ustring stuff.
1864 sal_Unicode cNull = 0;
1865 if (sal_Int32 pos = rStr.indexOf(cNull); pos >= 0)
1866 {
1867 rStr = rStr.replaceAll(std::u16string_view(&cNull, 1), u"", pos);
1868 }
1869}
1870
1872 OUString& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted,
1873 bool& rbOverflowCell, bool bRemoveSpace )
1874{
1875 rbIsQuoted = false;
1876 rField.clear();
1877 const sal_Unicode cBlank = ' ';
1878 if (cStr && !ScGlobal::UnicodeStrChr(pSeps, cBlank))
1879 {
1880 // Cope with broken generators that put leading blanks before a quoted
1881 // field, like "field1", "field2", "..."
1882 // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1883 const sal_Unicode* pb = p;
1884 while (*pb == cBlank)
1885 ++pb;
1886 if (*pb == cStr)
1887 p = pb;
1888 }
1889 if (cStr && *p == cStr) // String in quotes
1890 {
1891 rbIsQuoted = true;
1892 const sal_Unicode* p1;
1893 p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DoubledQuoteMode::ESCAPE, rbOverflowCell );
1894 while (!lcl_isFieldEnd( *p, pSeps))
1895 p++;
1896 // Append remaining unquoted and undelimited data (dirty, dirty) to
1897 // this field.
1898 if (p > p1)
1899 {
1900 const sal_Unicode* ptrim_f = p;
1901 if ( bRemoveSpace )
1902 {
1903 while ( ptrim_f > p1 && ( *(ptrim_f - 1) == cBlank ) )
1904 --ptrim_f;
1905 }
1906 if (!lcl_appendLineData( rField, p1, ptrim_f))
1907 rbOverflowCell = true;
1908 }
1909 if( *p )
1910 p++;
1911 }
1912 else // up to delimiter
1913 {
1914 const sal_Unicode* p0 = p;
1915 while (!lcl_isFieldEnd( *p, pSeps))
1916 p++;
1917 const sal_Unicode* ptrim_i = p0;
1918 const sal_Unicode* ptrim_f = p; // [ptrim_i,ptrim_f) is cell data after trimming
1919 if ( bRemoveSpace )
1920 {
1921 while ( ptrim_i < ptrim_f && *ptrim_i == cBlank )
1922 ++ptrim_i;
1923 while ( ptrim_f > ptrim_i && ( *(ptrim_f - 1) == cBlank ) )
1924 --ptrim_f;
1925 }
1926 if (!lcl_appendLineData( rField, ptrim_i, ptrim_f))
1927 rbOverflowCell = true;
1928 if( *p )
1929 p++;
1930 }
1931 if ( bMergeSeps ) // skip following delimiters
1932 {
1933 while (*p && ScGlobal::UnicodeStrChr( pSeps, *p))
1934 p++;
1935 }
1936 return p;
1937}
1938
1939namespace {
1940
1947bool hasLineBreaksOrSeps( const OUString& rStr, sal_Unicode cSep )
1948{
1949 const sal_Unicode* p = rStr.getStr();
1950 for (sal_Int32 i = 0, n = rStr.getLength(); i < n; ++i, ++p)
1951 {
1952 sal_Unicode c = *p;
1953 if (c == cSep)
1954 // separator found.
1955 return true;
1956
1957 switch (c)
1958 {
1959 case '\n':
1960 case '\r':
1961 // line break found.
1962 return true;
1963 default:
1964 ;
1965 }
1966 }
1967 return false;
1968}
1969
1970}
1971
1973{
1974 SCCOL nCol;
1975 SCROW nRow;
1976 SCCOL nStartCol = aRange.aStart.Col();
1977 SCROW nStartRow = aRange.aStart.Row();
1978 SCTAB nStartTab = aRange.aStart.Tab();
1979 SCCOL nEndCol = aRange.aEnd.Col();
1980 SCROW nEndRow = aRange.aEnd.Row();
1981 SCTAB nEndTab = aRange.aEnd.Tab();
1982
1983 if (!rDoc.GetClipParam().isMultiRange() && nStartTab == nEndTab)
1984 if (!rDoc.ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow ))
1985 return false;
1986
1987 OUString aCellStr;
1988
1989 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1990
1991 // We need to cache sc::ColumnBlockPosition per each column, tab is always nStartTab.
1992 std::vector< sc::ColumnBlockPosition > blockPos( nEndCol - nStartCol + 1 );
1993 for( SCCOL i = nStartCol; i <= nEndCol; ++i )
1994 rDoc.InitColumnBlockPosition( blockPos[ i - nStartCol ], nStartTab, i );
1995 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1996 {
1997 if (bIncludeFiltered || !rDoc.RowFiltered( nRow, nStartTab ))
1998 {
1999 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
2000 {
2001 ScAddress aPos(nCol, nRow, nStartTab);
2002 sal_uInt32 nNumFmt = rDoc.GetNumberFormat(aPos);
2003 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2004
2005 ScRefCellValue aCell(rDoc, aPos, blockPos[ nCol - nStartCol ]);
2006 switch (aCell.getType())
2007 {
2008 case CELLTYPE_FORMULA:
2009 {
2010 if (bFormulas)
2011 {
2012 aCellStr = aCell.getFormula()->GetFormula();
2013 if( aCellStr.indexOf( cSep ) != -1 )
2014 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2015 else
2016 lcl_WriteSimpleString( rStrm, aCellStr );
2017 }
2018 else
2019 {
2020 const Color* pColor;
2021 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2022
2023 bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
2024 if( bMultiLineText )
2025 {
2027 aCellStr = aCellStr.replaceAll( "\n", " " );
2029 aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
2030 }
2031
2033 aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
2034
2035 if( mExportTextOptions.mbAddQuotes && ( aCellStr.indexOf( cSep ) != -1 ) )
2036 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2037 else
2038 lcl_WriteSimpleString( rStrm, aCellStr );
2039 }
2040 }
2041 break;
2042 case CELLTYPE_VALUE:
2043 {
2044 const Color* pColor;
2045 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2046 lcl_WriteSimpleString( rStrm, aCellStr );
2047 }
2048 break;
2049 case CELLTYPE_NONE:
2050 break;
2051 default:
2052 {
2053 const Color* pColor;
2054 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2055
2056 bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
2057 if( bMultiLineText )
2058 {
2060 aCellStr = aCellStr.replaceAll( "\n", " " );
2062 aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
2063 }
2064
2066 aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
2067
2068 if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCellStr, cSep) )
2069 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2070 else
2071 lcl_WriteSimpleString( rStrm, aCellStr );
2072 }
2073 }
2074 if( nCol < nEndCol )
2075 lcl_WriteSimpleString( rStrm, rtl::OUStringChar(cSep) );
2076 }
2077 // Do not append a line feed for one single cell.
2078 // NOTE: this Doc2Text() is only called for clipboard via
2079 // ScImportExport::ExportStream().
2080 if (nStartRow != nEndRow || nStartCol != nEndCol)
2082 if( rStrm.GetError() != ERRCODE_NONE )
2083 break;
2084 if( nSizeLimit && rStrm.Tell() > nSizeLimit )
2085 break;
2086 }
2087 }
2088
2089 return rStrm.GetError() == ERRCODE_NONE;
2090}
2091
2093{
2094 bool bOk = true;
2095 bool bMyDoc = false;
2096 SylkVersion eVersion = SylkVersion::OTHER;
2097
2098 // US-English separators for StringToDouble
2099 sal_Unicode const cDecSep = '.';
2100 sal_Unicode const cGrpSep = ',';
2101
2102 SCCOL nStartCol = aRange.aStart.Col();
2103 SCROW nStartRow = aRange.aStart.Row();
2104 SCCOL nEndCol = aRange.aEnd.Col();
2105 SCROW nEndRow = aRange.aEnd.Row();
2106 sal_uInt64 nOldPos = rStrm.Tell();
2107 bool bData = !bSingle;
2108 ::std::vector< sal_uInt32 > aFormats;
2109
2110 if( !bSingle)
2111 bOk = StartPaste();
2112
2113 while( bOk )
2114 {
2115 OUString aLine;
2116 OUString aText;
2117 OStringBuffer aByteLine;
2118 SCCOL nCol = nStartCol;
2119 SCROW nRow = nStartRow;
2120 SCCOL nRefCol = nCol;
2121 SCROW nRefRow = nRow;
2122 rStrm.Seek( nOldPos );
2123 for( ;; )
2124 {
2126 rStrm.ReadLine( aByteLine );
2127 aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
2128 if( rStrm.eof() )
2129 break;
2130 bool bInvalidCol = false;
2131 bool bInvalidRow = false;
2132 const sal_Unicode* p = aLine.getStr();
2133 sal_Unicode cTag = *p++;
2134 if( cTag == 'C' ) // Content
2135 {
2136 if( *p++ != ';' )
2137 return false;
2138
2139 bool bInvalidRefCol = false;
2140 bool bInvalidRefRow = false;
2141 while( *p )
2142 {
2143 sal_Unicode ch = *p++;
2145 switch( ch )
2146 {
2147 case 'X':
2148 {
2149 bInvalidCol = false;
2150 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
2151 if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
2152 {
2153 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
2154 nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
2155 bInvalidCol = bOverflowCol = true;
2156 }
2157 break;
2158 }
2159 case 'Y':
2160 {
2161 bInvalidRow = false;
2162 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
2163 if (bFail || nRow < 0 || nMaxImportRow < nRow)
2164 {
2165 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
2166 nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
2167 bInvalidRow = bOverflowRow = true;
2168 }
2169 break;
2170 }
2171 case 'C':
2172 {
2173 bInvalidRefCol = false;
2174 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nRefCol);
2175 if (bFail || nRefCol < 0 || rDoc.MaxCol() < nRefCol)
2176 {
2177 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;C invalid nRefCol=" << nRefCol);
2178 nRefCol = std::clamp<SCCOL>(nRefCol, 0, rDoc.MaxCol());
2179 bInvalidRefCol = bOverflowCol = true;
2180 }
2181 break;
2182 }
2183 case 'R':
2184 {
2185 bInvalidRefRow = false;
2186 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRefRow);
2187 if (bFail || nRefRow < 0 || nMaxImportRow < nRefRow)
2188 {
2189 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;R invalid nRefRow=" << nRefRow);
2190 nRefRow = std::clamp<SCROW>(nRefRow, 0, nMaxImportRow);
2191 bInvalidRefRow = bOverflowRow = true;
2192 }
2193 break;
2194 }
2195 case 'K':
2196 {
2197 if( !bSingle &&
2198 ( nCol < nStartCol || nCol > nEndCol
2199 || nRow < nStartRow || nRow > nEndRow
2200 || nCol > rDoc.MaxCol() || nRow > nMaxImportRow
2201 || bInvalidCol || bInvalidRow ) )
2202 break;
2203 if( !bData )
2204 {
2205 if( nRow > nEndRow )
2206 nEndRow = nRow;
2207 if( nCol > nEndCol )
2208 nEndCol = nCol;
2209 break;
2210 }
2211 bool bText;
2212 if( *p == '"' )
2213 {
2214 bText = true;
2215 aText.clear();
2216 p = lcl_ScanSylkString( p, aText, eVersion);
2217 }
2218 else
2219 bText = false;
2220 const sal_Unicode* q = p;
2221 while( *q && *q != ';' )
2222 q++;
2223 if ( (*q != ';' || *(q+1) != 'I') && !bInvalidCol && !bInvalidRow )
2224 { // don't ignore value
2225 if( bText )
2226 {
2229 ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
2230 }
2231 else
2232 {
2233 double fVal = rtl_math_uStringToDouble( p,
2234 aLine.getStr() + aLine.getLength(),
2235 cDecSep, cGrpSep, nullptr, nullptr );
2236 rDoc.SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
2237 }
2238 }
2239 }
2240 break;
2241 case 'E':
2242 case 'M':
2243 {
2244 if ( ch == 'M' )
2245 {
2246 if ( nRefCol < nCol )
2247 nRefCol = nCol;
2248 if ( nRefRow < nRow )
2249 nRefRow = nRow;
2250 if ( !bData )
2251 {
2252 if( nRefRow > nEndRow )
2253 nEndRow = nRefRow;
2254 if( nRefCol > nEndCol )
2255 nEndCol = nRefCol;
2256 }
2257 }
2258 if( !bMyDoc || !bData )
2259 break;
2260 aText = "=";
2261 p = lcl_ScanSylkFormula( p, aText, eVersion);
2262
2263 if (bInvalidCol || bInvalidRow || (ch == 'M' && (bInvalidRefCol || bInvalidRefRow)))
2264 break;
2265
2266 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
2267 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
2268 * end it probably should be GRAM_ODFF_R1C1, since
2269 * R1C1 is what Excel writes in SYLK, or even
2270 * better GRAM_ENGLISH_XL_R1C1. */
2272 ScCompiler aComp(rDoc, aPos, eGrammar);
2273 std::unique_ptr<ScTokenArray> xCode(aComp.CompileString(aText)); // ctor/InsertMatrixFormula did copy TokenArray
2275 if ( ch == 'M' )
2276 {
2278 aMark.SelectTable( aPos.Tab(), true );
2279 rDoc.InsertMatrixFormula( nCol, nRow, nRefCol,
2280 nRefRow, aMark, OUString(), xCode.get() );
2281 }
2282 else
2283 {
2284 ScFormulaCell* pFCell = new ScFormulaCell(
2285 rDoc, aPos, *xCode, eGrammar, ScMatrixMode::NONE);
2286 rDoc.SetFormulaCell(aPos, pFCell);
2287 }
2288 }
2289 break;
2290 }
2291 while( *p && *p != ';' )
2292 p++;
2293 if( *p )
2294 p++;
2295 }
2296 }
2297 else if( cTag == 'F' ) // Format
2298 {
2299 if( *p++ != ';' )
2300 return false;
2301 sal_Int32 nFormat = -1;
2302 while( *p )
2303 {
2304 sal_Unicode ch = *p++;
2306 switch( ch )
2307 {
2308 case 'X':
2309 {
2310 bInvalidCol = false;
2311 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
2312 if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
2313 {
2314 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
2315 nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
2316 bInvalidCol = bOverflowCol = true;
2317 }
2318 break;
2319 }
2320 case 'Y':
2321 {
2322 bInvalidRow = false;
2323 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
2324 if (bFail || nRow < 0 || nMaxImportRow < nRow)
2325 {
2326 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
2327 nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
2328 bInvalidRow = bOverflowRow = true;
2329 }
2330 break;
2331 }
2332 case 'P' :
2333 if ( bData )
2334 {
2335 // F;P<n> sets format code of P;P<code> at
2336 // current position, or at ;X;Y if specified.
2337 // Note that ;X;Y may appear after ;P
2338 const sal_Unicode* p0 = p;
2339 while( *p && *p != ';' )
2340 p++;
2341 OUString aNumber(p0, p - p0);
2342 nFormat = aNumber.toInt32();
2343 }
2344 break;
2345 }
2346 while( *p && *p != ';' )
2347 p++;
2348 if( *p )
2349 p++;
2350 }
2351 if ( !bData )
2352 {
2353 if( nRow > nEndRow )
2354 nEndRow = nRow;
2355 if( nCol > nEndCol )
2356 nEndCol = nCol;
2357 }
2358 if ( 0 <= nFormat && o3tl::make_unsigned(nFormat) < aFormats.size() && !bInvalidCol && !bInvalidRow )
2359 {
2360 sal_uInt32 nKey = aFormats[nFormat];
2361 rDoc.ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
2363 }
2364 }
2365 else if( cTag == 'P' )
2366 {
2367 if ( bData && *p == ';' && *(p+1) == 'P' )
2368 {
2369 OUString aCode( p+2 );
2370
2371 sal_uInt32 nKey;
2372 sal_Int32 nCheckPos;
2373
2374 if (aCode.getLength() > 2048 && utl::ConfigManager::IsFuzzing())
2375 {
2376 // consider an excessive length as a failure when fuzzing
2377 nCheckPos = 1;
2378 }
2379 else
2380 {
2381 // unescape doubled semicolons
2382 aCode = aCode.replaceAll(";;", ";");
2383 // get rid of Xcl escape characters
2384 aCode = aCode.replaceAll("\x1b", "");
2386 rDoc.GetFormatTable()->PutandConvertEntry( aCode, nCheckPos, nType, nKey,
2388 }
2389
2390 if ( nCheckPos )
2391 nKey = 0;
2392
2393 aFormats.push_back( nKey );
2394 }
2395 }
2396 else if (cTag == 'I' && *p == 'D' && aLine.getLength() > 4)
2397 {
2398 aLine = aLine.copy(4);
2399 if (aLine == "CALCOOO32")
2400 eVersion = SylkVersion::OOO32;
2401 else if (aLine == "SCALC3")
2402 eVersion = SylkVersion::SCALC3;
2403 bMyDoc = (eVersion <= SylkVersion::OWN);
2404 }
2405 else if( cTag == 'E' ) // End
2406 break;
2407 }
2408 if( !bData )
2409 {
2410 aRange.aEnd.SetCol( nEndCol );
2411 aRange.aEnd.SetRow( nEndRow );
2412 bOk = StartPaste();
2413 bData = true;
2414 }
2415 else
2416 break;
2417 }
2418
2419 EndPaste();
2420 return bOk;
2421}
2422
2424{
2425 SCCOL nCol;
2426 SCROW nRow;
2427 SCCOL nStartCol = aRange.aStart.Col();
2428 SCROW nStartRow = aRange.aStart.Row();
2429 SCCOL nEndCol = aRange.aEnd.Col();
2430 SCROW nEndRow = aRange.aEnd.Row();
2431 OUString aCellStr;
2432 OUString aValStr;
2433 lcl_WriteSimpleString( rStrm, u"ID;PCALCOOO32" );
2435
2436 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
2437 {
2438 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
2439 {
2440 OUString aBufStr;
2441 double nVal;
2442 bool bForm = false;
2443 SCROW r = nRow - nStartRow + 1;
2444 SCCOL c = nCol - nStartCol + 1;
2445 ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, aRange.aStart.Tab()));
2446 CellType eType = aCell.getType();
2447 switch( eType )
2448 {
2449 case CELLTYPE_FORMULA:
2450 bForm = bFormulas;
2451 if( rDoc.HasValueData( nCol, nRow, aRange.aStart.Tab()) )
2452 goto hasvalue;
2453 else
2454 goto hasstring;
2455
2456 case CELLTYPE_VALUE:
2457 hasvalue:
2458 nVal = rDoc.GetValue( nCol, nRow, aRange.aStart.Tab() );
2459
2460 aValStr = ::rtl::math::doubleToUString( nVal,
2461 rtl_math_StringFormat_Automatic,
2462 rtl_math_DecimalPlaces_Max, '.', true );
2463
2464 aBufStr = "C;X"
2465 + OUString::number( c )
2466 + ";Y"
2467 + OUString::number( r )
2468 + ";K"
2469 + aValStr;
2470 lcl_WriteSimpleString( rStrm, aBufStr );
2471 goto checkformula;
2472
2473 case CELLTYPE_STRING:
2474 case CELLTYPE_EDIT:
2475 hasstring:
2476 aCellStr = rDoc.GetString(nCol, nRow, aRange.aStart.Tab());
2477 aCellStr = aCellStr.replaceAll("\n", SYLK_LF);
2478
2479 aBufStr = "C;X"
2480 + OUString::number( c )
2481 + ";Y"
2482 + OUString::number( r )
2483 + ";K";
2484 lcl_WriteSimpleString( rStrm, aBufStr );
2485 lcl_WriteString( rStrm, aCellStr, '"', ';' );
2486
2487 checkformula:
2488 if( bForm )
2489 {
2490 const ScFormulaCell* pFCell = aCell.getFormula();
2491 switch ( pFCell->GetMatrixFlag() )
2492 {
2494 aCellStr.clear();
2495 break;
2496 default:
2498 /* FIXME: do we want GRAM_ODFF_A1 instead? At
2499 * the end it probably should be
2500 * GRAM_ODFF_R1C1, since R1C1 is what Excel
2501 * writes in SYLK, or even better
2502 * GRAM_ENGLISH_XL_R1C1. */
2503 }
2504 if ( pFCell->GetMatrixFlag() != ScMatrixMode::NONE &&
2505 aCellStr.startsWith("{") &&
2506 aCellStr.endsWith("}") )
2507 { // cut off matrix {} characters
2508 aCellStr = aCellStr.copy(1, aCellStr.getLength()-2);
2509 }
2510 if ( aCellStr[0] == '=' )
2511 aCellStr = aCellStr.copy(1);
2512 OUString aPrefix;
2513 switch ( pFCell->GetMatrixFlag() )
2514 {
2516 { // diff expression with 'M' M$-extension
2517 SCCOL nC;
2518 SCROW nR;
2519 pFCell->GetMatColsRows( nC, nR );
2520 nC += c - 1;
2521 nR += r - 1;
2522 aPrefix = ";R"
2523 + OUString::number( nR )
2524 + ";C"
2525 + OUString::number( nC )
2526 + ";M";
2527 }
2528 break;
2530 { // diff expression with 'I' M$-extension
2531 ScAddress aPos;
2532 (void)pFCell->GetMatrixOrigin( rDoc, aPos );
2533 aPrefix = ";I;R"
2534 + OUString::number( aPos.Row() - nStartRow + 1 )
2535 + ";C"
2536 + OUString::number( aPos.Col() - nStartCol + 1 );
2537 }
2538 break;
2539 default:
2540 // formula Expression
2541 aPrefix = ";E";
2542 }
2543 lcl_WriteSimpleString( rStrm, aPrefix );
2544 if ( !aCellStr.isEmpty() )
2545 lcl_WriteString( rStrm, aCellStr, 0, ';' );
2546 }
2548 break;
2549
2550 default:
2551 {
2552 // added to avoid warnings
2553 }
2554 }
2555 }
2556 }
2557 lcl_WriteSimpleString( rStrm, rtl::OUStringChar( 'E' ) );
2559 return rStrm.GetError() == ERRCODE_NONE;
2560}
2561
2562bool ScImportExport::Doc2HTML( SvStream& rStrm, const OUString& rBaseURL )
2563{
2564 // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
2565 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
2567 return rStrm.GetError() == ERRCODE_NONE;
2568}
2569
2571{
2572 // rtl_TextEncoding is ignored in ScExportRTF
2573 ScFormatFilter::Get().ScExportRTF( rStrm, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
2574 return rStrm.GetError() == ERRCODE_NONE;
2575}
2576
2578{
2579 // for DIF in the clipboard, IBM_850 is always used
2580 ScFormatFilter::Get().ScExportDif( rStrm, &rDoc, aRange, RTL_TEXTENCODING_IBM_850 );
2581 return true;
2582}
2583
2585{
2586 SCTAB nTab = aRange.aStart.Tab();
2587 ScDocumentUniquePtr pImportDoc( new ScDocument( SCDOCMODE_UNDO ) );
2588 pImportDoc->InitUndo( rDoc, nTab, nTab );
2589
2590 // for DIF in the clipboard, IBM_850 is always used
2591 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc.get(), aRange.aStart, RTL_TEXTENCODING_IBM_850 );
2592
2593 SCCOL nEndCol;
2594 SCROW nEndRow;
2595 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
2596 // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2597 if ( nEndCol < aRange.aStart.Col() )
2598 nEndCol = aRange.aStart.Col();
2599 if ( nEndRow < aRange.aStart.Row() )
2600 nEndRow = aRange.aStart.Row();
2601 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
2602
2603 bool bOk = StartPaste();
2604 if (bOk)
2605 {
2607 rDoc.DeleteAreaTab( aRange, nFlags );
2608 pImportDoc->CopyToDocument(aRange, nFlags, false, rDoc);
2609 EndPaste();
2610 }
2611
2612 return bOk;
2613}
2614
2615bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
2616{
2617 std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateRTFImport( &rDoc, aRange );
2618 if (!pImp)
2619 return false;
2620 pImp->Read( rStrm, rBaseURL );
2621 aRange = pImp->GetRange();
2622
2623 bool bOk = StartPaste();
2624 if (bOk)
2625 {
2627 rDoc.DeleteAreaTab( aRange, nFlags );
2628 pImp->WriteToDocument();
2629 EndPaste();
2630 }
2631 return bOk;
2632}
2633
2634bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
2635{
2636 std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateHTMLImport( &rDoc, rBaseURL, aRange);
2637 if (!pImp)
2638 return false;
2639 pImp->Read( rStrm, rBaseURL );
2640 aRange = pImp->GetRange();
2641
2642 bool bOk = StartPaste();
2643 if (bOk)
2644 {
2645 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2646 // a Draw Layer but no Draw View -> create Draw Layer and View here
2647 if (pDocSh)
2649
2651 rDoc.DeleteAreaTab( aRange, nFlags );
2652
2653 if (pExtOptions)
2654 {
2655 // Pick up import options if available.
2656 LanguageType eLang = pExtOptions->GetLanguage();
2658 bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
2659 bool bScientificNumber = pExtOptions->IsDetectScientificNumber();
2660 pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber, bScientificNumber);
2661 }
2662 else
2663 // Regular import, with no options.
2664 pImp->WriteToDocument();
2665
2666 EndPaste();
2667 }
2668 return bOk;
2669}
2670
2671#ifndef DISABLE_DYNLOADING
2672
2673extern "C" { static void thisModule() {} }
2674
2675#else
2676
2677extern "C" {
2679}
2680
2681#endif
2682
2683typedef ScFormatFilterPlugin * (*FilterFn)();
2685{
2686 static ScFormatFilterPlugin *plugin = []()
2687 {
2688#ifndef DISABLE_DYNLOADING
2689 OUString sFilterLib(SVLIBRARY("scfilt"));
2690 static ::osl::Module aModule;
2691 bool bLoaded = aModule.is();
2692 if (!bLoaded)
2693 bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
2694 if (!bLoaded)
2695 bLoaded = aModule.load(sFilterLib);
2696 if (bLoaded)
2697 {
2698 oslGenericFunction fn = aModule.getFunctionSymbol( "ScFilterCreate" );
2699 if (fn != nullptr)
2700 return reinterpret_cast<FilterFn>(fn)();
2701 }
2702 assert(false);
2703 return static_cast<ScFormatFilterPlugin*>(nullptr);
2704#else
2705 return ScFilterCreate();
2706#endif
2707 }();
2708
2709 return *plugin;
2710}
2711
2712// Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2713// array.
2714static const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
2715 sal_Unicode c )
2716{
2717 while (*pStr)
2718 {
2719 if (*pStr == c)
2720 return pStr;
2721 ++pStr;
2722 }
2723 return nullptr;
2724}
2725
2727 : SvMemoryStream( const_cast<sal_Unicode *>(rStr.getStr()),
2728 rStr.getLength() * sizeof(sal_Unicode), StreamMode::READ)
2729{
2730 SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
2731#ifdef OSL_BIGENDIAN
2732 SetEndian(SvStreamEndian::BIG);
2733#else
2734 SetEndian(SvStreamEndian::LITTLE);
2735#endif
2736}
2737
2738OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
2739 OUString& rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode& rcDetectSep, sal_uInt32 nMaxSourceLines )
2740{
2741 enum RetryState
2742 {
2743 FORBID,
2744 ALLOW,
2745 RETRY,
2746 RETRIED
2747 } eRetryState = (bEmbeddedLineBreak && rcDetectSep == 0 ? RetryState::ALLOW : RetryState::FORBID);
2748
2749 sal_uInt64 nStreamPos = (eRetryState == RetryState::ALLOW ? rStream.Tell() : 0);
2750
2751Label_RetryWithNewSep:
2752
2753 if (eRetryState == RetryState::RETRY)
2754 {
2755 eRetryState = RetryState::RETRIED;
2756 rStream.Seek( nStreamPos);
2757 }
2758
2759 OUString aStr;
2761
2762 if (bEmbeddedLineBreak)
2763 {
2764 sal_Int32 nFirstLineLength = aStr.getLength();
2765 sal_uInt64 nFirstLineStreamPos = rStream.Tell();
2766 sal_uInt32 nLine = 0;
2767
2768 const sal_Unicode* pSeps = rFieldSeparators.getStr();
2769
2770 QuoteType eQuoteState = FIELDEND_QUOTE;
2771 bool bFieldStart = true;
2772
2773 sal_Int32 nLastOffset = 0;
2774 sal_Int32 nQuotes = 0;
2775 while (!rStream.eof() && aStr.getLength() < nArbitraryLineLengthLimit)
2776 {
2777 const sal_Unicode * p = aStr.getStr() + nLastOffset;
2778 const sal_Unicode * const pStop = aStr.getStr() + aStr.getLength();
2779 while (p < pStop)
2780 {
2781 if (!*p)
2782 {
2783 // Skip embedded null-characters. They don't change
2784 // anything and are handled at a higher level.
2785 ++p;
2786 continue;
2787 }
2788
2789 if (nQuotes)
2790 {
2791 if (*p == cFieldQuote)
2792 {
2793 if (bFieldStart)
2794 {
2795 ++nQuotes;
2796 bFieldStart = false;
2797 eQuoteState = FIELDSTART_QUOTE;
2798 nFirstLineLength = aStr.getLength();
2799 nFirstLineStreamPos = rStream.Tell();
2800 }
2801 // Do not detect a FIELDSTART_QUOTE if not in
2802 // bFieldStart mode, in which case for unquoted content
2803 // we are in FIELDEND_QUOTE state.
2804 else if (eQuoteState != FIELDEND_QUOTE)
2805 {
2806 eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote, rcDetectSep);
2807
2808 if (eRetryState == RetryState::ALLOW && rcDetectSep)
2809 {
2810 eRetryState = RetryState::RETRY;
2811 rFieldSeparators += OUStringChar(rcDetectSep);
2812 pSeps = rFieldSeparators.getStr();
2813 goto Label_RetryWithNewSep;
2814 }
2815
2816 // DONTKNOW_QUOTE is an embedded unescaped quote we
2817 // don't count for pairing.
2818 if (eQuoteState != DONTKNOW_QUOTE)
2819 ++nQuotes;
2820 }
2821 }
2822 else if (eQuoteState == FIELDEND_QUOTE)
2823 {
2824 if (bFieldStart)
2825 // If blank is a separator it starts a field, if it
2826 // is not and thus maybe leading before quote we
2827 // are still at start of field regarding quotes.
2828 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2829 else
2830 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2831 }
2832 }
2833 else
2834 {
2835 if (*p == cFieldQuote && bFieldStart)
2836 {
2837 nQuotes = 1;
2838 eQuoteState = FIELDSTART_QUOTE;
2839 bFieldStart = false;
2840 nFirstLineLength = aStr.getLength();
2841 nFirstLineStreamPos = rStream.Tell();
2842 }
2843 else if (eQuoteState == FIELDEND_QUOTE)
2844 {
2845 // This also skips leading blanks at beginning of line
2846 // if followed by a quote. It's debatable whether we
2847 // actually want that or not, but congruent with what
2848 // ScanNextFieldFromString() does.
2849 if (bFieldStart)
2850 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2851 else
2852 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2853 }
2854 }
2855 // A quote character inside a field content does not start
2856 // a quote.
2857 ++p;
2858 }
2859
2860 if ((nQuotes & 1) == 0)
2861 // We still have a (theoretical?) problem here if due to
2862 // nArbitraryLineLengthLimit (or nMaxSourceLines below) we
2863 // split a string right between a doubled quote pair.
2864 break;
2865 else if (eQuoteState == DONTKNOW_QUOTE)
2866 // A single unescaped quote somewhere in a quote started
2867 // field, most likely that was not meant to have embedded
2868 // linefeeds either.
2869 break;
2870 else if (++nLine >= nMaxSourceLines && nMaxSourceLines > 0)
2871 // Unconditionally increment nLine even if nMaxSourceLines==0
2872 // so it can be observed in debugger.
2873 break;
2874 else
2875 {
2876 nLastOffset = aStr.getLength();
2877 OUString aNext;
2879 if (!rStream.eof())
2880 aStr += "\n" + aNext;
2881 }
2882 }
2883 if (nQuotes & 1)
2884 {
2885 // No closing quote at all. A single quote at field start => no
2886 // embedded linefeeds for that field, take only first logical line.
2887 aStr = aStr.copy( 0, nFirstLineLength);
2888 rStream.Seek( nFirstLineStreamPos);
2889 }
2890 }
2891 return aStr;
2892}
2893
2894/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SCCOL MAXCOLCOUNT
Definition: address.hxx:63
ScRefFlags
Definition: address.hxx:158
const SCROW SCROWS32K
Definition: address.hxx:92
const SCROW SCROW_MAX
Definition: address.hxx:55
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
static OUString GetAppName()
css::uno::Sequence< css::i18n::CalendarItem2 > getMonths() const
void setValue(sal_Int16 nFieldIndex, sal_Int16 nValue)
sal_Int16 getNumberOfMonthsInYear() const
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
std::unique_ptr< EditTextObject > CreateTextObject()
SvStream * IsValid(SvStream &)
SCTAB Tab() const
Definition: address.hxx:283
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1537
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
static sal_Unicode GetWeightedFieldSep(const OUString &rFieldSeps, bool bDecodeNumbers)
From the import field separators obtain the one most likely to be used for export,...
Definition: asciiopt.cxx:287
sal_Unicode GetTextSep() const
Definition: asciiopt.hxx:68
const OUString & GetFieldSeps() const
Definition: asciiopt.hxx:59
static OUString GetString(const ScRefCellValue &rCell, sal_uInt32 nFormat, const Color **ppColor, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bNullVals=true, bool bFormula=false, bool bUseStarFormat=false)
Definition: cellform.cxx:31
std::unique_ptr< ScTokenArray > CompileString(const OUString &rFormula)
Tokenize formula expression string into an array of tokens.
Definition: compiler.cxx:4691
static weld::Window * GetActiveDialogParent()
Definition: docsh.cxx:3112
void SetDocumentModified()
Definition: docsh.cxx:2982
void PostDataChanged()
Definition: docsh3.cxx:93
ScDrawLayer * MakeDrawLayer()
Definition: docsh2.cxx:169
void PostPaint(SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart, sal_uInt16 nExtFlags=0)
Definition: docsh3.cxx:101
bool AdjustRowHeight(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
merge with docfunc
Definition: docsh5.cxx:405
virtual SfxUndoManager * GetUndoManager() override
Definition: docsh.cxx:2968
static SCTAB GetCurTab()
Definition: docsh4.cxx:2614
Accessor class to ScDocument.
void setEditCell(const ScAddress &rPos, std::unique_ptr< EditTextObject > pEditText)
void setStringCell(const ScAddress &rPos, const OUString &rStr)
ScDocument & getDoc()
void setNumericCell(const ScAddress &rPos, double fVal)
void setAutoInput(const ScAddress &rPos, const OUString &rStr, const ScSetStringParam *pStringParam=nullptr)
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:898
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3640
SC_DLLPUBLIC ScFormulaCell * SetFormulaCell(const ScAddress &rPos, ScFormulaCell *pCell)
Set formula cell, and transfer its ownership to the document.
Definition: documen2.cxx:1149
bool ValidRow(SCROW nRow) const
Definition: document.hxx:900
SC_DLLPUBLIC void InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData &rMark, const OUString &rFormula, const ScTokenArray *p=nullptr, const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: documen4.cxx:259
ScClipParam & GetClipParam()
Definition: document.cxx:2564
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1018
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
bool IsClipboard() const
Definition: document.hxx:1594
SC_DLLPUBLIC bool RowFiltered(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4475
SC_DLLPUBLIC void SetTextCell(const ScAddress &rPos, const OUString &rStr)
Call this if you are not sure whether to put this as an edit text or a simple text.
Definition: document.cxx:3452
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6050
SC_DLLPUBLIC void EnsureTable(SCTAB nTab)
Definition: documen2.cxx:577
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:492
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
SC_DLLPUBLIC void CheckLinkFormulaNeedingCheck(const ScTokenArray &rCode)
Check token array and set link check if ocDde/ocWebservice is contained.
Definition: documen8.cxx:1149
SC_DLLPUBLIC ScFieldEditEngine & GetEditEngine()
Definition: documen2.cxx:483
SC_DLLPUBLIC double GetValue(const ScAddress &rPos) const
Definition: document.cxx:3626
void BroadcastCells(const ScRange &rRange, SfxHintId nHint, bool bBroadcastSingleBroadcasters=true)
Definition: documen7.cxx:158
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2628
SC_DLLPUBLIC void ApplyPattern(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr &rAttr)
Definition: document.cxx:4747
SC_DLLPUBLIC void SetNumberFormat(const ScAddress &rPos, sal_uInt32 nNumberFormat)
Definition: document.cxx:3682
SC_DLLPUBLIC bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: document.cxx:3391
void CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, InsertDeleteFlags nFlags, bool bMarked, ScDocument &rDestDoc, const ScMarkData *pMarks=nullptr, bool bColRowFlags=true)
Definition: document.cxx:2041
SC_DLLPUBLIC void SetValue(SCCOL nCol, SCROW nRow, SCTAB nTab, const double &rVal)
Definition: document.cxx:3477
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4741
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:899
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3750
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC ScRangeName * GetRangeName(SCTAB nTab) const
Definition: documen3.cxx:171
SC_DLLPUBLIC void DeleteAreaTab(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, InsertDeleteFlags nDelFlag)
Definition: document.cxx:1920
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3505
bool IsBlockEmpty(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const
Definition: document.cxx:5288
bool IsUndoEnabled() const
Definition: document.hxx:1595
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:619
bool IsEditable() const
Definition: editable.hxx:84
TranslateId GetMessageId() const
Definition: editable.cxx:152
virtual std::unique_ptr< ScEEAbsImport > CreateHTMLImport(ScDocument *pDocP, const OUString &rBaseURL, const ScRange &rRange)=0
virtual void ScExportDif(SvStream &, ScDocument *, const ScAddress &rOutPos, const rtl_TextEncoding eDest)=0
virtual void ScExportHTML(SvStream &, const OUString &rBaseURL, ScDocument *, const ScRange &rRange, const rtl_TextEncoding eDest, bool bAll, const OUString &rStreamPath, OUString &rNonConvertibleChars, const OUString &rFilterOptions)=0
virtual ErrCode ScImportDif(SvStream &, ScDocument *, const ScAddress &rInsPos, const rtl_TextEncoding eSrc)=0
virtual void ScExportRTF(SvStream &, ScDocument *, const ScRange &rRange, const rtl_TextEncoding eDest)=0
virtual std::unique_ptr< ScEEAbsImport > CreateRTFImport(ScDocument *pDoc, const ScRange &rRange)=0
static SC_DLLPUBLIC ScFormatFilterPlugin & Get()
Definition: impex.cxx:2684
void GetMatColsRows(SCCOL &nCols, SCROW &nRows) const
ScMatrixMode GetMatrixFlag() const
bool GetMatrixOrigin(const ScDocument &rDoc, ScAddress &rPos) const
OUString GetFormula(const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
static const sal_Unicode * UnicodeStrChr(const sal_Unicode *pStr, sal_Unicode c)
strchr() functionality on unicode, as long as we need it for FormulaToken etc.
Definition: global.cxx:691
static SC_DLLPUBLIC LanguageType eLnge
Definition: global.hxx:560
static sal_Unicode ToUpperAlpha(sal_Unicode c)
Definition: global.hxx:631
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1064
static const OUString & GetClipDocName()
Definition: global.cxx:494
ScRange aRange
Definition: impex.hxx:53
sal_Unicode cStr
Definition: impex.hxx:60
static void EmbeddedNullTreatment(OUString &rStr)
Definition: impex.cxx:1855
static sal_Int32 CountVisualWidth(const OUString &rStr, sal_Int32 &nIdx, sal_Int32 nMaxWidth)
ScImportExport::CountVisualWidth Count the width of string visually ( in multiple of western characte...
Definition: impex.cxx:559
OUString aStreamPath
Definition: impex.hxx:54
void SetFilterOptions(const OUString &rFilterOptions)
Definition: impex.cxx:220
bool Doc2Dif(SvStream &)
Definition: impex.cxx:2577
bool Doc2HTML(SvStream &, const OUString &)
Definition: impex.cxx:2562
static void WriteUnicodeOrByteEndl(SvStream &rStrm)
Definition: impex.cxx:537
bool Doc2RTF(SvStream &)
Definition: impex.cxx:2570
bool bOverflowCell
Definition: impex.hxx:68
bool bOverflowCol
Definition: impex.hxx:67
ScExportTextOptions mExportTextOptions
Definition: impex.hxx:75
bool ExportByteString(OString &, rtl_TextEncoding, SotClipboardFormatId)
Definition: impex.cxx:369
bool bUndo
Definition: impex.hxx:65
bool mbImportBroadcast
Definition: impex.hxx:70
static bool IsFormatSupported(SotClipboardFormatId nFormat)
Definition: impex.cxx:225
bool ExportString(OUString &, SotClipboardFormatId)
Definition: impex.cxx:340
static void WriteUnicodeOrByteString(SvStream &rStrm, std::u16string_view rString, bool bZero=false)
Definition: impex.cxx:508
ScDocument & rDoc
Definition: impex.hxx:51
sal_uInt32 nSizeLimit
Definition: impex.hxx:57
bool StartPaste()
Definition: impex.cxx:237
bool ExtText2Doc(SvStream &)
Definition: impex.cxx:1577
std::unique_ptr< ScAsciiOptions > pExtOptions
Definition: impex.hxx:77
bool Dif2Doc(SvStream &)
Definition: impex.cxx:2584
bool Text2Doc(SvStream &)
Definition: impex.cxx:975
bool ExportStream(SvStream &, const OUString &rBaseURL, SotClipboardFormatId)
Definition: impex.cxx:435
bool bFormulas
Definition: impex.hxx:61
bool Doc2Text(SvStream &)
Definition: impex.cxx:1972
bool ImportString(const OUString &, SotClipboardFormatId)
Definition: impex.cxx:316
bool RTF2Doc(SvStream &, const OUString &rBaseURL)
Definition: impex.cxx:2615
static const sal_Unicode * ScanNextFieldFromString(const sal_Unicode *p, OUString &rField, sal_Unicode cStr, const sal_Unicode *pSeps, bool bMergeSeps, bool &rbIsQuoted, bool &rbOverflowCell, bool bRemoveSpace)
Definition: impex.cxx:1871
bool bSingle
Definition: impex.hxx:64
bool Sylk2Doc(SvStream &)
Definition: impex.cxx:2092
ScImportExport(ScDocument &)
Definition: impex.cxx:112
OUString maFilterOptions
Definition: impex.hxx:56
bool ImportStream(SvStream &, const OUString &rBaseURL, SotClipboardFormatId)
Definition: impex.cxx:395
void EndPaste(bool bAutoRowHeight=true)
Definition: impex.cxx:261
bool bIncludeFiltered
Definition: impex.hxx:62
static void SetNoEndianSwap(SvStream &rStrm)
only if stream is only used in own (!) memory
Definition: impex.cxx:590
void SetExtOptions(const ScAsciiOptions &rOpt)
Definition: impex.cxx:207
sal_Unicode cSep
Definition: impex.hxx:59
OUString aNonConvertibleChars
Definition: impex.hxx:55
bool HTML2Doc(SvStream &, const OUString &rBaseURL)
Definition: impex.cxx:2634
bool Doc2Sylk(SvStream &)
Definition: impex.cxx:2423
~ScImportExport() COVERITY_NOEXCEPT_FALSE
Definition: impex.cxx:201
bool ExportData(std::u16string_view rMimeType, css::uno::Any &rValue)
Definition: impex.cxx:289
bool bOverflowRow
Definition: impex.hxx:66
ScDocShell * pDocSh
Definition: impex.hxx:50
SCROW nMaxImportRow
Definition: impex.hxx:58
std::unique_ptr< ScDocument, o3tl::default_delete< ScDocument > > pUndoDoc
Definition: impex.hxx:52
ScImportStringStream(const OUString &rStr)
Definition: impex.cxx:2726
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
void SelectTable(SCTAB nTab, bool bNew)
Definition: markdata.cxx:157
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:92
SfxItemSet & GetItemSet()
Definition: patattr.hxx:192
SC_DLLPUBLIC ScRangeData * findByUpperName(const OUString &rName)
Definition: rangenam.cxx:704
OUString Format(const ScDocument &rDocument, ScRefFlags nFlags=ScRefFlags::ZERO, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1, bool bFullAddressNotation=false) const
Returns string with formatted cell range from aStart to aEnd, according to provided address conventio...
Definition: address.cxx:2170
ScAddress aEnd
Definition: address.hxx:498
ScRefFlags Parse(const OUString &, const ScDocument &, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1, ScAddress::ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1700
ScAddress aStart
Definition: address.hxx:497
Warning box for "Replace cell contents?".
Definition: warnbox.hxx:27
virtual short run() override
Opens dialog if IsDialogEnabled() returns true.
Definition: warnbox.cxx:35
static bool SC_DLLPUBLIC isMultiline(std::u16string_view rStr)
Definition: stringutil.cxx:425
void UpdateInputHandler(bool bForce=false, bool bStopEditing=true)
Definition: tabvwsha.cxx:690
static ScTabViewShell * GetActiveViewShell()
Definition: tabvwsh4.cxx:1076
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
OUString GetTitle(sal_uInt16 nMaxLen=0) const
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
static SotClipboardFormatId GetFormatIdFromMimeType(std::u16string_view rMimeType)
const void * GetData()
virtual sal_uInt64 TellEnd() override
sal_uInt32 GetStandardIndex(LanguageType eLnge=LANGUAGE_DONTKNOW)
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
bool PutandConvertEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge, bool bConvertDateOrder, bool bReplaceBooleanEquivalent=true)
SvNumFormatType GetType(sal_uInt32 nFIndex) const
sal_uInt16 ExpandTwoDigitYear(sal_uInt16 nYear) const
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
sal_uInt64 Tell() const
void StartReadingUnicodeText(rtl_TextEncoding eReadBomCharSet)
void SetEndian(SvStreamEndian SvStreamEndian)
LineEnd GetLineDelimiter() const
std::size_t WriteBytes(const void *pData, std::size_t nSize)
bool eof() const
SvStream & WriteUChar(unsigned char nChar)
bool ReadUniOrByteStringLine(OUString &rStr, rtl_TextEncoding eSrcCharSet, sal_Int32 nMaxCodepointsToRead=0xFFFE)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
SvStream & WriteOString(std::string_view rStr)
bool ReadLine(OStringBuffer &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
SvStreamEndian GetEndian() const
sal_uInt64 Seek(sal_uInt64 nPos)
void SetStreamCharSet(rtl_TextEncoding eCharSet)
SvStream & WriteChar(char nChar)
rtl_TextEncoding GetStreamCharSet() const
ErrCode GetError() const
static bool IsFuzzing()
const sal_uInt8 SC_COL_TEXT
Definition: csvcontrol.hxx:55
const sal_uInt8 SC_COL_MDY
Definition: csvcontrol.hxx:56
const sal_uInt8 SC_COL_YMD
Definition: csvcontrol.hxx:58
const sal_uInt8 SC_COL_STANDARD
Definition: csvcontrol.hxx:54
const sal_uInt8 SC_COL_DMY
Definition: csvcontrol.hxx:57
const sal_uInt8 SC_COL_ENGLISH
Definition: csvcontrol.hxx:60
const sal_uInt8 SC_COL_SKIP
Definition: csvcontrol.hxx:59
std::unique_ptr< ScDocument, o3tl::default_delete< ScDocument > > ScDocumentUniquePtr
Definition: document.hxx:2720
@ SCDOCMODE_UNDO
Definition: document.hxx:258
float u
#define ERRCODE_NONE
DocumentType eType
SotClipboardFormatId
ScFormatFilterPlugin * ScFilterCreate()
Definition: ftools.cxx:358
CellType
Definition: global.hxx:272
@ CELLTYPE_EDIT
Definition: global.hxx:277
@ CELLTYPE_STRING
Definition: global.hxx:275
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_NONE
Definition: global.hxx:273
@ CELLTYPE_VALUE
Definition: global.hxx:274
InsertDeleteFlags
Definition: global.hxx:149
@ NOCAPTIONS
Sparklines in a cell.
static QuoteType lcl_isEscapedOrFieldEndQuote(sal_Int32 nQuotes, const sal_Unicode *p, const sal_Unicode *pSeps, sal_Unicode cStr, sal_Unicode &rcDetectSep)
Determine if *p is a quote that is escaped by being doubled or ends a quoted field.
Definition: impex.cxx:688
static const sal_Unicode * lcl_ScanString(const sal_Unicode *p, OUString &rField, const sal_Unicode *pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool &rbOverflowCell)
Scan for a quoted string.
Definition: impex.cxx:753
static const sal_Unicode * lcl_UnicodeStrChr(const sal_Unicode *pStr, sal_Unicode c)
Definition: impex.cxx:2714
static void lcl_UnescapeSylk(OUString &rString, SylkVersion eVersion)
Definition: impex.cxx:833
static bool lcl_appendLineData(OUString &rField, const sal_Unicode *p1, const sal_Unicode *p2)
Append characters of [p1,p2) to rField.
Definition: impex.cxx:710
ScFormatFilterPlugin *(* FilterFn)()
Definition: impex.cxx:2683
static bool lcl_PutString(ScDocumentImport &rDocImport, bool bUseDocImport, SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rStr, sal_uInt8 nColFormat, SvNumberFormatter *pFormatter, bool bDetectNumFormat, bool bDetectSciNumFormat, bool bEvaluateFormulas, bool bSkipEmptyCells, const ::utl::TransliterationWrapper &rTransliteration, CalendarWrapper &rCalendar, const ::utl::TransliterationWrapper *pSecondTransliteration, CalendarWrapper *pSecondCalendar)
Definition: impex.cxx:1072
static OUString lcl_GetFixed(const OUString &rLine, sal_Int32 nStart, sal_Int32 nNext, bool &rbIsQuoted, bool &rbOverflowCell)
Definition: impex.cxx:1535
static void lcl_WriteSimpleString(SvStream &rStrm, std::u16string_view rString)
Definition: impex.cxx:970
static bool lcl_isFieldEnd(sal_Unicode c, const sal_Unicode *pSeps)
Definition: impex.cxx:599
static const sal_Unicode * lcl_ScanSylkString(const sal_Unicode *p, OUString &rString, SylkVersion eVersion)
Definition: impex.cxx:846
static QuoteType lcl_isFieldEndQuote(const sal_Unicode *p, const sal_Unicode *pSeps, sal_Unicode &rcDetectSep)
Determine if *p is a quote that ends a quoted field.
Definition: impex.cxx:625
constexpr sal_Int32 nArbitraryLineLengthLimit
Definition: impex.cxx:83
static const sal_Unicode * lcl_ScanSylkFormula(const sal_Unicode *p, OUString &rString, SylkVersion eVersion)
Definition: impex.cxx:888
constexpr sal_Int32 nArbitraryCellLengthLimit
Definition: impex.cxx:82
static void thisModule()
Definition: impex.cxx:2673
OUString ReadCsvLine(SvStream &rStream, bool bEmbeddedLineBreak, OUString &rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode &rcDetectSep, sal_uInt32 nMaxSourceLines)
Read a CSV (comma separated values) data line using ReadUniOrByteStringLine().
Definition: impex.cxx:2738
static void lcl_WriteString(SvStream &rStrm, OUString &rString, sal_Unicode cQuote, sal_Unicode cEsc)
Definition: impex.cxx:952
sal_Int32 nIndex
Mode eMode
void * p
sal_Int64 n
#define LANGUAGE_ENGLISH_US
LINEEND_LF
LINEEND_CR
LineEnd GetSystemLineEnd()
TOOLS_DLLPUBLIC OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
sal_uInt16 nPos
#define SAL_WARN(area, stream)
aStr
std::unique_ptr< sal_Int32[]> pData
double getLength(const B2DPolygon &rCandidate)
Reference< XComponentContext > getProcessComponentContext()
int i
void SvStream & rStrm
std::enable_if< std::is_signed< T >::value, bool >::type checked_add(T a, T b, T &result)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
CAUTION! The following defines must be in the same namespace as the respective type.
Definition: broadcast.cxx:15
READ
#define SFX_TITLE_FULLNAME
ConversionMode mode
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
static SfxItemSet & rSet
StreamMode
TOOLS_DLLPUBLIC SvStream & endl(SvStream &rStr)
bool isMultiRange() const
Definition: clipparam.cxx:38
sal_Unicode mcSeparatorConvertTo
Definition: impex.hxx:44
NewlineConversion meNewlineConversion
Definition: impex.hxx:43
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
CellType getType() const
Definition: cellvalue.hxx:133
Store parameters used in the ScDocument::SetString() method.
Definition: stringutil.hxx:35
bool mbCheckLinkFormula
When true and the string results in a compiled formula, check the formula tokens for presence of func...
Definition: stringutil.hxx:103
#define SVLIBRARY(Base)
unsigned char sal_uInt8
#define SAL_MAX_UINT16
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode
signed char sal_Int8
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
RET_YES
size_t pos
static N to(double f)
Definition: xltools.cxx:275
SvNumFormatType