2017-07-27 10 views
13

Pourquoi System.IOUtils.TPath.HasValidPathChars accepte-t-il '?' comme un caractère valide dans un chemin? Je définis le deuxième paramètre (UseWildcards) sur false. Donc, d'après la documentation, le '?' devrait être rejeté. Pourtant, la fonction renvoie True pour 'c: \ test \ test?'.Pourquoi TPath.HasValidPathChars accepte-t-il '?' comme un caractère valide dans un chemin?

UseWildcards = Indique si les caractères de masque sont traités comme caractères de chemin d'accès valide (par exemple astérisque ou point d'interrogation).

Le comportement de cette fonction n'est-il que partiellement correct? La fonction aurait-elle pu donner un meilleur résultat?

+2

Les ''? Ne doit pas être rejeté parce que les chemins peuvent contenir des points d'interrogation sur Windows. Exemple: https://superuser.com/q/1069055 –

+0

Ce poste de super-utilisateur indique également: « Vous ne pouvez pas utiliser ces types de chemins pour accéder à des fichiers ou des répertoires dans l'espace utilisateur Seuls certains composants du système à faible niveau sont conçus pour fonctionner avec. Chemins du gestionnaire d'objets. " Donc, de ce point de vue, '?' Est un caractère de chemin invalide. – gabr

+0

@ GünthertheBeautiful - L'article dit que \ ?? est un chemin valide, donc HasValidPathChars devrait vérifier '??' et retourne true SI le motif correct (\ ??) est trouvé et false quand il y a un seul '?' – Ampere

Répondre

17

TPath.HasValidPathChars est complètement cassé. Ceci est sa mise en œuvre:

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; 

Le point crucial est l'appel à IsValidPathChar. Regardons ce que ça fait.

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

Maintenant, FInvalidPathChars est défini comme:

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; 

C'est, ordinaux moins de 32, et ", <, > et |.

Nous devons également comprendre ce que fait IsPathWildcardChar.

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

FPathWildcardChars est:

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

Maintenant, retour à TPath.HasValidPathChars. Considérons cette déclaration if:

if not IsValidPathChar(Ch) then 

La condition not IsValidPathChar(Ch) est évaluée à True quand IsValidPathChar(Ch) est False. Ce qui se passe si Ch est dans FInvalidPathChars. C'est-à-dire si Ch a un ordinal inférieur à 32, ou est l'un de ", <, > et |. Votre chaîne de test est 'C:\test\test?\' et aucun de ces caractères n'est en FInvalidPathChars Ce qui signifie que la condition dans l'instruction if not IsValidPathChar(Ch) then évalue toujours False. Ainsi, même si votre chaîne contient un caractère générique, il ne peut jamais atteindre le test suivant:

if UseWildcards then 

Il est facile de conclure que HasValidPathChars retourne la même valeur quelle que soit la valeur du paramètre d'entrée UseWildcards. Et si vous avez un doute sur l'analyse, ce programme devrait dissiper:

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

Cela ressemble à une autre fonction dans cette unité IOUtils redoutée qui a été mal mis en œuvre et non testés.

J'ai soumis un rapport de bogue: RSP-18696.

D'après avoir trébuché sur beaucoup de ces problèmes avec IOUtils, mon expérience est que l'unité ne doit pas être digne de confiance. Je ne l'utiliserais pas. Trouvez une solution alternative pour résoudre votre problème.

+0

"Il est facile de conclure que HasValidPathChars renvoie la même valeur quelle que soit la valeur du paramètre d'entrée UseWildcards" - Je voulais juste dire exactement cela !!! – Ampere

+0

Merci David. "Mon expérience est que l'unité n'est pas digne de confiance" - J'avais ma propre bibliothèque 'E/S utils' mais je l'ai remplacé par Embarcadero quand j'ai acheté Delphi XE parce que ... eh bien ... il a été construit par Embarcadero. .. donc ça doit être mieux que le mien ... non? Je ne suis pas top programmeur Delphi donc je m'attends à ce que le pire programmeur chez Embarcadero soit au moins 3 fois meilleur que moi (il devrait être un vrai professionnel Delphi, non?) !!!!!!!!!!!!!! Comment ils peuvent laisser sortir ces énormes erreurs? Probablement c'est pourquoi l'IDE se bloque tellement: ils ont utilisé IOutils dans leur code IDE :) – Ampere