SetupLdrAndSetup.Messages.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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: Int64;
  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. type
  100. PMessagesHeader = ^TMessagesHeader;
  101. procedure AssignSetupMessages(const P; const Size: Cardinal);
  102. { Takes message data, and assigns the individual messages to SetupMessages. }
  103. begin
  104. if (Size <= SizeOf(TMessagesHdrID) + SizeOf(TMessagesHeader)) or
  105. (TMessagesHdrID(P) <> MessagesHdrID) then
  106. Corrupted;
  107. const Header = PMessagesHeader(PByte(@P) + SizeOf(TMessagesHdrID));
  108. if (Header.TotalSize <> not Header.NotTotalSize) or
  109. (Header.TotalSize <> Size) or
  110. (Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
  111. Corrupted;
  112. var M := PChar(PByte(Header) + SizeOf(TMessagesHeader));
  113. const EndP = PChar(PByte(@P) + Header.TotalSize);
  114. if (GetCRC32(M^, Cardinal((EndP - M) * SizeOf(Char))) <> Header.CRCMessages) or
  115. (EndP[-1] <> #0) then
  116. Corrupted;
  117. for var I := Low(SetupMessages) to High(SetupMessages) do begin
  118. if M >= EndP then
  119. Corrupted;
  120. const L = StrLen(M);
  121. SetString(SetupMessages[I], M, L);
  122. Inc(M, L + 1);
  123. end;
  124. end;
  125. procedure LoadSetupMessages(const Filename: String; const Offset: Int64;
  126. const LoadMessagesLangOptions: Boolean);
  127. { Loads Setup messages from an uncompressed file }
  128. var
  129. F: TFile;
  130. TestID: TMessagesHdrID;
  131. Header: TMessagesHeader;
  132. P: Pointer;
  133. begin
  134. FreeSetupMessages;
  135. if not NewFileExists(Filename) then
  136. raise Exception.CreateFmt(SMsgsFileMissing, [Filename]);
  137. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  138. try
  139. F.Seek(Offset);
  140. if F.Read(TestID, SizeOf(TestID)) <> SizeOf(TestID) then
  141. Corrupted;
  142. if TestID <> MessagesHdrID then
  143. Corrupted;
  144. if F.Read(Header, SizeOf(Header)) <> SizeOf(Header) then
  145. Corrupted;
  146. if (Header.TotalSize <> not Header.NotTotalSize) or
  147. (Header.TotalSize <= SizeOf(TestID) + SizeOf(Header)) or
  148. (Header.NumMessages <> (Ord(High(SetupMessages)) - Ord(Low(SetupMessages)) + 1)) then
  149. Corrupted;
  150. F.Seek(Offset);
  151. GetMem(P, Header.TotalSize);
  152. try
  153. if F.Read(P^, Header.TotalSize) <> Header.TotalSize then
  154. Corrupted;
  155. AssignSetupMessages(P^, Header.TotalSize);
  156. finally
  157. FreeMem(P);
  158. end;
  159. if LoadMessagesLangOptions then begin
  160. if F.Read(MessagesLangOptions, SizeOf(MessagesLangOptions)) <> SizeOf(MessagesLangOptions) then
  161. Corrupted;
  162. if MessagesLangOptions.ID <> MessagesLangOptionsID then
  163. Corrupted;
  164. end;
  165. finally
  166. F.Free;
  167. end;
  168. end;
  169. function IntToHexStr8(I: Integer): String;
  170. begin
  171. FmtStr(Result, '0x%.8x', [I]);
  172. end;
  173. initialization
  174. finalization
  175. FreeSetupMessages;
  176. end.