123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- unit SetupLdrAndSetup.Messages;
- {
- Inno Setup
- Copyright (C) 1997-2025 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- Message file handling functions - only to be used by Setup(Ldr)
- }
- {$IF not Defined(SETUPPROJ) and not Defined(SETUPLDRPROJ) }
- {$Message Error 'Only the Setup and SetupLdr projects should use this unit.'}
- {$IFEND}
- interface
- uses
- Shared.SetupMessageIDs, Shared.Struct;
- 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.';
- { These currently always occur before the messages file is loaded }
- SMissingPassword = 'Please specify the password using the /PASSWORD= command line parameter.';
- SIncorrectPassword = 'The password you specified is not correct. Please try again.';
- implementation
- uses
- Windows, SysUtils, Compression.Base, Shared.CommonFunc, Shared.FileClass;
- 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.
|