FIX: Use normalized strings when compare file names under macOS (fixes #1981)

This commit is contained in:
Alexander Koblov 2025-12-01 18:54:11 +03:00
commit f27b7f8526
2 changed files with 61 additions and 6 deletions

View file

@ -182,6 +182,8 @@ function MapFile(const sFileName : String; out FileMapRec : TFileMapRec) : Boole
}
procedure UnMapFile(var FileMapRec : TFileMapRec);
function NormalizeFileName(const Source: String): String;
{en
Convert from console to UTF8 encoding.
}
@ -335,6 +337,9 @@ uses
{$ENDIF}
{$IF DEFINED(UNIX)}
Unix, dl,
{$ENDIF}
{$IF DEFINED(DARWIN)}
LazFileUtils,
{$ENDIF}
DCStrUtils, LazUTF8;
@ -845,6 +850,17 @@ begin
end;
{$ENDIF}
function NormalizeFileName(const Source: String): String; inline;
{$IF DEFINED(DARWIN)}
begin
Result:= GetDarwinNormalizedFileName(Source);
end;
{$ELSE}
begin
Result:= Source;
end;
{$ENDIF}
function ConsoleToUTF8(const Source: String): RawByteString;
{$IFDEF MSWINDOWS}
begin
@ -1606,7 +1622,11 @@ begin
end;
function mbCompareFileNames(const FileName1, FileName2: String): Boolean; inline;
{$IF DEFINED(WINDOWS) OR DEFINED(DARWIN)}
{$IF DEFINED(DARWIN)}
begin
Result:= CompareFilenamesIgnoreCase(FileName1, FileName2) = 0;
end;
{$ELSEIF DEFINED(MSWINDOWS)}
begin
Result:= (UnicodeCompareText(CeUtf8ToUtf16(FileName1), CeUtf8ToUtf16(FileName2)) = 0);
end;

View file

@ -42,12 +42,14 @@ type
private
FList: PStringHashItemList;
FCount: Integer;
fNormalize: Boolean;
fCaseSensitive: Boolean;
function BinarySearch(HashValue: Cardinal): Integer;
function CompareString(const Low, Key: String): Boolean;
function CompareValue(const Value1, Value2: Cardinal): Integer;
procedure FindHashBoundaries(HashValue: Cardinal; StartFrom: Integer; out First, Last: Integer);
function GetData(const S: String): Pointer;
procedure SetNormalize(AValue: Boolean);
procedure SetCaseSensitive(const Value: Boolean);
procedure Delete(Index: Integer);
procedure SetData(const S: String; const AValue: Pointer);
@ -66,6 +68,7 @@ type
function Remove(const S: String): Integer;
function Remove(const S: String; Data: Pointer): Integer;
procedure FindBoundaries(StartFrom: Integer; out First, Last: Integer);
property Normalize: Boolean read fNormalize write SetNormalize;
property CaseSensitive: Boolean read fCaseSensitive write SetCaseSensitive;
property Count: Integer read FCount;
property Data[const S: String]: Pointer read GetData write SetData; default;
@ -75,7 +78,7 @@ type
implementation
uses
LazUTF8;
LazUTF8, DCOSUtils;
{ TStringHashListUtf8 }
@ -97,6 +100,10 @@ begin
else begin
Text:= UTF8LowerCase(S);
end;
if fNormalize then
begin
Text:= NormalizeFileName(Text);
end;
New(Item);
Val:= HashOf(Text);
Item^.HashValue := Val;
@ -180,13 +187,20 @@ var
begin
P:= Pointer(Low);
Len:= Length(Low);
if fCaseSensitive then
if not fNormalize then
begin
Result:= (Len = Length(Key));
if Result then Result:= (CompareByte(P^, Pointer(Key)^, Len) = 0);
LKey:= Key;
end
else begin
LKey:= UTF8LowerCase(Key);
LKey:= NormalizeFileName(Key);
end;
if fCaseSensitive then
begin
Result:= (Len = Length(LKey));
if Result then Result:= (CompareByte(P^, Pointer(LKey)^, Len) = 0);
end
else begin
LKey:= UTF8LowerCase(LKey);
Result:= (Len = Length(LKey));
if Result then Result:= (CompareByte(P^, Pointer(LKey)^, Len) = 0);
end;
@ -232,6 +246,18 @@ begin
Add(S,AValue);
end;
procedure TStringHashListUtf8.SetNormalize(AValue: Boolean);
begin
if fNormalize <> AValue then
begin
if Count > 0 then
begin
raise EListError.Create(lrsListMustBeEmpty);
end;
fNormalize := AValue;
end;
end;
destructor TStringHashListUtf8.Destroy;
begin
Clear;
@ -249,6 +275,10 @@ begin
else begin
Text:= UTF8LowerCase(S);
end;
if fNormalize then
begin
Text:= NormalizeFileName(Text);
end;
Value:= HashOf(Text);
Result:= BinarySearch(Value);
if (Result <> -1) and not CompareString(Text, FList[Result]^.Key) then
@ -275,6 +305,10 @@ begin
else begin
Text:= UTF8LowerCase(S);
end;
if fNormalize then
begin
Text:= NormalizeFileName(Text);
end;
Value:= HashOf(Text);
Result:= BinarySearch(Value);
if (Result <> -1) and
@ -335,7 +369,8 @@ end;
constructor TStringHashListUtf8.Create(CaseSensitivity: boolean);
begin
fCaseSensitive:=CaseSensitivity;
fNormalize:= True;
fCaseSensitive:= CaseSensitivity;
inherited Create;
end;