diff options
author | Neil <nyamatongwe@gmail.com> | 2024-02-15 14:17:08 +1100 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2024-02-15 14:17:08 +1100 |
commit | 38d2856d341358bf9c691157ae0ca2e8960e35df (patch) | |
tree | a1a187630421e954b65181bb2d2fb4a58d2549ff /src/UndoHistory.cxx | |
parent | a6a2fe933e0103464c1a357f987ad10e3bcf6622 (diff) | |
download | scintilla-mirror-38d2856d341358bf9c691157ae0ca2e8960e35df.tar.gz |
Perform validation of undo state when SCI_SETUNDOCURRENT called, setting status
when invalid.
Diffstat (limited to 'src/UndoHistory.cxx')
-rw-r--r-- | src/UndoHistory.cxx | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx index 1a956b998..62f871a60 100644 --- a/src/UndoHistory.cxx +++ b/src/UndoHistory.cxx @@ -173,6 +173,14 @@ bool UndoActions::AtStart(size_t index) const noexcept { return !types[index-1].mayCoalesce; } +size_t UndoActions::LengthTo(size_t index) const noexcept { + size_t sum = 0; + for (size_t act = 0; act < index; act++) { + sum += lengths.ValueAt(act); + } + return sum; +} + void ScrapStack::Clear() noexcept { stack.clear(); current = 0; @@ -395,15 +403,49 @@ bool UndoHistory::AfterOrAtDetachPoint() const noexcept { return detach && (*detach <= currentAction); } -void UndoHistory::SetCurrent(int action) noexcept { - // Find position in scraps for action - memory = {}; - size_t position = 0; +intptr_t UndoHistory::Delta(int action) noexcept { + intptr_t sizeChange = 0; for (int act = 0; act < action; act++) { - position += actions.lengths.ValueAt(act); + const intptr_t lengthChange = actions.lengths.SignedValueAt(act); + sizeChange += (actions.types[act].at == ActionType::insert) ? lengthChange : -lengthChange; + } + return sizeChange; +} + +bool UndoHistory::Validate(intptr_t lengthDocument) noexcept { + // Check history for validity + const intptr_t sizeChange = Delta(currentAction); + if (sizeChange > lengthDocument) { + // Current document size too small for changes made in undo history. + return false; } - scraps->SetCurrent(position); + const intptr_t lengthOriginal = lengthDocument - sizeChange; + intptr_t lengthCurrent = lengthOriginal; + for (int act = 0; act < actions.SSize(); act++) { + const intptr_t lengthChange = actions.lengths.SignedValueAt(act); + if (actions.positions.SignedValueAt(act) > lengthCurrent) { + // Change outside document. + return false; + } + lengthCurrent += (actions.types[act].at == ActionType::insert) ? lengthChange : -lengthChange; + if (lengthCurrent < 0) { + return false; + } + } + return true; +} + +void UndoHistory::SetCurrent(int action, intptr_t lengthDocument) { + // Find position in scraps for action + memory = {}; + const size_t lengthSum = actions.LengthTo(action); + scraps->SetCurrent(lengthSum); currentAction = action; + if (!Validate(lengthDocument)) { + currentAction = 0; + DeleteUndoHistory(); + throw std::runtime_error("UndoHistory::SetCurrent: invalid undo history."); + } } int UndoHistory::Current() const noexcept { |