Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / source / core / data / cellvalue.cxx
blob4330ea9729920a180dc34ccbfa73379b1cd04275
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <cellvalue.hxx>
11 #include <document.hxx>
12 #include <column.hxx>
13 #include <formulacell.hxx>
14 #include <editeng/editobj.hxx>
15 #include <editeng/editstat.hxx>
16 #include <stringutil.hxx>
17 #include <editutil.hxx>
18 #include <tokenarray.hxx>
19 #include <formula/token.hxx>
20 #include <formula/errorcodes.hxx>
21 #include <svl/sharedstring.hxx>
23 namespace {
25 CellType adjustCellType( CellType eOrig )
27 switch (eOrig)
29 case CELLTYPE_EDIT:
30 return CELLTYPE_STRING;
31 default:
34 return eOrig;
37 template<typename T>
38 OUString getString( const T& rVal )
40 if (rVal.getType() == CELLTYPE_STRING)
41 return rVal.getSharedString()->getString();
43 if (rVal.getType() == CELLTYPE_EDIT)
45 OUStringBuffer aRet;
46 sal_Int32 n = rVal.getEditText()->GetParagraphCount();
47 for (sal_Int32 i = 0; i < n; ++i)
49 if (i > 0)
50 aRet.append('\n');
51 aRet.append(rVal.getEditText()->GetText(i));
53 return aRet.makeStringAndClear();
56 return OUString();
59 bool equalsFormulaCells( const ScFormulaCell* p1, const ScFormulaCell* p2 )
61 const ScTokenArray* pCode1 = p1->GetCode();
62 const ScTokenArray* pCode2 = p2->GetCode();
64 if (pCode1->GetLen() != pCode2->GetLen())
65 return false;
67 if (pCode1->GetCodeError() != pCode2->GetCodeError())
68 return false;
70 sal_uInt16 n = pCode1->GetLen();
71 formula::FormulaToken** ppToken1 = pCode1->GetArray();
72 formula::FormulaToken** ppToken2 = pCode2->GetArray();
73 for (sal_uInt16 i = 0; i < n; ++i)
75 if (!ppToken1[i]->TextEqual(*(ppToken2[i])))
76 return false;
79 return true;
82 template<typename T>
83 bool equalsWithoutFormatImpl( const T& left, const T& right )
85 CellType eType1 = adjustCellType(left.getType());
86 CellType eType2 = adjustCellType(right.getType());
87 if (eType1 != eType2)
88 return false;
90 switch (eType1)
92 case CELLTYPE_NONE:
93 return true;
94 case CELLTYPE_VALUE:
95 return left.getDouble() == right.getDouble();
96 case CELLTYPE_STRING:
98 OUString aStr1 = getString(left);
99 OUString aStr2 = getString(right);
100 return aStr1 == aStr2;
102 case CELLTYPE_FORMULA:
103 return equalsFormulaCells(left.getFormula(), right.getFormula());
104 default:
107 return false;
110 bool equalsWithoutFormatImpl( const ScCellValue& left, const ScCellValue& right )
112 CellType eType1 = adjustCellType(left.getType());
113 CellType eType2 = adjustCellType(right.getType());
114 if (eType1 != eType2)
115 return false;
117 switch (eType1)
119 case CELLTYPE_NONE:
120 return true;
121 case CELLTYPE_VALUE:
122 return left.getDouble() == right.getDouble();
123 case CELLTYPE_STRING:
125 OUString aStr1 = getString(left);
126 OUString aStr2 = getString(right);
127 return aStr1 == aStr2;
129 case CELLTYPE_FORMULA:
130 return equalsFormulaCells(left.getFormula(), right.getFormula());
131 default:
134 return false;
137 void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow )
139 switch (rCell.getType())
141 case CELLTYPE_STRING:
142 rColumn.SetRawString(nRow, *rCell.getSharedString());
143 break;
144 case CELLTYPE_EDIT:
145 rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.getEditText(), rColumn.GetDoc()));
146 break;
147 case CELLTYPE_VALUE:
148 rColumn.SetValue(nRow, rCell.getDouble());
149 break;
150 case CELLTYPE_FORMULA:
152 ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab());
153 rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.getFormula(), rColumn.GetDoc(), aDestPos));
155 break;
156 default:
157 rColumn.DeleteContent(nRow);
161 bool hasStringImpl( CellType eType, ScFormulaCell* pFormula )
163 switch (eType)
165 case CELLTYPE_STRING:
166 case CELLTYPE_EDIT:
167 return true;
168 case CELLTYPE_FORMULA:
169 return !pFormula->IsValue();
170 default:
171 return false;
175 bool hasNumericImpl( CellType eType, ScFormulaCell* pFormula )
177 switch (eType)
179 case CELLTYPE_VALUE:
180 return true;
181 case CELLTYPE_FORMULA:
182 return pFormula->IsValue();
183 default:
184 return false;
188 template <typename T>
189 OUString getStringImpl( const T& rCell, const ScDocument* pDoc )
191 switch (rCell.getType())
193 case CELLTYPE_VALUE:
194 return OUString::number(rCell.getDouble());
195 case CELLTYPE_STRING:
196 return rCell.getSharedString()->getString();
197 case CELLTYPE_EDIT:
198 if (rCell.getEditText())
199 return ScEditUtil::GetString(*rCell.getEditText(), pDoc);
200 break;
201 case CELLTYPE_FORMULA:
202 return rCell.getFormula()->GetString().getString();
203 default:
206 return OUString();
209 template<typename CellT>
210 OUString getRawStringImpl( const CellT& rCell, const ScDocument& rDoc )
212 switch (rCell.getType())
214 case CELLTYPE_VALUE:
215 return OUString::number(rCell.getDouble());
216 case CELLTYPE_STRING:
217 return rCell.getSharedString()->getString();
218 case CELLTYPE_EDIT:
219 if (rCell.getEditText())
220 return ScEditUtil::GetString(*rCell.getEditText(), &rDoc);
221 break;
222 case CELLTYPE_FORMULA:
223 return rCell.getFormula()->GetRawString().getString();
224 default:
227 return OUString();
232 ScCellValue::ScCellValue() {}
234 ScCellValue::ScCellValue( const ScRefCellValue& rCell )
236 switch (rCell.getType())
238 case CELLTYPE_STRING:
239 maData = *rCell.getSharedString();
240 break;
241 case CELLTYPE_EDIT:
242 maData = rCell.getEditText()->Clone().release();
243 break;
244 case CELLTYPE_FORMULA:
245 maData = rCell.getFormula()->Clone();
246 break;
247 case CELLTYPE_VALUE:
248 maData = rCell.getDouble();
249 break;
250 default: ;
254 ScCellValue::ScCellValue( double fValue ) : maData(fValue) {}
256 ScCellValue::ScCellValue( const svl::SharedString& rString ) : maData(rString) {}
258 ScCellValue::ScCellValue( std::unique_ptr<EditTextObject> xEdit ) : maData(xEdit.release()) {}
260 ScCellValue::ScCellValue( const ScCellValue& r )
262 switch (r.getType())
264 case CELLTYPE_STRING:
265 maData = *r.getSharedString();
266 break;
267 case CELLTYPE_EDIT:
268 maData = r.getEditText()->Clone().release();
269 break;
270 case CELLTYPE_FORMULA:
271 maData = r.getFormula()->Clone();
272 break;
273 case CELLTYPE_VALUE:
274 maData = r.getDouble();
275 break;
276 default: ;
280 void ScCellValue::reset_to_empty()
282 suppress_fun_call_w_exception(maData = std::monostate()); // reset to empty;
285 ScCellValue::ScCellValue(ScCellValue&& r) noexcept
286 : maData(std::move(r.maData))
288 r.reset_to_empty();
291 ScCellValue::~ScCellValue()
293 clear();
296 CellType ScCellValue::getType() const
298 switch (maData.index())
300 case 0: return CELLTYPE_NONE;
301 case 1: return CELLTYPE_VALUE;
302 case 2: return CELLTYPE_STRING;
303 case 3: return CELLTYPE_EDIT;
304 case 4: return CELLTYPE_FORMULA;
305 default:
306 assert(false);
307 return CELLTYPE_NONE;
311 void ScCellValue::clear() noexcept
313 switch (getType())
315 case CELLTYPE_EDIT:
316 suppress_fun_call_w_exception(delete getEditText());
317 break;
318 case CELLTYPE_FORMULA:
319 suppress_fun_call_w_exception(delete getFormula());
320 break;
321 default:
325 // Reset to empty value.
326 reset_to_empty();
329 void ScCellValue::set( double fValue )
331 clear();
332 maData = fValue;
335 void ScCellValue::set( const svl::SharedString& rStr )
337 clear();
338 maData = rStr;
341 void ScCellValue::set( const EditTextObject& rEditText )
343 clear();
344 maData = rEditText.Clone().release();
347 void ScCellValue::set( std::unique_ptr<EditTextObject> xEditText )
349 clear();
350 maData = xEditText.release();
353 void ScCellValue::set( ScFormulaCell* pFormula )
355 clear();
356 maData = pFormula;
359 void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
361 clear();
363 ScRefCellValue aRefVal(const_cast<ScDocument&>(rDoc), rPos);
365 switch (aRefVal.getType())
367 case CELLTYPE_STRING:
368 maData = *aRefVal.getSharedString();
369 break;
370 case CELLTYPE_EDIT:
371 maData = aRefVal.getEditText() ? aRefVal.getEditText()->Clone().release() : static_cast<EditTextObject*>(nullptr);
372 break;
373 case CELLTYPE_VALUE:
374 maData = aRefVal.getDouble();
375 break;
376 case CELLTYPE_FORMULA:
377 maData = aRefVal.getFormula()->Clone();
378 break;
379 default: ; // leave empty
383 void ScCellValue::assign(const ScCellValue& rOther, ScDocument& rDestDoc, ScCloneFlags nCloneFlags)
385 clear();
387 switch (rOther.getType())
389 case CELLTYPE_STRING:
390 maData = rOther.maData;
391 break;
392 case CELLTYPE_EDIT:
394 // Switch to the pool of the destination document.
395 ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
396 if (rOther.getEditText()->HasOnlineSpellErrors())
398 EEControlBits nControl = rEngine.GetControlWord();
399 const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
400 bool bNewControl = ((nControl & nSpellControl) != nSpellControl);
401 if (bNewControl)
402 rEngine.SetControlWord(nControl | nSpellControl);
403 rEngine.SetTextCurrentDefaults(*rOther.getEditText());
404 maData = rEngine.CreateTextObject().release();
405 if (bNewControl)
406 rEngine.SetControlWord(nControl);
408 else
410 rEngine.SetTextCurrentDefaults(*rOther.getEditText());
411 maData = rEngine.CreateTextObject().release();
414 break;
415 case CELLTYPE_VALUE:
416 maData = rOther.maData;
417 break;
418 case CELLTYPE_FORMULA:
419 // Switch to the destination document.
420 maData = new ScFormulaCell(*rOther.getFormula(), rDestDoc, rOther.getFormula()->aPos, nCloneFlags);
421 break;
422 default: ; // leave empty
426 void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
428 switch (getType())
430 case CELLTYPE_STRING:
432 ScSetStringParam aParam;
433 aParam.setTextInput();
434 rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
436 break;
437 case CELLTYPE_EDIT:
438 rDoc.SetEditText(rPos, getEditText()->Clone());
439 break;
440 case CELLTYPE_VALUE:
441 rDoc.SetValue(rPos, getDouble());
442 break;
443 case CELLTYPE_FORMULA:
444 rDoc.SetFormulaCell(rPos, getFormula()->Clone());
445 break;
446 default:
447 rDoc.SetEmptyCell(rPos);
451 void ScCellValue::commit( ScColumn& rColumn, SCROW nRow ) const
453 commitToColumn(*this, rColumn, nRow);
456 void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
458 switch (getType())
460 case CELLTYPE_STRING:
462 // Currently, string cannot be placed without copying.
463 ScSetStringParam aParam;
464 aParam.setTextInput();
465 rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
467 break;
468 case CELLTYPE_EDIT:
469 // Cell takes the ownership of the text object.
470 rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(getEditText()));
471 break;
472 case CELLTYPE_VALUE:
473 rDoc.SetValue(rPos, getDouble());
474 break;
475 case CELLTYPE_FORMULA:
476 // This formula cell instance is directly placed in the document without copying.
477 rDoc.SetFormulaCell(rPos, getFormula());
478 break;
479 default:
480 rDoc.SetEmptyCell(rPos);
483 reset_to_empty(); // reset to empty
486 void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType )
488 switch (getType())
490 case CELLTYPE_STRING:
492 // Currently, string cannot be placed without copying.
493 rColumn.SetRawString(nRow, *getSharedString());
495 break;
496 case CELLTYPE_EDIT:
497 // Cell takes the ownership of the text object.
498 rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(getEditText()));
499 break;
500 case CELLTYPE_VALUE:
501 rColumn.SetValue(nRow, getDouble());
502 break;
503 case CELLTYPE_FORMULA:
504 // This formula cell instance is directly placed in the document without copying.
505 rColumn.SetFormulaCell(nRow, getFormula(), eListenType);
506 break;
507 default:
508 rColumn.DeleteContent(nRow);
511 reset_to_empty(); // reset to empty
514 OUString ScCellValue::getString( const ScDocument& rDoc ) const
516 return getStringImpl(*this, &rDoc);
519 bool ScCellValue::isEmpty() const
521 return getType() == CELLTYPE_NONE;
524 bool ScCellValue::equalsWithoutFormat( const ScCellValue& r ) const
526 return equalsWithoutFormatImpl(*this, r);
529 ScCellValue& ScCellValue::operator= ( const ScCellValue& r )
531 ScCellValue aTmp(r);
532 swap(aTmp);
533 return *this;
536 ScCellValue& ScCellValue::operator=(ScCellValue&& rCell) noexcept
538 clear();
539 maData = std::move(rCell.maData);
540 rCell.reset_to_empty(); // reset to empty;
541 return *this;
544 ScCellValue& ScCellValue::operator= ( const ScRefCellValue& r )
546 ScCellValue aTmp(r);
547 swap(aTmp);
548 return *this;
551 void ScCellValue::swap( ScCellValue& r )
553 std::swap(maData, r.maData);
556 ScRefCellValue::ScRefCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {}
557 ScRefCellValue::ScRefCellValue( double fValue ) : meType(CELLTYPE_VALUE), mfValue(fValue) {}
558 ScRefCellValue::ScRefCellValue( const svl::SharedString* pString ) : meType(CELLTYPE_STRING), mpString(pString) {}
559 ScRefCellValue::ScRefCellValue( const EditTextObject* pEditText ) : meType(CELLTYPE_EDIT), mpEditText(pEditText) {}
560 ScRefCellValue::ScRefCellValue( ScFormulaCell* pFormula ) : meType(CELLTYPE_FORMULA), mpFormula(pFormula) {}
562 ScRefCellValue::ScRefCellValue( ScDocument& rDoc, const ScAddress& rPos )
564 assign( rDoc, rPos);
567 ScRefCellValue::ScRefCellValue( ScDocument& rDoc, const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
569 assign( rDoc, rPos, rBlockPos );
572 void ScRefCellValue::clear()
574 // Reset to empty value.
575 meType = CELLTYPE_NONE;
576 mfValue = 0.0;
579 void ScRefCellValue::assign( ScDocument& rDoc, const ScAddress& rPos )
581 *this = rDoc.GetRefCellValue(rPos);
584 void ScRefCellValue::assign( ScDocument& rDoc, const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
586 *this = rDoc.GetRefCellValue(rPos, rBlockPos);
589 void ScRefCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
591 switch (meType)
593 case CELLTYPE_STRING:
595 ScSetStringParam aParam;
596 aParam.setTextInput();
597 rDoc.SetString(rPos, mpString->getString(), &aParam);
599 break;
600 case CELLTYPE_EDIT:
601 rDoc.SetEditText(rPos, ScEditUtil::Clone(*mpEditText, rDoc));
602 break;
603 case CELLTYPE_VALUE:
604 rDoc.SetValue(rPos, mfValue);
605 break;
606 case CELLTYPE_FORMULA:
607 rDoc.SetFormulaCell(rPos, new ScFormulaCell(*mpFormula, rDoc, rPos));
608 break;
609 default:
610 rDoc.SetEmptyCell(rPos);
614 bool ScRefCellValue::hasString() const
616 return hasStringImpl(meType, mpFormula);
619 bool ScRefCellValue::hasNumeric() const
621 return hasNumericImpl(meType, mpFormula);
624 bool ScRefCellValue::hasError() const
626 return meType == CELLTYPE_FORMULA && mpFormula->GetErrCode() != FormulaError::NONE;
629 double ScRefCellValue::getValue()
631 switch (meType)
633 case CELLTYPE_VALUE:
634 return mfValue;
635 case CELLTYPE_FORMULA:
636 return mpFormula->GetValue();
637 default:
640 return 0.0;
643 double ScRefCellValue::getRawValue() const
645 switch (meType)
647 case CELLTYPE_VALUE:
648 return mfValue;
649 case CELLTYPE_FORMULA:
650 return mpFormula->GetRawValue();
651 default:
654 return 0.0;
657 OUString ScRefCellValue::getString( const ScDocument* pDoc ) const
659 return getStringImpl(*this, pDoc);
662 OUString ScRefCellValue::getRawString( const ScDocument& rDoc ) const
664 return getRawStringImpl(*this, rDoc);
667 bool ScRefCellValue::isEmpty() const
669 return meType == CELLTYPE_NONE;
672 bool ScRefCellValue::hasEmptyValue()
674 if (isEmpty())
675 return true;
677 if (meType == CELLTYPE_FORMULA)
678 return mpFormula->IsEmpty();
680 return false;
683 bool ScRefCellValue::equalsWithoutFormat( const ScRefCellValue& r ) const
685 return equalsWithoutFormatImpl(*this, r);
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */