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