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