Подтвердить что ты не робот

Почему TPath.HasValidPathChars принимает '?' как действительный char в пути?

Почему System.IOUtils.TPath.HasValidPathChars принимает '?' как действительный char в пути? Я установил второй параметр (UseWildcards) в значение false. Итак, согласно документации "?" должны быть отклонены. Тем не менее, функция возвращает True для 'c:\test\test? \'.

UseWildcards = Указывает, обрабатываются ли символы маски как действительные символы пути (например, звездочка или знак вопроса).

Является ли поведение этой функции только частично правильным? Может ли функция вернуть лучший результат?

4b9b3361

Ответ 1

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, мой опыт в том, что устройству не нужно доверять. Я бы не использовал его. Найдите альтернативный способ решения вашей проблемы.