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