From 8374cbc33328e6b6fcd9fb903697b1ddab273087 Mon Sep 17 00:00:00 2001 From: Juha Date: Sat, 13 Apr 2024 13:35:55 +0300 Subject: [PATCH] IDE, FindInFiles: Prevent corrupt data in case UTF8 characters have size mismatch in upper/lower case. Issue #40893, patch by n7800. --- ide/lazarusidestrconsts.pas | 4 ++++ ide/searchfrm.pas | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/ide/lazarusidestrconsts.pas b/ide/lazarusidestrconsts.pas index 7b624d8bf2..2c38499e1b 100644 --- a/ide/lazarusidestrconsts.pas +++ b/ide/lazarusidestrconsts.pas @@ -4191,6 +4191,10 @@ resourcestring lisDirectories = 'Directories'; lisFindFileFileMask = 'Fi&le mask'; lisFindFileIncludeSubDirectories = 'Include &sub directories'; + lisFindFileReplacementIsNotPossible = 'This file contains characters that have ' + + 'different lengths in upper and lower case. The current implementation does ' + + 'not allow for correct replacement in this case (but you can use ' + + 'case-sensitive replacement). This file will have to be skipped:'; // package manager lisPkgMangPackage = 'Package: %s'; diff --git a/ide/searchfrm.pas b/ide/searchfrm.pas index 3344889d00..a9a1ed0798 100644 --- a/ide/searchfrm.pas +++ b/ide/searchfrm.pas @@ -529,6 +529,7 @@ var Src: String; NewMatchStartPos: PtrInt; NewMatchEndPos: PtrInt; + i, l, n1, n2: Integer; begin //debugln(['SearchInText TheFileName=',TheFileName,' SearchFor=',SearchFor,'" ReplaceText=',ReplaceText,'"']); @@ -584,6 +585,35 @@ begin CaseFile:=TSourceLog.Create(UTF8UpperCase(OriginalFile.Source)); TempSearch:=UTF8UpperCase(TempSearch); Src:=CaseFile.Source; + + // Comparing character lengths after UTF8UpperCase: + // their difference can lead to damage to the text when replacing + // issue #40893 + if sesoReplace in Flags then + begin + // length of strings in bytes (not use UTF8Length) + n1 := length(OriginalFile.Source); + n2 := length(CaseFile.Source); + l := n1; // assumed n1=n2 + i := 1; + while (n1 = n2) and (i <= l) do + begin + // length of characters in bytes + n1 := UTF8CodepointSize(@OriginalFile.Source[i]); + n2 := UTF8CodepointSize(@CaseFile.Source[i]); + inc(i, n1); // assumed n1=n2 + end; + if n1 <> n2 then + begin + if IDEMessageDialog(lisCCOWarningCaption, + lisFindFileReplacementIsNotPossible + LineEnding + LineEnding + TheFileName, + mtWarning, [mbOK, mbCancel]) = mrCancel + then + DoAbort; + + exit(mrAbort); + end; + end; end else Src:=OriginalFile.Source; end;