2024-08-06 13:54:25 +02:00
|
|
|
unit SetupLdrAndSetup.Messages;
|
2011-10-06 20:53:09 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
Inno Setup
|
2024-04-02 16:35:06 +02:00
|
|
|
Copyright (C) 1997-2024 Jordan Russell
|
2011-10-06 20:53:09 +02:00
|
|
|
Portions by Martijn Laan
|
|
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
|
|
|
|
2024-04-02 16:35:06 +02:00
|
|
|
Message file handling functions - only to be used by Setup(Ldr)
|
2011-10-06 20:53:09 +02:00
|
|
|
}
|
|
|
|
|
2024-04-02 16:35:06 +02:00
|
|
|
{$IF not Defined(SETUPPROJ) and not Defined(SETUPLDRPROJ) }
|
|
|
|
{$Message Error 'Only the Setup and SetupLdr projects should use this unit.'}
|
|
|
|
{$IFEND}
|
|
|
|
|
2011-10-06 20:53:09 +02:00
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2024-08-04 19:59:25 +02:00
|
|
|
Shared.SetupMessageIDs, Shared.Struct;
|
2011-10-06 20:53:09 +02:00
|
|
|
|
|
|
|
const
|
|
|
|
SNewLine = #13#10; { line break }
|
|
|
|
SNewLine2 = #13#10#13#10; { double line break }
|
|
|
|
|
|
|
|
var
|
|
|
|
SetupMessages: array[TSetupMessageID] of String;
|
|
|
|
MessagesLangOptions: TMessagesLangOptions;
|
|
|
|
|
|
|
|
function FmtMessage(S: PChar; const Args: array of String): String;
|
|
|
|
function FmtSetupMessage(const ID: TSetupMessageID; const Args: array of String): String;
|
|
|
|
function FmtSetupMessage1(const ID: TSetupMessageID; const Arg1: String): String;
|
|
|
|
procedure AssignSetupMessages(const P; const Size: Cardinal);
|
|
|
|
procedure LoadSetupMessages(const Filename: String; const Offset: Cardinal;
|
|
|
|
const LoadMessagesLangOptions: Boolean);
|
|
|
|
function IntToHexStr8(I: Integer): String;
|
|
|
|
|
|
|
|
const
|
|
|
|
{ You don't have to translate these. The only time they are used is when an
|
|
|
|
error occurs before or while the messages file is loaded. Otherwise, it
|
|
|
|
uses the corresponding messages in the messages file. }
|
|
|
|
SSetupFileMissing = 'The file %1 is missing from the installation directory. ' +
|
|
|
|
'Please correct the problem or obtain a new copy of the program.';
|
|
|
|
SSetupFileCorrupt = 'The setup files are corrupted. Please obtain a new ' +
|
|
|
|
'copy of the program.';
|
|
|
|
SSetupFileCorruptOrWrongVer = 'The setup files are corrupted, or are ' +
|
|
|
|
'incompatible with this version of Setup. Please correct the problem or ' +
|
|
|
|
'obtain a new copy of the program.';
|
|
|
|
SMsgsFileMissing = 'Messages file "%s" is missing. Please correct ' +
|
|
|
|
'the problem or obtain a new copy of the program.';
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
uses
|
2024-08-05 17:25:42 +02:00
|
|
|
Windows, SysUtils, Compression.Base, Shared.CommonFunc, Shared.FileClass;
|
2011-10-06 20:53:09 +02:00
|
|
|
|
|
|
|
const
|
|
|
|
SMsgsFileTooLarge = 'Internal error: Messages file is too large';
|
|
|
|
|
|
|
|
function FmtMessage(S: PChar; const Args: array of String): String;
|
|
|
|
var
|
|
|
|
P: PChar;
|
|
|
|
Z: String;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if S = nil then Exit;
|
|
|
|
while True do begin
|
|
|
|
P := StrScan(S, '%');
|
|
|
|
if P = nil then begin
|
|
|
|
Result := Result + S;
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
if P <> S then begin
|
|
|
|
SetString(Z, S, P - S);
|
|
|
|
Result := Result + Z;
|
|
|
|
S := P;
|
|
|
|
end;
|
|
|
|
Inc(P);
|
|
|
|
if CharInSet(P^, ['1'..'9']) and (Ord(P^) - Ord('1') <= High(Args)) then begin
|
|
|
|
Result := Result + Args[Ord(P^) - Ord('1')];
|
|
|
|
Inc(S, 2);
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
Result := Result + '%';
|
|
|
|
Inc(S);
|
|
|
|
if P^ = '%' then
|
|
|
|
Inc(S);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function FmtSetupMessage(const ID: TSetupMessageID; const Args: array of String): String;
|
|
|
|
begin
|
|
|
|
Result := FmtMessage(PChar(SetupMessages[ID]), Args);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function FmtSetupMessage1(const ID: TSetupMessageID; const Arg1: String): String;
|
|
|
|
begin
|
|
|
|
Result := FmtSetupMessage(ID, [Arg1]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure FreeSetupMessages;
|
|
|
|
var
|
|
|
|
I: TSetupMessageID;
|
|
|
|
begin
|
|
|
|
for I := Low(SetupMessages) to High(SetupMessages) do
|
|
|
|
SetupMessages[I] := '';
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure Corrupted;
|
|
|
|
begin
|
|
|
|
raise Exception.Create(SSetupFileCorrupt);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure AssignSetupMessages(const P; const Size: Cardinal);
|
|
|
|
{ Takes message data, and assigns the individual messages to SetupMessages. }
|
|
|
|
var
|
|
|
|
Header: ^TMessagesHeader;
|
|
|
|
M, EndP: PChar;
|
|
|
|
I: TSetupMessageID;
|
|
|
|
L: Integer;
|
|
|
|
begin
|
|
|
|
if (Size <= SizeOf(TMessagesHdrID) + SizeOf(TMessagesHeader)) or
|
|
|
|
(TMessagesHdrID(P) <> MessagesHdrID) then
|
|
|
|
Corrupted;
|
|
|
|
Cardinal(Header) := Cardinal(@P) + SizeOf(TMessagesHdrID);
|
|
|
|
if (Header.TotalSize <> not Header.NotTotalSize) or
|
|
|
|
(Cardinal(Header.TotalSize) <> Size) or
|
|
|
|
(Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
|
|
|
|
Corrupted;
|
|
|
|
Cardinal(M) := Cardinal(Header) + SizeOf(TMessagesHeader);
|
|
|
|
Cardinal(EndP) := Cardinal(@P) + Cardinal(Header.TotalSize);
|
|
|
|
if (GetCRC32(M^, (EndP - M) * SizeOf(Char)) <> Header.CRCMessages) or
|
|
|
|
(EndP[-1] <> #0) then
|
|
|
|
Corrupted;
|
|
|
|
for I := Low(SetupMessages) to High(SetupMessages) do begin
|
|
|
|
if M >= EndP then
|
|
|
|
Corrupted;
|
|
|
|
L := StrLen(M);
|
|
|
|
SetString(SetupMessages[I], M, L);
|
|
|
|
Inc(M, L + 1);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure LoadSetupMessages(const Filename: String; const Offset: Cardinal;
|
|
|
|
const LoadMessagesLangOptions: Boolean);
|
|
|
|
{ Loads Setup messages from an uncompressed file }
|
|
|
|
var
|
|
|
|
F: TFile;
|
|
|
|
TestID: TMessagesHdrID;
|
|
|
|
Header: TMessagesHeader;
|
|
|
|
P: Pointer;
|
|
|
|
begin
|
|
|
|
FreeSetupMessages;
|
|
|
|
if not NewFileExists(Filename) then
|
|
|
|
raise Exception.CreateFmt(SMsgsFileMissing, [Filename]);
|
|
|
|
F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
|
|
|
|
try
|
|
|
|
F.Seek(Offset);
|
|
|
|
if F.Read(TestID, SizeOf(TestID)) <> SizeOf(TestID) then
|
|
|
|
Corrupted;
|
|
|
|
if TestID <> MessagesHdrID then
|
|
|
|
Corrupted;
|
|
|
|
if F.Read(Header, SizeOf(Header)) <> SizeOf(Header) then
|
|
|
|
Corrupted;
|
|
|
|
if (Header.TotalSize <> not Header.NotTotalSize) or
|
|
|
|
(Header.TotalSize <= SizeOf(TestID) + SizeOf(Header)) or
|
|
|
|
(Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
|
|
|
|
Corrupted;
|
|
|
|
|
|
|
|
F.Seek(Offset);
|
|
|
|
GetMem(P, Header.TotalSize);
|
|
|
|
try
|
|
|
|
if F.Read(P^, Header.TotalSize) <> Header.TotalSize then
|
|
|
|
Corrupted;
|
|
|
|
AssignSetupMessages(P^, Header.TotalSize);
|
|
|
|
finally
|
|
|
|
FreeMem(P);
|
|
|
|
end;
|
|
|
|
|
|
|
|
if LoadMessagesLangOptions then begin
|
|
|
|
if F.Read(MessagesLangOptions, SizeOf(MessagesLangOptions)) <> SizeOf(MessagesLangOptions) then
|
|
|
|
Corrupted;
|
|
|
|
if MessagesLangOptions.ID <> MessagesLangOptionsID then
|
|
|
|
Corrupted;
|
|
|
|
end;
|
|
|
|
finally
|
|
|
|
F.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function IntToHexStr8(I: Integer): String;
|
|
|
|
begin
|
|
|
|
FmtStr(Result, '0x%.8x', [I]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
|
|
finalization
|
|
|
|
FreeSetupMessages;
|
|
|
|
end.
|