SetupLdrAndSetup.Messages.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. unit SetupLdrAndSetup.Messages;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Message file handling functions - only to be used by Setup(Ldr)
  8. }
  9. {$IF not Defined(SETUPPROJ) and not Defined(SETUPLDRPROJ) }
  10. {$Message Error 'Only the Setup and SetupLdr projects should use this unit.'}
  11. {$IFEND}
  12. interface
  13. uses
  14. Shared.SetupMessageIDs, Shared.Struct;
  15. const
  16. SNewLine = #13#10; { line break }
  17. SNewLine2 = #13#10#13#10; { double line break }
  18. var
  19. SetupMessages: array[TSetupMessageID] of String;
  20. MessagesLangOptions: TMessagesLangOptions;
  21. function FmtMessage(S: PChar; const Args: array of String): String;
  22. function FmtSetupMessage(const ID: TSetupMessageID; const Args: array of String): String;
  23. function FmtSetupMessage1(const ID: TSetupMessageID; const Arg1: String): String;
  24. procedure AssignSetupMessages(const P; const Size: Cardinal);
  25. procedure LoadSetupMessages(const Filename: String; const Offset: Cardinal;
  26. const LoadMessagesLangOptions: Boolean);
  27. function IntToHexStr8(I: Integer): String;
  28. const
  29. { You don't have to translate these. The only time they are used is when an
  30. error occurs before or while the messages file is loaded. Otherwise, it
  31. uses the corresponding messages in the messages file. }
  32. SSetupFileMissing = 'The file %1 is missing from the installation directory. ' +
  33. 'Please correct the problem or obtain a new copy of the program.';
  34. SSetupFileCorrupt = 'The setup files are corrupted. Please obtain a new ' +
  35. 'copy of the program.';
  36. SSetupFileCorruptOrWrongVer = 'The setup files are corrupted, or are ' +
  37. 'incompatible with this version of Setup. Please correct the problem or ' +
  38. 'obtain a new copy of the program.';
  39. SMsgsFileMissing = 'Messages file "%s" is missing. Please correct ' +
  40. 'the problem or obtain a new copy of the program.';
  41. { These currently always occur before the messages file is loaded }
  42. SMissingPassword = 'Please specify the password using the /PASSWORD= command line parameter.';
  43. SIncorrectPassword = 'The password you specified is not correct. Please try again.';
  44. implementation
  45. uses
  46. Windows, SysUtils, Compression.Base, Shared.CommonFunc, Shared.FileClass;
  47. const
  48. SMsgsFileTooLarge = 'Internal error: Messages file is too large';
  49. function FmtMessage(S: PChar; const Args: array of String): String;
  50. var
  51. P: PChar;
  52. Z: String;
  53. begin
  54. Result := '';
  55. if S = nil then Exit;
  56. while True do begin
  57. P := StrScan(S, '%');
  58. if P = nil then begin
  59. Result := Result + S;
  60. Break;
  61. end;
  62. if P <> S then begin
  63. SetString(Z, S, P - S);
  64. Result := Result + Z;
  65. S := P;
  66. end;
  67. Inc(P);
  68. if CharInSet(P^, ['1'..'9']) and (Ord(P^) - Ord('1') <= High(Args)) then begin
  69. Result := Result + Args[Ord(P^) - Ord('1')];
  70. Inc(S, 2);
  71. end
  72. else begin
  73. Result := Result + '%';
  74. Inc(S);
  75. if P^ = '%' then
  76. Inc(S);
  77. end;
  78. end;
  79. end;
  80. function FmtSetupMessage(const ID: TSetupMessageID; const Args: array of String): String;
  81. begin
  82. Result := FmtMessage(PChar(SetupMessages[ID]), Args);
  83. end;
  84. function FmtSetupMessage1(const ID: TSetupMessageID; const Arg1: String): String;
  85. begin
  86. Result := FmtSetupMessage(ID, [Arg1]);
  87. end;
  88. procedure FreeSetupMessages;
  89. var
  90. I: TSetupMessageID;
  91. begin
  92. for I := Low(SetupMessages) to High(SetupMessages) do
  93. SetupMessages[I] := '';
  94. end;
  95. procedure Corrupted;
  96. begin
  97. raise Exception.Create(SSetupFileCorrupt);
  98. end;
  99. procedure AssignSetupMessages(const P; const Size: Cardinal);
  100. { Takes message data, and assigns the individual messages to SetupMessages. }
  101. var
  102. Header: ^TMessagesHeader;
  103. M, EndP: PChar;
  104. I: TSetupMessageID;
  105. L: Integer;
  106. begin
  107. if (Size <= SizeOf(TMessagesHdrID) + SizeOf(TMessagesHeader)) or
  108. (TMessagesHdrID(P) <> MessagesHdrID) then
  109. Corrupted;
  110. Cardinal(Header) := Cardinal(@P) + SizeOf(TMessagesHdrID);
  111. if (Header.TotalSize <> not Header.NotTotalSize) or
  112. (Cardinal(Header.TotalSize) <> Size) or
  113. (Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
  114. Corrupted;
  115. Cardinal(M) := Cardinal(Header) + SizeOf(TMessagesHeader);
  116. Cardinal(EndP) := Cardinal(@P) + Cardinal(Header.TotalSize);
  117. if (GetCRC32(M^, (EndP - M) * SizeOf(Char)) <> Header.CRCMessages) or
  118. (EndP[-1] <> #0) then
  119. Corrupted;
  120. for I := Low(SetupMessages) to High(SetupMessages) do begin
  121. if M >= EndP then
  122. Corrupted;
  123. L := StrLen(M);
  124. SetString(SetupMessages[I], M, L);
  125. Inc(M, L + 1);
  126. end;
  127. end;
  128. procedure LoadSetupMessages(const Filename: String; const Offset: Cardinal;
  129. const LoadMessagesLangOptions: Boolean);
  130. { Loads Setup messages from an uncompressed file }
  131. var
  132. F: TFile;
  133. TestID: TMessagesHdrID;
  134. Header: TMessagesHeader;
  135. P: Pointer;
  136. begin
  137. FreeSetupMessages;
  138. if not NewFileExists(Filename) then
  139. raise Exception.CreateFmt(SMsgsFileMissing, [Filename]);
  140. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  141. try
  142. F.Seek(Offset);
  143. if F.Read(TestID, SizeOf(TestID)) <> SizeOf(TestID) then
  144. Corrupted;
  145. if TestID <> MessagesHdrID then
  146. Corrupted;
  147. if F.Read(Header, SizeOf(Header)) <> SizeOf(Header) then
  148. Corrupted;
  149. if (Header.TotalSize <> not Header.NotTotalSize) or
  150. (Header.TotalSize <= SizeOf(TestID) + SizeOf(Header)) or
  151. (Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
  152. Corrupted;
  153. F.Seek(Offset);
  154. GetMem(P, Header.TotalSize);
  155. try
  156. if F.Read(P^, Header.TotalSize) <> Header.TotalSize then
  157. Corrupted;
  158. AssignSetupMessages(P^, Header.TotalSize);
  159. finally
  160. FreeMem(P);
  161. end;
  162. if LoadMessagesLangOptions then begin
  163. if F.Read(MessagesLangOptions, SizeOf(MessagesLangOptions)) <> SizeOf(MessagesLangOptions) then
  164. Corrupted;
  165. if MessagesLangOptions.ID <> MessagesLangOptionsID then
  166. Corrupted;
  167. end;
  168. finally
  169. F.Free;
  170. end;
  171. end;
  172. function IntToHexStr8(I: Integer): String;
  173. begin
  174. FmtStr(Result, '0x%.8x', [I]);
  175. end;
  176. initialization
  177. finalization
  178. FreeSetupMessages;
  179. end.