I have an working Pascal scripts for Inno Setup, but recently we ran into an issue with Unicode characters. And after changing the Inno Setup to Unicode version we got errors in existing scripts. And this error is too generic - "Type mismatch" for certain line. Since our main script is composed of lots of other scripts that are included I'm not sure if that line is the correct, and it points to this function below, and line with Set of Char
.
After looking the Inno Setup documentation I found that Unicode version is bit more strict about some things, and also there was some changes around ANSI string handling (and probably Char
as well).
function IsValidName(Name: String):String;
var
Valid_Ch: Set of Char;
Location: Integer;
begin
Valid_Ch := ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '-'];
Result := '';
for Location := 1 to Length(Name) do
begin
if Name[Location] in Valid_Ch then
begin
Result := Result + Name[Location];
end
else
begin
Result := Result + '_';
end;
end;
end;
This all looks fine to me, but this is my first touch with Pascal. I would be thankful if someone more experienced could help me about this.
Thanks!
In Pascal (Script) the set
can contain 256 (2^8) values only. In Unicode Inno Setup the Char
is 2-byte, hence it can contain a way more than 256 different values. So you cannot use it with set
anymore.
You have these options:
In your case, as the set is in fact constant, you can use a constant set in the if
expression. Interestingly, that works even in Unicode version (possibly there's some hack built in that allows this exception).
function IsValidName(Name: string): string;
var
Location: Integer;
begin
Result := Name;
for Location := 1 to Length(Name) do
begin
if not (Name[Location] in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '-']) then
begin
Result[Location] := '_';
end;
end;
end;
Had you needed the set to be variable (not your case):
- Use
Byte
and cast between Char
and Byte
and explicitly replace all characters with Ord() > 255
Or use a string
instead of the set
. For an example, see below.
function IsValidName(Name: string): string;
var
Valid_Ch: string;
Location: Integer;
begin
Valid_Ch := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_-';
Result := Name;
for Location := 1 to Length(Result) do
begin
if Pos(Result[Location], Valid_Ch) = 0 then
begin
Result[Location] := '_';
end;
end;
end;
Also note that appending the string char-by-char can be pretty inefficient. Replace the characters in-place instead (as shown in both examples above).