unfortunatly there are errors in the behavior of the current implementation (since 9.1.3).
The handling of the escape char is not correct, since a backslash at the end of the mask will lead to access of Mask with MaskIndex > Length(Mask) and having '\\_' in the mask won't show the expected results.
In addition, I have improved the performance with masks containing many following wildcards ('foo%%%%%').
Setting OldFilterAsteriskBehavior will restore the behavior of versions before 9.1.3 (no escaping too).
Here is the current patch:
Code: Select all
diff -ur NewFilterBehavior.orig/Source/MemData.pas ODAC for RAD Studio XE2/Source/MemData.pas
--- NewFilterBehavior.orig/Source/MemData.pas 2013-09-12 19:48:14.000000000 +0200
+++ ODAC for RAD Studio XE2/Source/MemData.pas 2013-09-25 16:05:58.000000000 +0200
@@ -1432,6 +1432,9 @@
function AddCRUnicode(Source, Dest: IntPtr; Count: integer): integer; overload;
function RemoveCRUnicode(Source, Dest: IntPtr; DestLen, Count: integer): integer; overload;
+var
+ OldFilterAsteriskBehavior: Boolean = True;
+
implementation
uses
@@ -5296,18 +5299,62 @@
WildcardAst = '*';
WildcardPct = '%';
WildcardOne = '_';
+ EscapeChar = '\';
type
TMatchesResult = (mrFalse,mrTrue,mrEnd);
+ function IsWildcardMany(MaskIndex: integer): Boolean;
+ begin
+ case Mask[MaskIndex] of
+ WildcardAst:
+ begin
+ if OldFilterAsteriskBehavior then
+ Result := True
+ else if FilterNoPartialCompare then
+ Result := False
+ else if Node.NodeType in [ntLike, ntNotLike] then
+ Result := False
+ else
+ Result := MaskIndex = Length(Mask);
+ end;
+ WildcardPct:
+ begin
+ if OldFilterAsteriskBehavior then
+ Result := True
+ else
+ Result := Node.NodeType in [ntLike, ntNotLike];
+ end
+ else
+ Result := False;
+ end;
+ end;
+ function IsWildcardOne(MaskIndex: integer): Boolean;
+ begin
+ case Mask[MaskIndex] of
+ WildcardOne:
+ begin
+ if OldFilterAsteriskBehavior then
+ Result := True
+ else
+ Result := Node.NodeType in [ntLike, ntNotLike];
+ end
+ else
+ Result := False;
+ end;
+ end;
function SubMatchesMask(StIndex, MaskIndex: integer): TMatchesResult;
+ var
+ Escaped: Boolean;
begin
while (MaskIndex <= Length(Mask)) and
- ((StIndex <= Length(St)) or
- ((Mask[MaskIndex] = WildcardAst) or (Mask[MaskIndex] = WildcardPct))) do begin
- if (Mask[MaskIndex] = WildcardAst) or (Mask[MaskIndex] = WildcardPct) then begin
+ ((StIndex <= Length(St)) or IsWildcardMany(MaskIndex)) do begin
+ if IsWildcardMany(MaskIndex) then begin
+ while MaskIndex < Length(Mask) do
+ if IsWildcardMany(MaskIndex+1) then
+ Inc(MaskIndex); // Speed up with multiple '%'
if MaskIndex = Length(Mask) then begin //-
Result := mrTrue; // Speed up
- Exit; // with mask '*'
+ Exit; // with mask ending with '*'.
end //-
else
case SubMatchesMask(StIndex, MaskIndex + 1) of
@@ -5329,9 +5376,10 @@
end;
end
else begin
- if Mask[MaskIndex] = '\' then
+ Escaped := not OldFilterAsteriskBehavior and (MaskIndex < Length(Mask)) and (Mask[MaskIndex] = EscapeChar);
+ if Escaped then
Inc(MaskIndex);
- if (St[StIndex] = Mask[MaskIndex]) or ((Mask[MaskIndex] = WildcardOne) and (Mask[MaskIndex - 1] <> '\'))
+ if (St[StIndex] = Mask[MaskIndex]) or (IsWildcardOne(MaskIndex) and not Escaped)
then begin
Inc(StIndex);
Inc(MaskIndex); Andre