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 )
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 )
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 )
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 )
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
1581 SCCOL nStartCol = aRange.aStart.Col();
1582 SCCOL nEndCol = aRange.aEnd.Col();
1583 SCROW nStartRow = aRange.aStart.Row();
1584 const SCTAB nTab = aRange.aStart.Tab();
1585
1586 bool bFixed = pExtOptions->IsFixedLen();
1587 OUString aSeps = pExtOptions->GetFieldSeps(); // Need non-const for ReadCsvLine(),
1588 const sal_Unicode* pSeps = aSeps.getStr(); // but it will be const anyway (asserted below).
1589 bool bMerge = pExtOptions->IsMergeSeps();
1590 bool bRemoveSpace = pExtOptions->IsRemoveSpace();
1591 sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
1592 const sal_Int32* pColStart = pExtOptions->GetColStart();
1593 const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
1594 tools::Long nSkipLines = pExtOptions->GetStartRow();
1595
1596 LanguageType eDocLang = pExtOptions->GetLanguage();
1597 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eDocLang);
1598 bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1599 bool bEvaluateFormulas = pExtOptions->IsEvaluateFormulas();
1600 bool bSkipEmptyCells = pExtOptions->IsSkipEmptyCells();
1601
1602 // For date recognition
1603 ::utl::TransliterationWrapper aTransliteration(
1604 comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE );
1605 aTransliteration.loadModuleIfNeeded( eDocLang );
1606 CalendarWrapper aCalendar( comphelper::getProcessComponentContext() );
1607 aCalendar.loadDefaultCalendar(
1608 LanguageTag::convertToLocale( eDocLang ) );
1609 std::unique_ptr< ::utl::TransliterationWrapper > pEnglishTransliteration;
1610 std::unique_ptr< CalendarWrapper > pEnglishCalendar;
1611 if ( eDocLang != LANGUAGE_ENGLISH_US )
1612 {
1613 pEnglishTransliteration.reset(new ::utl::TransliterationWrapper (
1614 comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE ));
1615 aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1616 pEnglishCalendar.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
1617 pEnglishCalendar->loadDefaultCalendar(
1618 LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) );
1619 }
1620
1621 OUString aLine;
1622 OUString aCell;
1623 sal_uInt16 i;
1624 SCROW nRow = nStartRow;
1625 sal_Unicode cDetectSep = 0xffff; // No separator detection here.
1626
1627 while(--nSkipLines>0)
1628 {
1629 aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep); // content is ignored
1630 if ( rStrm.eof() )
1631 break;
1632 }
1633
1634 // Determine range for Undo.
1635 // We don't need this during import of a file to a new sheet or document...
1636 bool bDetermineRange = bUndo;
1637 bool bColumnsAreDetermined = false;
1638
1639 // Row heights don't need to be adjusted on the fly if EndPaste() is called
1640 // afterwards, which happens only if bDetermineRange. This variable also
1641 // survives the toggle of bDetermineRange down at the end of the do{} loop.
1642 bool bRangeIsDetermined = bDetermineRange;
1643
1644 bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1645
1646 sal_uInt64 nOriginalStreamPos = rStrm.Tell();
1647
1648 SCROW nFirstUpdateRowHeight = SCROW_MAX;
1649 SCROW nLastUpdateRowHeight = -1;
1650
1651 ScDocumentImport aDocImport(rDoc);
1652 do
1653 {
1654 for( ;; )
1655 {
1656 aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep);
1657 if ( rStrm.eof() && aLine.isEmpty() )
1658 break;
1659
1660 assert(pSeps == aSeps.getStr());
1661
1662 if ( nRow > rDoc.MaxRow() )
1663 {
1664 bOverflowRow = true; // display warning on import
1665 break; // for
1666 }
1667
1668 if (!bDetermineRange)
1669 EmbeddedNullTreatment( aLine);
1670
1671 sal_Int32 nLineLen = aLine.getLength();
1672 SCCOL nCol = nStartCol;
1673 bool bMultiLine = false;
1674 if ( bFixed ) // Fixed line length
1675 {
1676 if (bDetermineRange)
1677 {
1678 if (!bColumnsAreDetermined)
1679 {
1680 // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it
1681 // is only an overflow if there is really data following to
1682 // be put behind the last column, which doesn't happen if
1683 // info is SC_COL_SKIP.
1684 for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
1685 {
1686 const sal_uInt8 nFmt = pColFormat[i];
1687 if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
1688 {
1689 if (nCol > rDoc.MaxCol())
1690 bOverflowCol = true; // display warning on import
1691 ++nCol;
1692 }
1693 }
1694 bColumnsAreDetermined = true;
1695 }
1696 }
1697 else
1698 {
1699 sal_Int32 nStartIdx = 0;
1700 // Same maxcol+1 check reason as above.
1701 for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
1702 {
1703 sal_Int32 nNextIdx = nStartIdx;
1704 if (i + 1 < nInfoCount)
1705 CountVisualWidth( aLine, nNextIdx, pColStart[i+1] - pColStart[i] );
1706 else
1707 nNextIdx = nLineLen;
1708 sal_uInt8 nFmt = pColFormat[i];
1709 if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
1710 {
1711 if (nCol > rDoc.MaxCol())
1712 bOverflowCol = true; // display warning on import
1713 else
1714 {
1715 bool bIsQuoted = false;
1716 aCell = lcl_GetFixed( aLine, nStartIdx, nNextIdx, bIsQuoted, bOverflowCell );
1717 if (bIsQuoted && bQuotedAsText)
1718 nFmt = SC_COL_TEXT;
1719
1720 bMultiLine |= lcl_PutString(
1721 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1722 &aNumFormatter, bDetectNumFormat, bEvaluateFormulas, bSkipEmptyCells,
1723 aTransliteration, aCalendar,
1724 pEnglishTransliteration.get(), pEnglishCalendar.get());
1725 }
1726 ++nCol;
1727 }
1728 nStartIdx = nNextIdx;
1729 }
1730 }
1731 }
1732 else // Search for the separator
1733 {
1734 SCCOL nSourceCol = 0;
1735 sal_uInt16 nInfoStart = 0;
1736 const sal_Unicode* p = aLine.getStr();
1737 // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it is only an
1738 // overflow if there is really data following to be put behind
1739 // the last column, which doesn't happen if info is
1740 // SC_COL_SKIP.
1741 while (*p && nCol <= rDoc.MaxCol()+1)
1742 {
1743 bool bIsQuoted = false;
1745 cStr, pSeps, bMerge, bIsQuoted, bOverflowCell, bRemoveSpace );
1746
1748 for ( i=nInfoStart; i<nInfoCount; i++ )
1749 {
1750 if ( pColStart[i] == nSourceCol + 1 ) // pColStart is 1-based
1751 {
1752 nFmt = pColFormat[i];
1753 nInfoStart = i + 1; // ColInfos are in succession
1754 break; // for
1755 }
1756 }
1757 if ( nFmt != SC_COL_SKIP )
1758 {
1759 if (nCol > rDoc.MaxCol())
1760 bOverflowCol = true; // display warning on import
1761 else if (!bDetermineRange)
1762 {
1763 if (bIsQuoted && bQuotedAsText)
1764 nFmt = SC_COL_TEXT;
1765
1766 bMultiLine |= lcl_PutString(
1767 aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
1768 &aNumFormatter, bDetectNumFormat, bEvaluateFormulas, bSkipEmptyCells,
1769 aTransliteration, aCalendar,
1770 pEnglishTransliteration.get(), pEnglishCalendar.get());
1771 }
1772 ++nCol;
1773 }
1774
1775 ++nSourceCol;
1776 }
1777 }
1778 if (nEndCol < nCol)
1779 nEndCol = nCol;
1780
1781 if (!bDetermineRange)
1782 {
1783 if (bMultiLine && !bRangeIsDetermined && pDocSh)
1784 { // Adjust just once at the end for a whole range.
1785 nFirstUpdateRowHeight = std::min( nFirstUpdateRowHeight, nRow );
1786 nLastUpdateRowHeight = std::max( nLastUpdateRowHeight, nRow );
1787 }
1788 xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1789 }
1790 ++nRow;
1791 }
1792 // so far nRow/nEndCol pointed to the next free
1793 if (nRow > nStartRow)
1794 --nRow;
1795 if (nEndCol > nStartCol)
1796 nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), rDoc.MaxCol());
1797
1798 if (bDetermineRange)
1799 {
1800 aRange.aEnd.SetCol( nEndCol );
1801 aRange.aEnd.SetRow( nRow );
1802
1803 if ( !mbApi && nStartCol != nEndCol &&
1804 !rDoc.IsBlockEmpty( nStartCol + 1, nStartRow, nEndCol, nRow, nTab ) )
1805 {
1807 if (aBox.run() != RET_YES)
1808 {
1809 return false;
1810 }
1811 }
1812
1813 rStrm.Seek( nOriginalStreamPos );
1814 nRow = nStartRow;
1815 if (!StartPaste())
1816 {
1817 EndPaste(false);
1818 return false;
1819 }
1820 }
1821
1822 bDetermineRange = !bDetermineRange; // toggle
1823 } while (!bDetermineRange);
1824
1825 if ( !mbOverwriting )
1826 aDocImport.finalize();
1827
1828 xProgress.reset(); // make room for AdjustRowHeight progress
1829
1830 if( nFirstUpdateRowHeight < nLastUpdateRowHeight && pDocSh )
1831 pDocSh->AdjustRowHeight( nFirstUpdateRowHeight, nLastUpdateRowHeight, nTab);
1832
1833 if (bRangeIsDetermined)
1834 EndPaste(false);
1835
1836 if (mbImportBroadcast && !mbOverwriting)
1837 {
1838 rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
1839 pDocSh->PostDataChanged();
1840 }
1841 return true;
1842}
1843
1845{
1846 // A nasty workaround for data with embedded NULL characters. As long as we
1847 // can't handle them properly as cell content (things assume 0-terminated
1848 // strings at too many places) simply strip all NULL characters from raw
1849 // data. Excel does the same. See fdo#57841 for sample data.
1850
1851 // The normal case is no embedded NULL, check first before de-/allocating
1852 // ustring stuff.
1853 sal_Unicode cNull = 0;
1854 if (sal_Int32 pos = rStr.indexOf(cNull); pos >= 0)
1855 {
1856 rStr = rStr.replaceAll(std::u16string_view(&cNull, 1), u"", pos);
1857 }
1858}
1859
1861 OUString& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted,
1862 bool& rbOverflowCell, bool bRemoveSpace )
1863{
1864 rbIsQuoted = false;
1865 rField.clear();
1866 const sal_Unicode cBlank = ' ';
1867 if (cStr && !ScGlobal::UnicodeStrChr(pSeps, cBlank))
1868 {
1869 // Cope with broken generators that put leading blanks before a quoted
1870 // field, like "field1", "field2", "..."
1871 // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1872 const sal_Unicode* pb = p;
1873 while (*pb == cBlank)
1874 ++pb;
1875 if (*pb == cStr)
1876 p = pb;
1877 }
1878 if (cStr && *p == cStr) // String in quotes
1879 {
1880 rbIsQuoted = true;
1881 const sal_Unicode* p1;
1882 p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DoubledQuoteMode::ESCAPE, rbOverflowCell );
1883 while (!lcl_isFieldEnd( *p, pSeps))
1884 p++;
1885 // Append remaining unquoted and undelimited data (dirty, dirty) to
1886 // this field.
1887 if (p > p1)
1888 {
1889 const sal_Unicode* ptrim_f = p;
1890 if ( bRemoveSpace )
1891 {
1892 while ( ptrim_f > p1 && ( *(ptrim_f - 1) == cBlank ) )
1893 --ptrim_f;
1894 }
1895 if (!lcl_appendLineData( rField, p1, ptrim_f))
1896 rbOverflowCell = true;
1897 }
1898 if( *p )
1899 p++;
1900 }
1901 else // up to delimiter
1902 {
1903 const sal_Unicode* p0 = p;
1904 while (!lcl_isFieldEnd( *p, pSeps))
1905 p++;
1906 const sal_Unicode* ptrim_i = p0;
1907 const sal_Unicode* ptrim_f = p; // [ptrim_i,ptrim_f) is cell data after trimming
1908 if ( bRemoveSpace )
1909 {
1910 while ( ptrim_i < ptrim_f && *ptrim_i == cBlank )
1911 ++ptrim_i;
1912 while ( ptrim_f > ptrim_i && ( *(ptrim_f - 1) == cBlank ) )
1913 --ptrim_f;
1914 }
1915 if (!lcl_appendLineData( rField, ptrim_i, ptrim_f))
1916 rbOverflowCell = true;
1917 if( *p )
1918 p++;
1919 }
1920 if ( bMergeSeps ) // skip following delimiters
1921 {
1922 while (*p && ScGlobal::UnicodeStrChr( pSeps, *p))
1923 p++;
1924 }
1925 return p;
1926}
1927
1928namespace {
1929
1936bool hasLineBreaksOrSeps( const OUString& rStr, sal_Unicode cSep )
1937{
1938 const sal_Unicode* p = rStr.getStr();
1939 for (sal_Int32 i = 0, n = rStr.getLength(); i < n; ++i, ++p)
1940 {
1941 sal_Unicode c = *p;
1942 if (c == cSep)
1943 // separator found.
1944 return true;
1945
1946 switch (c)
1947 {
1948 case '\n':
1949 case '\r':
1950 // line break found.
1951 return true;
1952 default:
1953 ;
1954 }
1955 }
1956 return false;
1957}
1958
1959}
1960
1962{
1963 SCCOL nCol;
1964 SCROW nRow;
1965 SCCOL nStartCol = aRange.aStart.Col();
1966 SCROW nStartRow = aRange.aStart.Row();
1967 SCTAB nStartTab = aRange.aStart.Tab();
1968 SCCOL nEndCol = aRange.aEnd.Col();
1969 SCROW nEndRow = aRange.aEnd.Row();
1970 SCTAB nEndTab = aRange.aEnd.Tab();
1971
1972 if (!rDoc.GetClipParam().isMultiRange() && nStartTab == nEndTab)
1973 if (!rDoc.ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow ))
1974 return false;
1975
1976 OUString aCellStr;
1977
1978 bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1979
1980 // We need to cache sc::ColumnBlockPosition per each column, tab is always nStartTab.
1981 std::vector< sc::ColumnBlockPosition > blockPos( nEndCol - nStartCol + 1 );
1982 for( SCCOL i = nStartCol; i <= nEndCol; ++i )
1983 rDoc.InitColumnBlockPosition( blockPos[ i - nStartCol ], nStartTab, i );
1984 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1985 {
1986 if (bIncludeFiltered || !rDoc.RowFiltered( nRow, nStartTab ))
1987 {
1988 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1989 {
1990 ScAddress aPos(nCol, nRow, nStartTab);
1991 sal_uInt32 nNumFmt = rDoc.GetNumberFormat(aPos);
1992 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
1993
1994 ScRefCellValue aCell(rDoc, aPos, blockPos[ nCol - nStartCol ]);
1995 switch (aCell.getType())
1996 {
1997 case CELLTYPE_FORMULA:
1998 {
1999 if (bFormulas)
2000 {
2001 aCellStr = aCell.getFormula()->GetFormula();
2002 if( aCellStr.indexOf( cSep ) != -1 )
2003 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2004 else
2005 lcl_WriteSimpleString( rStrm, aCellStr );
2006 }
2007 else
2008 {
2009 const Color* pColor;
2010 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2011
2012 bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
2013 if( bMultiLineText )
2014 {
2016 aCellStr = aCellStr.replaceAll( "\n", " " );
2018 aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
2019 }
2020
2022 aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
2023
2024 if( mExportTextOptions.mbAddQuotes && ( aCellStr.indexOf( cSep ) != -1 ) )
2025 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2026 else
2027 lcl_WriteSimpleString( rStrm, aCellStr );
2028 }
2029 }
2030 break;
2031 case CELLTYPE_VALUE:
2032 {
2033 const Color* pColor;
2034 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2035 lcl_WriteSimpleString( rStrm, aCellStr );
2036 }
2037 break;
2038 case CELLTYPE_NONE:
2039 break;
2040 default:
2041 {
2042 const Color* pColor;
2043 aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
2044
2045 bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
2046 if( bMultiLineText )
2047 {
2049 aCellStr = aCellStr.replaceAll( "\n", " " );
2051 aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
2052 }
2053
2055 aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
2056
2057 if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCellStr, cSep) )
2058 lcl_WriteString( rStrm, aCellStr, cStr, cStr );
2059 else
2060 lcl_WriteSimpleString( rStrm, aCellStr );
2061 }
2062 }
2063 if( nCol < nEndCol )
2064 lcl_WriteSimpleString( rStrm, rtl::OUStringChar(cSep) );
2065 }
2066 // Do not append a line feed for one single cell.
2067 // NOTE: this Doc2Text() is only called for clipboard via
2068 // ScImportExport::ExportStream().
2069 if (nStartRow != nEndRow || nStartCol != nEndCol)
2071 if( rStrm.GetError() != ERRCODE_NONE )
2072 break;
2073 if( nSizeLimit && rStrm.Tell() > nSizeLimit )
2074 break;
2075 }
2076 }
2077
2078 return rStrm.GetError() == ERRCODE_NONE;
2079}
2080
2082{
2083 bool bOk = true;
2084 bool bMyDoc = false;
2085 SylkVersion eVersion = SylkVersion::OTHER;
2086
2087 // US-English separators for StringToDouble
2088 sal_Unicode const cDecSep = '.';
2089 sal_Unicode const cGrpSep = ',';
2090
2091 SCCOL nStartCol = aRange.aStart.Col();
2092 SCROW nStartRow = aRange.aStart.Row();
2093 SCCOL nEndCol = aRange.aEnd.Col();
2094 SCROW nEndRow = aRange.aEnd.Row();
2095 sal_uInt64 nOldPos = rStrm.Tell();
2096 bool bData = !bSingle;
2097 ::std::vector< sal_uInt32 > aFormats;
2098
2099 if( !bSingle)
2100 bOk = StartPaste();
2101
2102 while( bOk )
2103 {
2104 OUString aLine;
2105 OUString aText;
2106 OStringBuffer aByteLine;
2107 SCCOL nCol = nStartCol;
2108 SCROW nRow = nStartRow;
2109 SCCOL nRefCol = nCol;
2110 SCROW nRefRow = nRow;
2111 rStrm.Seek( nOldPos );
2112 for( ;; )
2113 {
2115 rStrm.ReadLine( aByteLine );
2116 aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
2117 if( rStrm.eof() )
2118 break;
2119 bool bInvalidCol = false;
2120 bool bInvalidRow = false;
2121 const sal_Unicode* p = aLine.getStr();
2122 sal_Unicode cTag = *p++;
2123 if( cTag == 'C' ) // Content
2124 {
2125 if( *p++ != ';' )
2126 return false;
2127
2128 bool bInvalidRefCol = false;
2129 bool bInvalidRefRow = false;
2130 while( *p )
2131 {
2132 sal_Unicode ch = *p++;
2134 switch( ch )
2135 {
2136 case 'X':
2137 {
2138 bInvalidCol = false;
2139 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
2140 if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
2141 {
2142 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
2143 nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
2144 bInvalidCol = bOverflowCol = true;
2145 }
2146 break;
2147 }
2148 case 'Y':
2149 {
2150 bInvalidRow = false;
2151 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
2152 if (bFail || nRow < 0 || nMaxImportRow < nRow)
2153 {
2154 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
2155 nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
2156 bInvalidRow = bOverflowRow = true;
2157 }
2158 break;
2159 }
2160 case 'C':
2161 {
2162 bInvalidRefCol = false;
2163 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nRefCol);
2164 if (bFail || nRefCol < 0 || rDoc.MaxCol() < nRefCol)
2165 {
2166 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;C invalid nRefCol=" << nRefCol);
2167 nRefCol = std::clamp<SCCOL>(nRefCol, 0, rDoc.MaxCol());
2168 bInvalidRefCol = bOverflowCol = true;
2169 }
2170 break;
2171 }
2172 case 'R':
2173 {
2174 bInvalidRefRow = false;
2175 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRefRow);
2176 if (bFail || nRefRow < 0 || nMaxImportRow < nRefRow)
2177 {
2178 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;R invalid nRefRow=" << nRefRow);
2179 nRefRow = std::clamp<SCROW>(nRefRow, 0, nMaxImportRow);
2180 bInvalidRefRow = bOverflowRow = true;
2181 }
2182 break;
2183 }
2184 case 'K':
2185 {
2186 if( !bSingle &&
2187 ( nCol < nStartCol || nCol > nEndCol
2188 || nRow < nStartRow || nRow > nEndRow
2189 || nCol > rDoc.MaxCol() || nRow > nMaxImportRow
2190 || bInvalidCol || bInvalidRow ) )
2191 break;
2192 if( !bData )
2193 {
2194 if( nRow > nEndRow )
2195 nEndRow = nRow;
2196 if( nCol > nEndCol )
2197 nEndCol = nCol;
2198 break;
2199 }
2200 bool bText;
2201 if( *p == '"' )
2202 {
2203 bText = true;
2204 aText.clear();
2205 p = lcl_ScanSylkString( p, aText, eVersion);
2206 }
2207 else
2208 bText = false;
2209 const sal_Unicode* q = p;
2210 while( *q && *q != ';' )
2211 q++;
2212 if ( (*q != ';' || *(q+1) != 'I') && !bInvalidCol && !bInvalidRow )
2213 { // don't ignore value
2214 if( bText )
2215 {
2218 ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
2219 }
2220 else
2221 {
2222 double fVal = rtl_math_uStringToDouble( p,
2223 aLine.getStr() + aLine.getLength(),
2224 cDecSep, cGrpSep, nullptr, nullptr );
2225 rDoc.SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
2226 }
2227 }
2228 }
2229 break;
2230 case 'E':
2231 case 'M':
2232 {
2233 if ( ch == 'M' )
2234 {
2235 if ( nRefCol < nCol )
2236 nRefCol = nCol;
2237 if ( nRefRow < nRow )
2238 nRefRow = nRow;
2239 if ( !bData )
2240 {
2241 if( nRefRow > nEndRow )
2242 nEndRow = nRefRow;
2243 if( nRefCol > nEndCol )
2244 nEndCol = nRefCol;
2245 }
2246 }
2247 if( !bMyDoc || !bData )
2248 break;
2249 aText = "=";
2250 p = lcl_ScanSylkFormula( p, aText, eVersion);
2251
2252 if (bInvalidCol || bInvalidRow || (ch == 'M' && (bInvalidRefCol || bInvalidRefRow)))
2253 break;
2254
2255 ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
2256 /* FIXME: do we want GRAM_ODFF_A1 instead? At the
2257 * end it probably should be GRAM_ODFF_R1C1, since
2258 * R1C1 is what Excel writes in SYLK, or even
2259 * better GRAM_ENGLISH_XL_R1C1. */
2261 ScCompiler aComp(rDoc, aPos, eGrammar);
2262 std::unique_ptr<ScTokenArray> xCode(aComp.CompileString(aText)); // ctor/InsertMatrixFormula did copy TokenArray
2264 if ( ch == 'M' )
2265 {
2267 aMark.SelectTable( aPos.Tab(), true );
2268 rDoc.InsertMatrixFormula( nCol, nRow, nRefCol,
2269 nRefRow, aMark, OUString(), xCode.get() );
2270 }
2271 else
2272 {
2273 ScFormulaCell* pFCell = new ScFormulaCell(
2274 rDoc, aPos, *xCode, eGrammar, ScMatrixMode::NONE);
2275 rDoc.SetFormulaCell(aPos, pFCell);
2276 }
2277 }
2278 break;
2279 }
2280 while( *p && *p != ';' )
2281 p++;
2282 if( *p )
2283 p++;
2284 }
2285 }
2286 else if( cTag == 'F' ) // Format
2287 {
2288 if( *p++ != ';' )
2289 return false;
2290 sal_Int32 nFormat = -1;
2291 while( *p )
2292 {
2293 sal_Unicode ch = *p++;
2295 switch( ch )
2296 {
2297 case 'X':
2298 {
2299 bInvalidCol = false;
2300 bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
2301 if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
2302 {
2303 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
2304 nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
2305 bInvalidCol = bOverflowCol = true;
2306 }
2307 break;
2308 }
2309 case 'Y':
2310 {
2311 bInvalidRow = false;
2312 bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
2313 if (bFail || nRow < 0 || nMaxImportRow < nRow)
2314 {
2315 SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
2316 nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
2317 bInvalidRow = bOverflowRow = true;
2318 }
2319 break;
2320 }
2321 case 'P' :
2322 if ( bData )
2323 {
2324 // F;P<n> sets format code of P;P<code> at
2325 // current position, or at ;X;Y if specified.
2326 // Note that ;X;Y may appear after ;P
2327 const sal_Unicode* p0 = p;
2328 while( *p && *p != ';' )
2329 p++;
2330 OUString aNumber(p0, p - p0);
2331 nFormat = aNumber.toInt32();
2332 }
2333 break;
2334 }
2335 while( *p && *p != ';' )
2336 p++;
2337 if( *p )
2338 p++;
2339 }
2340 if ( !bData )
2341 {
2342 if( nRow > nEndRow )
2343 nEndRow = nRow;
2344 if( nCol > nEndCol )
2345 nEndCol = nCol;
2346 }
2347 if ( 0 <= nFormat && o3tl::make_unsigned(nFormat) < aFormats.size() && !bInvalidCol && !bInvalidRow )
2348 {
2349 sal_uInt32 nKey = aFormats[nFormat];
2350 rDoc.ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
2352 }
2353 }
2354 else if( cTag == 'P' )
2355 {
2356 if ( bData && *p == ';' && *(p+1) == 'P' )
2357 {
2358 OUString aCode( p+2 );
2359
2360 sal_uInt32 nKey;
2361 sal_Int32 nCheckPos;
2362
2363 if (aCode.getLength() > 2048 && utl::ConfigManager::IsFuzzing())
2364 {
2365 // consider an excessive length as a failure when fuzzing
2366 nCheckPos = 1;
2367 }
2368 else
2369 {
2370 // unescape doubled semicolons
2371 aCode = aCode.replaceAll(";;", ";");
2372 // get rid of Xcl escape characters
2373 aCode = aCode.replaceAll("\x1b", "");
2375 rDoc.GetFormatTable()->PutandConvertEntry( aCode, nCheckPos, nType, nKey,
2377 }
2378
2379 if ( nCheckPos )
2380 nKey = 0;
2381
2382 aFormats.push_back( nKey );
2383 }
2384 }
2385 else if (cTag == 'I' && *p == 'D' && aLine.getLength() > 4)
2386 {
2387 aLine = aLine.copy(4);
2388 if (aLine == "CALCOOO32")
2389 eVersion = SylkVersion::OOO32;
2390 else if (aLine == "SCALC3")
2391 eVersion = SylkVersion::SCALC3;
2392 bMyDoc = (eVersion <= SylkVersion::OWN);
2393 }
2394 else if( cTag == 'E' ) // End
2395 break;
2396 }
2397 if( !bData )
2398 {
2399 aRange.aEnd.SetCol( nEndCol );
2400 aRange.aEnd.SetRow( nEndRow );
2401 bOk = StartPaste();
2402 bData = true;
2403 }
2404 else
2405 break;
2406 }
2407
2408 EndPaste();
2409 return bOk;
2410}
2411
2413{
2414 SCCOL nCol;
2415 SCROW nRow;
2416 SCCOL nStartCol = aRange.aStart.Col();
2417 SCROW nStartRow = aRange.aStart.Row();
2418 SCCOL nEndCol = aRange.aEnd.Col();
2419 SCROW nEndRow = aRange.aEnd.Row();
2420 OUString aCellStr;
2421 OUString aValStr;
2422 lcl_WriteSimpleString( rStrm, u"ID;PCALCOOO32" );
2424
2425 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
2426 {
2427 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
2428 {
2429 OUString aBufStr;
2430 double nVal;
2431 bool bForm = false;
2432 SCROW r = nRow - nStartRow + 1;
2433 SCCOL c = nCol - nStartCol + 1;
2434 ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, aRange.aStart.Tab()));
2435 CellType eType = aCell.getType();
2436 switch( eType )
2437 {
2438 case CELLTYPE_FORMULA:
2439 bForm = bFormulas;
2440 if( rDoc.HasValueData( nCol, nRow, aRange.aStart.Tab()) )
2441 goto hasvalue;
2442 else
2443 goto hasstring;
2444
2445 case CELLTYPE_VALUE:
2446 hasvalue:
2447 nVal = rDoc.GetValue( nCol, nRow, aRange.aStart.Tab() );
2448
2449 aValStr = ::rtl::math::doubleToUString( nVal,
2450 rtl_math_StringFormat_Automatic,
2451 rtl_math_DecimalPlaces_Max, '.', true );
2452
2453 aBufStr = "C;X"
2454 + OUString::number( c )
2455 + ";Y"
2456 + OUString::number( r )
2457 + ";K"
2458 + aValStr;
2459 lcl_WriteSimpleString( rStrm, aBufStr );
2460 goto checkformula;
2461
2462 case CELLTYPE_STRING:
2463 case CELLTYPE_EDIT:
2464 hasstring:
2465 aCellStr = rDoc.GetString(nCol, nRow, aRange.aStart.Tab());
2466 aCellStr = aCellStr.replaceAll("\n", SYLK_LF);
2467
2468 aBufStr = "C;X"
2469 + OUString::number( c )
2470 + ";Y"
2471 + OUString::number( r )
2472 + ";K";
2473 lcl_WriteSimpleString( rStrm, aBufStr );
2474 lcl_WriteString( rStrm, aCellStr, '"', ';' );
2475
2476 checkformula:
2477 if( bForm )
2478 {
2479 const ScFormulaCell* pFCell = aCell.getFormula();
2480 switch ( pFCell->GetMatrixFlag() )
2481 {
2483 aCellStr.clear();
2484 break;
2485 default:
2487 /* FIXME: do we want GRAM_ODFF_A1 instead? At
2488 * the end it probably should be
2489 * GRAM_ODFF_R1C1, since R1C1 is what Excel
2490 * writes in SYLK, or even better
2491 * GRAM_ENGLISH_XL_R1C1. */
2492 }
2493 if ( pFCell->GetMatrixFlag() != ScMatrixMode::NONE &&
2494 aCellStr.startsWith("{") &&
2495 aCellStr.endsWith("}") )
2496 { // cut off matrix {} characters
2497 aCellStr = aCellStr.copy(1, aCellStr.getLength()-2);
2498 }
2499 if ( aCellStr[0] == '=' )
2500 aCellStr = aCellStr.copy(1);
2501 OUString aPrefix;
2502 switch ( pFCell->GetMatrixFlag() )
2503 {
2505 { // diff expression with 'M' M$-extension
2506 SCCOL nC;
2507 SCROW nR;
2508 pFCell->GetMatColsRows( nC, nR );
2509 nC += c - 1;
2510 nR += r - 1;
2511 aPrefix = ";R"
2512 + OUString::number( nR )
2513 + ";C"
2514 + OUString::number( nC )
2515 + ";M";
2516 }
2517 break;
2519 { // diff expression with 'I' M$-extension
2520 ScAddress aPos;
2521 (void)pFCell->GetMatrixOrigin( rDoc, aPos );
2522 aPrefix = ";I;R"
2523 + OUString::number( aPos.Row() - nStartRow + 1 )
2524 + ";C"
2525 + OUString::number( aPos.Col() - nStartCol + 1 );
2526 }
2527 break;
2528 default:
2529 // formula Expression
2530 aPrefix = ";E";
2531 }
2532 lcl_WriteSimpleString( rStrm, aPrefix );
2533 if ( !aCellStr.isEmpty() )
2534 lcl_WriteString( rStrm, aCellStr, 0, ';' );
2535 }
2537 break;
2538
2539 default:
2540 {
2541 // added to avoid warnings
2542 }
2543 }
2544 }
2545 }
2546 lcl_WriteSimpleString( rStrm, rtl::OUStringChar( 'E' ) );
2548 return rStrm.GetError() == ERRCODE_NONE;
2549}
2550
2551bool ScImportExport::Doc2HTML( SvStream& rStrm, const OUString& rBaseURL )
2552{
2553 // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
2554 ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
2556 return rStrm.GetError() == ERRCODE_NONE;
2557}
2558
2560{
2561 // rtl_TextEncoding is ignored in ScExportRTF
2562 ScFormatFilter::Get().ScExportRTF( rStrm, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
2563 return rStrm.GetError() == ERRCODE_NONE;
2564}
2565
2567{
2568 // for DIF in the clipboard, IBM_850 is always used
2569 ScFormatFilter::Get().ScExportDif( rStrm, &rDoc, aRange, RTL_TEXTENCODING_IBM_850 );
2570 return true;
2571}
2572
2574{
2575 SCTAB nTab = aRange.aStart.Tab();
2576 ScDocumentUniquePtr pImportDoc( new ScDocument( SCDOCMODE_UNDO ) );
2577 pImportDoc->InitUndo( rDoc, nTab, nTab );
2578
2579 // for DIF in the clipboard, IBM_850 is always used
2580 ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc.get(), aRange.aStart, RTL_TEXTENCODING_IBM_850 );
2581
2582 SCCOL nEndCol;
2583 SCROW nEndRow;
2584 pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
2585 // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2586 if ( nEndCol < aRange.aStart.Col() )
2587 nEndCol = aRange.aStart.Col();
2588 if ( nEndRow < aRange.aStart.Row() )
2589 nEndRow = aRange.aStart.Row();
2590 aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
2591
2592 bool bOk = StartPaste();
2593 if (bOk)
2594 {
2596 rDoc.DeleteAreaTab( aRange, nFlags );
2597 pImportDoc->CopyToDocument(aRange, nFlags, false, rDoc);
2598 EndPaste();
2599 }
2600
2601 return bOk;
2602}
2603
2604bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
2605{
2606 std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateRTFImport( &rDoc, aRange );
2607 if (!pImp)
2608 return false;
2609 pImp->Read( rStrm, rBaseURL );
2610 aRange = pImp->GetRange();
2611
2612 bool bOk = StartPaste();
2613 if (bOk)
2614 {
2616 rDoc.DeleteAreaTab( aRange, nFlags );
2617 pImp->WriteToDocument();
2618 EndPaste();
2619 }
2620 return bOk;
2621}
2622
2623bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
2624{
2625 std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateHTMLImport( &rDoc, rBaseURL, aRange);
2626 if (!pImp)
2627 return false;
2628 pImp->Read( rStrm, rBaseURL );
2629 aRange = pImp->GetRange();
2630
2631 bool bOk = StartPaste();
2632 if (bOk)
2633 {
2634 // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2635 // a Draw Layer but no Draw View -> create Draw Layer and View here
2636 if (pDocSh)
2638
2640 rDoc.DeleteAreaTab( aRange, nFlags );
2641
2642 if (pExtOptions)
2643 {
2644 // Pick up import options if available.
2645 LanguageType eLang = pExtOptions->GetLanguage();
2647 bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
2648 pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
2649 }
2650 else
2651 // Regular import, with no options.
2652 pImp->WriteToDocument();
2653
2654 EndPaste();
2655 }
2656 return bOk;
2657}
2658
2659#ifndef DISABLE_DYNLOADING
2660
2661extern "C" { static void thisModule() {} }
2662
2663#else
2664
2665extern "C" {
2667}
2668
2669#endif
2670
2671typedef ScFormatFilterPlugin * (*FilterFn)();
2673{
2674 static ScFormatFilterPlugin *plugin = []()
2675 {
2676#ifndef DISABLE_DYNLOADING
2677 OUString sFilterLib(SVLIBRARY("scfilt"));
2678 static ::osl::Module aModule;
2679 bool bLoaded = aModule.is();
2680 if (!bLoaded)
2681 bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
2682 if (!bLoaded)
2683 bLoaded = aModule.load(sFilterLib);
2684 if (bLoaded)
2685 {
2686 oslGenericFunction fn = aModule.getFunctionSymbol( "ScFilterCreate" );
2687 if (fn != nullptr)
2688 return reinterpret_cast<FilterFn>(fn)();
2689 }
2690 assert(false);
2691 return static_cast<ScFormatFilterPlugin*>(nullptr);
2692#else
2693 return ScFilterCreate();
2694#endif
2695 }();
2696
2697 return *plugin;
2698}
2699
2700// Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2701// array.
2702static const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
2703 sal_Unicode c )
2704{
2705 while (*pStr)
2706 {
2707 if (*pStr == c)
2708 return pStr;
2709 ++pStr;
2710 }
2711 return nullptr;
2712}
2713
2715 : SvMemoryStream( const_cast<sal_Unicode *>(rStr.getStr()),
2716 rStr.getLength() * sizeof(sal_Unicode), StreamMode::READ)
2717{
2718 SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
2719#ifdef OSL_BIGENDIAN
2720 SetEndian(SvStreamEndian::BIG);
2721#else
2722 SetEndian(SvStreamEndian::LITTLE);
2723#endif
2724}
2725
2726OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
2727 OUString& rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode& rcDetectSep, sal_uInt32 nMaxSourceLines )
2728{
2729 enum RetryState
2730 {
2731 FORBID,
2732 ALLOW,
2733 RETRY,
2734 RETRIED
2735 } eRetryState = (bEmbeddedLineBreak && rcDetectSep == 0 ? RetryState::ALLOW : RetryState::FORBID);
2736
2737 sal_uInt64 nStreamPos = (eRetryState == RetryState::ALLOW ? rStream.Tell() : 0);
2738
2739Label_RetryWithNewSep:
2740
2741 if (eRetryState == RetryState::RETRY)
2742 {
2743 eRetryState = RetryState::RETRIED;
2744 rStream.Seek( nStreamPos);
2745 }
2746
2747 OUString aStr;
2749
2750 if (bEmbeddedLineBreak)
2751 {
2752 sal_Int32 nFirstLineLength = aStr.getLength();
2753 sal_uInt64 nFirstLineStreamPos = rStream.Tell();
2754 sal_uInt32 nLine = 0;
2755
2756 const sal_Unicode* pSeps = rFieldSeparators.getStr();
2757
2758 QuoteType eQuoteState = FIELDEND_QUOTE;
2759 bool bFieldStart = true;
2760
2761 sal_Int32 nLastOffset = 0;
2762 sal_Int32 nQuotes = 0;
2763 while (!rStream.eof() && aStr.getLength() < nArbitraryLineLengthLimit)
2764 {
2765 const sal_Unicode * p = aStr.getStr() + nLastOffset;
2766 const sal_Unicode * const pStop = aStr.getStr() + aStr.getLength();
2767 while (p < pStop)
2768 {
2769 if (!*p)
2770 {
2771 // Skip embedded null-characters. They don't change
2772 // anything and are handled at a higher level.
2773 ++p;
2774 continue;
2775 }
2776
2777 if (nQuotes)
2778 {
2779 if (*p == cFieldQuote)
2780 {
2781 if (bFieldStart)
2782 {
2783 ++nQuotes;
2784 bFieldStart = false;
2785 eQuoteState = FIELDSTART_QUOTE;
2786 nFirstLineLength = aStr.getLength();
2787 nFirstLineStreamPos = rStream.Tell();
2788 }
2789 // Do not detect a FIELDSTART_QUOTE if not in
2790 // bFieldStart mode, in which case for unquoted content
2791 // we are in FIELDEND_QUOTE state.
2792 else if (eQuoteState != FIELDEND_QUOTE)
2793 {
2794 eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote, rcDetectSep);
2795
2796 if (eRetryState == RetryState::ALLOW && rcDetectSep)
2797 {
2798 eRetryState = RetryState::RETRY;
2799 rFieldSeparators += OUStringChar(rcDetectSep);
2800 pSeps = rFieldSeparators.getStr();
2801 goto Label_RetryWithNewSep;
2802 }
2803
2804 // DONTKNOW_QUOTE is an embedded unescaped quote we
2805 // don't count for pairing.
2806 if (eQuoteState != DONTKNOW_QUOTE)
2807 ++nQuotes;
2808 }
2809 }
2810 else if (eQuoteState == FIELDEND_QUOTE)
2811 {
2812 if (bFieldStart)
2813 // If blank is a separator it starts a field, if it
2814 // is not and thus maybe leading before quote we
2815 // are still at start of field regarding quotes.
2816 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2817 else
2818 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2819 }
2820 }
2821 else
2822 {
2823 if (*p == cFieldQuote && bFieldStart)
2824 {
2825 nQuotes = 1;
2826 eQuoteState = FIELDSTART_QUOTE;
2827 bFieldStart = false;
2828 nFirstLineLength = aStr.getLength();
2829 nFirstLineStreamPos = rStream.Tell();
2830 }
2831 else if (eQuoteState == FIELDEND_QUOTE)
2832 {
2833 // This also skips leading blanks at beginning of line
2834 // if followed by a quote. It's debatable whether we
2835 // actually want that or not, but congruent with what
2836 // ScanNextFieldFromString() does.
2837 if (bFieldStart)
2838 bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2839 else
2840 bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
2841 }
2842 }
2843 // A quote character inside a field content does not start
2844 // a quote.
2845 ++p;
2846 }
2847
2848 if ((nQuotes & 1) == 0)
2849 // We still have a (theoretical?) problem here if due to
2850 // nArbitraryLineLengthLimit (or nMaxSourceLines below) we
2851 // split a string right between a doubled quote pair.
2852 break;
2853 else if (eQuoteState == DONTKNOW_QUOTE)
2854 // A single unescaped quote somewhere in a quote started
2855 // field, most likely that was not meant to have embedded
2856 // linefeeds either.
2857 break;
2858 else if (++nLine >= nMaxSourceLines && nMaxSourceLines > 0)
2859 // Unconditionally increment nLine even if nMaxSourceLines==0
2860 // so it can be observed in debugger.
2861 break;
2862 else
2863 {
2864 nLastOffset = aStr.getLength();
2865 OUString aNext;
2867 if (!rStream.eof())
2868 aStr += "\n" + aNext;
2869 }
2870 }
2871 if (nQuotes & 1)
2872 {
2873 // No closing quote at all. A single quote at field start => no
2874 // embedded linefeeds for that field, take only first logical line.
2875 aStr = aStr.copy( 0, nFirstLineLength);
2876 rStream.Seek( nFirstLineStreamPos);
2877 }
2878 }
2879 return aStr;
2880}
2881
2882/* 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, bool bMobile=false)
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:270
sal_Unicode GetTextSep() const
Definition: asciiopt.hxx:64
const OUString & GetFieldSeps() const
Definition: asciiopt.hxx:57
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:4687
static weld::Window * GetActiveDialogParent()
Definition: docsh.cxx:3089
void SetDocumentModified()
Definition: docsh.cxx:2959
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:2945
static SCTAB GetCurTab()
Definition: docsh4.cxx:2599
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:897
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3686
SC_DLLPUBLIC ScFormulaCell * SetFormulaCell(const ScAddress &rPos, ScFormulaCell *pCell)
Set formula cell, and transfer its ownership to the document.
Definition: documen2.cxx:1114
bool ValidRow(SCROW nRow) const
Definition: document.hxx:899
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:2601
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:891
bool IsClipboard() const
Definition: document.hxx:1592
SC_DLLPUBLIC bool RowFiltered(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4563
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:3490
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6170
SC_DLLPUBLIC void EnsureTable(SCTAB nTab)
Definition: documen2.cxx:566
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:500
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
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:3672
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:2663
SC_DLLPUBLIC void ApplyPattern(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr &rAttr)
Definition: document.cxx:4841
void SetNumberFormat(const ScAddress &rPos, sal_uInt32 nNumberFormat)
Definition: document.cxx:3732
SC_DLLPUBLIC bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: document.cxx:3422
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:3517
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4835
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:898
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3807
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:3545
bool IsBlockEmpty(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const
Definition: document.cxx:5405
bool IsUndoEnabled() const
Definition: document.hxx:1593
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:2672
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:1844
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:2566
bool Doc2HTML(SvStream &, const OUString &)
Definition: impex.cxx:2551
static void WriteUnicodeOrByteEndl(SvStream &rStrm)
Definition: impex.cxx:535
bool Doc2RTF(SvStream &)
Definition: impex.cxx:2559
bool bOverflowCell
Definition: impex.hxx:68
bool bOverflowCol
Definition: impex.hxx:67
ScExportTextOptions mExportTextOptions
Definition: impex.hxx:74
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:76
bool Dif2Doc(SvStream &)
Definition: impex.cxx:2573
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:1961
bool ImportString(const OUString &, SotClipboardFormatId)
Definition: impex.cxx:314
bool RTF2Doc(SvStream &, const OUString &rBaseURL)
Definition: impex.cxx:2604
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:1860
bool bSingle
Definition: impex.hxx:64
bool Sylk2Doc(SvStream &)
Definition: impex.cxx:2081
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:2623
bool Doc2Sylk(SvStream &)
Definition: impex.cxx:2412
~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:2714
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:2717
@ SCDOCMODE_UNDO
Definition: document.hxx:257
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:2702
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:2671
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:2661
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:2726
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.
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