为什么 TPath.HasValidPathChars 接受 '?'作为路径中的有效字符?

Why does TPath.HasValidPathChars accept '?' as a valid char in a path?

为什么 System.IOUtils.TPath.HasValidPathChars 接受'?'作为路径中的有效字符? 我将第二个参数 (UseWildcards) 设置为 false。因此,根据文档,'?'应该被拒绝。不过,函数 returns 对 'c:\test\test?\' 为真。

UseWildcards = Specifies whether the mask characters are treated as valid path characters (e.g. asterisk or question mark).

这个函数的行为是否只是部分正确?该函数是否可以返回更好的结果?

TPath.HasValidPathChars彻底坏掉了。这是它的实现:

class function TPath.HasValidPathChars(const Path: string;
  const UseWildcards: Boolean): Boolean;
var
  PPath: PChar;
  PathLen: Integer;
  Ch: Char;
  I: Integer;
begin
  // Result will become True if an invalid path char is found
{$IFDEF MSWINDOWS}
  I := GetPosAfterExtendedPrefix(Path) - 1;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
  I := 0;
{$ENDIF POSIX}

  PPath := PChar(Path);
  PathLen := Length(Path);
  Result := False;

  while (not Result) and (i < PathLen) do
  begin
    Ch := PPath[i];
    if not IsValidPathChar(Ch) then
      if UseWildcards then
        if not IsPathWildcardChar(Ch) then
          Result := True
        else
          Inc(i)
      else
        Result := True
    else
      Inc(i);
  end;

  Result := not Result;
end;

关键点是对IsValidPathChar的调用。让我们看看它的作用。

class function TPath.IsValidPathChar(const AChar: Char): Boolean;
begin
  Result := not IsCharInOrderedArray(AChar, FInvalidPathChars);
end;

现在,FInvalidPathChars 定义为:

FInvalidPathChars := TCharArray.Create(
  #0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12,
  #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24,
  #25, #26, #27, #28, #29, #30, #31,
  '"', '<', '>', '|');            // DO NOT LOCALIZE;

即所有小于32的序数,以及"<>|.

我们还需要了解 IsPathWildcardChar 的作用。

class function TPath.IsPathWildcardChar(const AChar: Char): Boolean;
begin
  Result := IsCharInOrderedArray(AChar, FPathWildcardChars);
end;

其中 FPathWildcardChars 是:

FPathWildcardChars := TCharArray.Create('*', '/', ':', '?', '\'); // DO NOT LOCALIZE;

现在,回到 TPath.HasValidPathChars。让我们考虑这个 if 语句:

if not IsValidPathChar(Ch) then

IsValidPathChar(Ch)False 时,条件 not IsValidPathChar(Ch) 的计算结果为 True。如果 ChFInvalidPathChars 中,就会发生这种情况。也就是说,如果 Ch 的序数小于 32,或者是 "<>|.

之一

您的测试字符串是 'C:\test\test?\',实际上 none 这些字符在 FInvalidPathChars 中。这意味着 if not IsValidPathChar(Ch) then 语句中的条件总是计算 False。所以即使你的字符串包含通配符,它​​也永远无法到达后续测试:

if UseWildcards then

不考虑输入参数UseWildcards的值,很容易得出HasValidPathCharsreturns相同的值。如果你对分析有任何疑问,这个程序应该打消它:

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.IOUtils;

procedure Main;
var
  Ch: Char;
begin
  for Ch := low(Ch) to high(Ch) do
    if TPath.HasValidPathChars(Ch, False)<>TPath.HasValidPathChars(Ch, True) then
      Writeln('different at #' + IntToStr(ord(Ch)));
  Writeln('finished');
end;

begin
  Main;
  Readln;
end.

这看起来像是这个可怕的 IOUtils 单元中的另一个功能,但未正确实施且未经过测试。

我已提交错误报告:RSP-18696

根据 IOUtils 偶然发现的许多此类问题,我的经验是该单位不值得信任。我不会使用它。找到解决问题的替代方法。