2017-07-27 48 views
13

Dlaczego System.IOUtils.TPath.HasValidPathChars akceptuje "?" jako poprawny znak na ścieżce? Ustawiam drugi parametr (UseWildcards) na false. Tak więc zgodnie z dokumentacją "?" należy odrzucić. Mimo to funkcja zwraca wartość True dla "c: \ test \ test? \".Dlaczego TPath.HasValidPathChars akceptuje "?" jako poprawny znak na ścieżce?

UseWildcards = Określa, czy znaki maski są traktowane jako ważne znaki ścieżki (np. Gwiazdka lub znak zapytania).

Czy zachowanie tej funkcji jest tylko częściowo poprawne? Czy funkcja zwróciła lepszy wynik?

+2

Znaku?? Nie należy odrzucać, ponieważ ścieżki mogą zawierać znaki zapytania w systemie Windows. Przykład: https://superuser.com/q/1069055 –

+0

Ten post użytkownika superużytkownicy również stwierdza: "Nie można używać tego rodzaju ścieżek w celu uzyskania dostępu do plików lub katalogów w przestrzeni użytkownika. Tylko niektóre komponenty systemowe niskiego poziomu są zaprojektowane do pracy z Ścieżki Menedżera obiektów. " Z tego punktu widzenia '?' Jest nieprawidłową ścieżką. – gabr

+0

@ GünthertheBeautiful - Artykuł mówi, że \ ?? jest poprawną ścieżką, więc HasValidPathChars powinno sprawdzić "??" i zwraca true, jeśli poprawny wzorzec (\ ??) zostanie znaleziony, a false, gdy istnieje pojedynczy znak "?" – Ampere

Odpowiedz

17

TPath.HasValidPathChars jest całkowicie zepsuty. To jest jego realizacja:

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; 

Kluczowym punktem jest wywołanie IsValidPathChar. Spójrzmy, co to oznacza.

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

Teraz FInvalidPathChars określa się:

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; 

Oznacza to, że wszystkie porządkowe mniej niż 32, a ", <, > i |.

Musimy również zrozumieć, co robi IsPathWildcardChar.

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

Gdzie FPathWildcardChars jest:

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

Wróćmy teraz do TPath.HasValidPathChars. Rozważmy ten if oświadczenie:

if not IsValidPathChar(Ch) then 

Warunkiem not IsValidPathChar(Ch) ocenia się True gdy IsValidPathChar(Ch) jest False. Co się stanie, jeśli Ch jest w FInvalidPathChars. To znaczy, jeśli Ch ma liczbę porządkową mniejszą niż 32, lub jest jedną z ", <, > i |.

Twój ciąg testowy to 'C:\test\test?\' i w rzeczywistości żaden z tych znaków nie jest w FInvalidPathChars. Co oznacza, że ​​warunek w instrukcji if not IsValidPathChar(Ch) then zawsze ocenia False. Więc nawet jeśli ciąg zawiera wieloznaczny, to nigdy nie może dotrzeć do kolejnego testu:

if UseWildcards then 

łatwo jest stwierdzić, że HasValidPathChars zwraca taką samą wartość niezależnie od wartości parametru wejściowego UseWildcards. A jeśli masz jakiekolwiek wątpliwości co do analizy, program ten powinien je rozwiać:

{$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. 

To wygląda jeszcze inną funkcję w tym bał IOUtils jednostki, które zostały niewłaściwie wykonane i nie testowane.

Złożyłem zgłoszenie błędu: RSP-18696.

Na podstawie natknięcia się na wiele takich problemów z IOUtils, moim doświadczeniem jest to, że jednostka nie jest zaufana. Nie użyłbym tego. Znajdź alternatywny sposób rozwiązania problemu.

+0

"Łatwo jest wywnioskować, że HasValidPathChars zwraca tę samą wartość niezależnie od wartości parametru wejściowego UseWildcards" - Chciałem właśnie to powiedzieć !!! – Ampere

+0

Dzięki David. "moje doświadczenie polega na tym, że tej jednostce nie można ufać" - miałem własną bibliotekę "I/O utils", ale zastąpiłem ją Embarcadero, gdy kupiłem Delphi XE, ponieważ ... no cóż ... został zbudowany przez Embarcadero. .. więc to musi być lepsze niż moje ... prawda? Nie jestem najlepszym programistą Delphi, więc spodziewam się, że najgorszy programista w Embarcadero będzie co najmniej 3 razy lepszy ode mnie (powinien być zawodowcem TRUE Delphi, prawda?) !!!!!!!!!!!!!! Jak mogą wypuścić tak wielkie błędy? Prawdopodobnie dlatego IDE tak się psuje: użyli IOutils w swoim kodzie IDE :) – Ampere