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

时间:2017-07-27 09:22:52

标签: delphi path directory delphi-xe7

为什么System.IOUtils.TPath.HasValidPathChars接受'?'作为路径中的有效字符? 我将第二个参数(UseWildcards)设置为false。所以,根据文件'?'应该被拒绝。仍然,该函数返回True为' c:\ test \ test?\'。

  

UseWildcards =指定是否将掩码字符视为   有效的路径字符(例如星号或问号)。

此功能的行为是否仅部分正确?该函数能否返回更好的结果?

1 个答案:

答案 0 :(得分:17)

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

not IsValidPathChar(Ch)True时,条件IsValidPathChar(Ch)的评估结果为False。如果Ch位于FInvalidPathChars,则会发生这种情况。也就是说,如果Ch的序数小于32,或者是"<>|之一。

您的测试字符串为'C:\test\test?\',实际上这些字符都不在FInvalidPathChars中。这意味着if not IsValidPathChar(Ch) then语句中的条件始终评估False。因此,即使您的字符串包含通配符,它​​也永远无法进入后续测试:

if UseWildcards then

很容易得出结论,HasValidPathChars返回相同的值,而与输入参数UseWildcards的值无关。如果您对分析有任何疑问,该程序应该消除它:

{$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的许多此类问题,我的经验是该单位不值得信任。我不会用它。找到另一种解决问题的方法。