Reputation: 4309
If you enter an invalid path or empty path, the Inno Setup will give you this error:
I need to create a function which does this for me. Currently I'm using DirExists
function, but I think it is not covering what I'm looking for.
Upvotes: 2
Views: 447
Reputation: 202642
The validation that Inno Setup does is relatively complex. Check the source code for ValidateCustomDirEdit
function to see what it does.
A very rouch equivalent of that code for default Inno Setup settings (AllowUNCPath=yes
, AllowRootDirectory=no
, AllowNetworkDrive=yes
) translated to Pascal Script is below. Note that it might not work correctly with MBCS.
procedure TidyUpDirName(var Path: String);
var
Prefix: string;
Prev: string;
begin
StringChangeEx(Path, '/', '\', True);
repeat
Prev := Path;
Path := Trim(Path);
Prefix := '';
if Copy(Path, 1, 2) = '\\' then
begin
Prefix := '\\';
Path := Copy(Path, 3, Length(Path) - 2);
end;
StringChangeEx(Path, '\\', '\', True);
Path := Prefix + Path;
Path := RemoveBackslashUnlessRoot(Path);
until Prev = Path;
end;
function ValidatePath(Path: string): Boolean;
var
I, P: Integer;
S, S2: string;
begin
TidyUpDirName(Path);
Result := False;
if Length(Path) > 240 then Exit;
if Copy(Path, 1, 2) <> '\\' then
begin
if (Length(Path) < 4) or
(Uppercase(Path[1])[1] < 'A') or (Uppercase(Path[1])[1] > 'Z') or
(Path[2] <> ':')
or (Path[3] <> '\') then Exit;
end
else
begin
if Pos('\', Copy(Path, 3, Length(Path) - 2)) = 0 then Exit;
end;
for I := 1 to Length(Path) do
begin
if Path[I] <= #31 then Exit;
if (Path[I] = ' ') and
((I = Length(Path)) or (Path[I + 1] = '\')) then Exit;
end;
S := Path;
while Length(S) > 0 do
begin
P := Pos('\', S);
if P > 0 then
begin
S2 := Copy(S, 1, P - 1);
S := Copy(S, P + 1, Length(S) - P);
end
else
begin
S2 := S;
S := '';
end;
S2 := Trim(S2);
if (Length(S2) > 0) and (S2 = StringOfChar('.', Length(S2))) then Exit;
end;
for I := 3 to Length(Path) do
begin
if Pos(Path[I], '/:*?"<>|') > 0 then Exit;
end;
Result := True;
end;
Tests:
procedure DoTest(Path: string; Expected: Boolean);
var
Actual: Boolean;
M: string;
begin
Actual := ValidatePath(Path);
M := Format('Path: "%s"; Result: %d; Expected: %d', [
Path, Integer(Actual), Integer(Expected)]);
Log(M);
if Actual <> Expected then RaiseException(M);
end;
procedure Test;
begin
DoTest('C:\path', True);
DoTest('\\server\path', True);
DoTest('c:\path', True);
DoTest('C:/path', True);
DoTest('//server/path', True);
DoTest('C:\path ', True);
DoTest(' C:\path ', True);
DoTest('C:\\path', True);
DoTest('\\server\\path', True);
DoTest('C:', False);
DoTest('C:\', False);
DoTest('1:\path', False);
DoTest('|:\path', False);
DoTest('C;\path', False);
DoTest('C:|path\sub', False);
DoTest('\\server', False);
DoTest('C:\\pa'#27'th', False);
DoTest('C:\\path \sub', False);
DoTest('C:\\path\sub \sub', False);
DoTest('C:\\.', False);
DoTest('C:\\..\sub', False);
DoTest('C:\\path\.\sub', False);
DoTest('C:\\path\ .\sub', False);
DoTest('C:\\path\.. \sub', False);
DoTest('C:\\path\su:b', False);
DoTest('C:\\pa?th\sub', False);
end;
Inno Setup additionally tests for existence of the drive:
DirExists(ExtractFileDrive(Path))
If you want your own path edit box with the same validation as the standard Select directory page, use CreateInputDirPage
/TInputDirWizardPage
, instead of a completely custom page. The TInputDirWizardPage
does the validation for you.
Or you can call a hidden TInputDirWizardPage
to do just the validation.
Upvotes: 3