Compiler.HelperFunc.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. unit Compiler.HelperFunc;
  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. Additional compiler functions
  8. }
  9. interface
  10. uses
  11. Windows, Classes, SysUtils, Shared.FileClass;
  12. type
  13. TColor = $7FFFFFFF-1..$7FFFFFFF;
  14. const
  15. clScrollBar = TColor(COLOR_SCROLLBAR or $80000000);
  16. clBackground = TColor(COLOR_BACKGROUND or $80000000);
  17. clActiveCaption = TColor(COLOR_ACTIVECAPTION or $80000000);
  18. clInactiveCaption = TColor(COLOR_INACTIVECAPTION or $80000000);
  19. clMenu = TColor(COLOR_MENU or $80000000);
  20. clWindow = TColor(COLOR_WINDOW or $80000000);
  21. clWindowFrame = TColor(COLOR_WINDOWFRAME or $80000000);
  22. clMenuText = TColor(COLOR_MENUTEXT or $80000000);
  23. clWindowText = TColor(COLOR_WINDOWTEXT or $80000000);
  24. clCaptionText = TColor(COLOR_CAPTIONTEXT or $80000000);
  25. clActiveBorder = TColor(COLOR_ACTIVEBORDER or $80000000);
  26. clInactiveBorder = TColor(COLOR_INACTIVEBORDER or $80000000);
  27. clAppWorkSpace = TColor(COLOR_APPWORKSPACE or $80000000);
  28. clHighlight = TColor(COLOR_HIGHLIGHT or $80000000);
  29. clHighlightText = TColor(COLOR_HIGHLIGHTTEXT or $80000000);
  30. clBtnFace = TColor(COLOR_BTNFACE or $80000000);
  31. clBtnShadow = TColor(COLOR_BTNSHADOW or $80000000);
  32. clGrayText = TColor(COLOR_GRAYTEXT or $80000000);
  33. clBtnText = TColor(COLOR_BTNTEXT or $80000000);
  34. clInactiveCaptionText = TColor(COLOR_INACTIVECAPTIONTEXT or $80000000);
  35. clBtnHighlight = TColor(COLOR_BTNHIGHLIGHT or $80000000);
  36. cl3DDkShadow = TColor(COLOR_3DDKSHADOW or $80000000);
  37. cl3DLight = TColor(COLOR_3DLIGHT or $80000000);
  38. clInfoText = TColor(COLOR_INFOTEXT or $80000000);
  39. clInfoBk = TColor(COLOR_INFOBK or $80000000);
  40. clBlack = TColor($000000);
  41. clMaroon = TColor($000080);
  42. clGreen = TColor($008000);
  43. clOlive = TColor($008080);
  44. clNavy = TColor($800000);
  45. clPurple = TColor($800080);
  46. clTeal = TColor($808000);
  47. clGray = TColor($808080);
  48. clSilver = TColor($C0C0C0);
  49. clRed = TColor($0000FF);
  50. clLime = TColor($00FF00);
  51. clYellow = TColor($00FFFF);
  52. clBlue = TColor($FF0000);
  53. clFuchsia = TColor($FF00FF);
  54. clAqua = TColor($FFFF00);
  55. clLtGray = TColor($C0C0C0);
  56. clDkGray = TColor($808080);
  57. clWhite = TColor($FFFFFF);
  58. clNone = TColor($1FFFFFFF);
  59. clDefault = TColor($20000000);
  60. function IdentToColor(const Ident: string; var Color: Longint): Boolean;
  61. function StringToColor(const S: string): TColor;
  62. function IsRelativePath(const Filename: String): Boolean;
  63. function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean = False;
  64. const OnCheckedTrust: TProc<Boolean> = nil): TMemoryStream;
  65. function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
  66. const CRC: Longint): Boolean;
  67. function IsX86OrX64Executable(const F: TFile): Boolean;
  68. function CountChars(const S: String; C: Char): Integer;
  69. function IsValidIdentString(const S: String; AllowBackslash, AllowOperators: Boolean): Boolean;
  70. procedure SkipWhitespace(var S: PChar);
  71. function ExtractWords(var S: PChar; const Sep: Char): String;
  72. function UnescapeBraces(const S: String): String;
  73. procedure GenerateRandomBytes(var Buffer; Bytes: Cardinal);
  74. implementation
  75. uses
  76. TrustFunc, Shared.CommonFunc, Shared.Int64Em,
  77. Compression.Base, Compiler.Messages;
  78. type
  79. TColorEntry = record
  80. Value: TColor;
  81. Name: string;
  82. end;
  83. const
  84. Colors: array[0..41] of TColorEntry = (
  85. (Value: clBlack; Name: 'clBlack'),
  86. (Value: clMaroon; Name: 'clMaroon'),
  87. (Value: clGreen; Name: 'clGreen'),
  88. (Value: clOlive; Name: 'clOlive'),
  89. (Value: clNavy; Name: 'clNavy'),
  90. (Value: clPurple; Name: 'clPurple'),
  91. (Value: clTeal; Name: 'clTeal'),
  92. (Value: clGray; Name: 'clGray'),
  93. (Value: clSilver; Name: 'clSilver'),
  94. (Value: clRed; Name: 'clRed'),
  95. (Value: clLime; Name: 'clLime'),
  96. (Value: clYellow; Name: 'clYellow'),
  97. (Value: clBlue; Name: 'clBlue'),
  98. (Value: clFuchsia; Name: 'clFuchsia'),
  99. (Value: clAqua; Name: 'clAqua'),
  100. (Value: clWhite; Name: 'clWhite'),
  101. (Value: clScrollBar; Name: 'clScrollBar'),
  102. (Value: clBackground; Name: 'clBackground'),
  103. (Value: clActiveCaption; Name: 'clActiveCaption'),
  104. (Value: clInactiveCaption; Name: 'clInactiveCaption'),
  105. (Value: clMenu; Name: 'clMenu'),
  106. (Value: clWindow; Name: 'clWindow'),
  107. (Value: clWindowFrame; Name: 'clWindowFrame'),
  108. (Value: clMenuText; Name: 'clMenuText'),
  109. (Value: clWindowText; Name: 'clWindowText'),
  110. (Value: clCaptionText; Name: 'clCaptionText'),
  111. (Value: clActiveBorder; Name: 'clActiveBorder'),
  112. (Value: clInactiveBorder; Name: 'clInactiveBorder'),
  113. (Value: clAppWorkSpace; Name: 'clAppWorkSpace'),
  114. (Value: clHighlight; Name: 'clHighlight'),
  115. (Value: clHighlightText; Name: 'clHighlightText'),
  116. (Value: clBtnFace; Name: 'clBtnFace'),
  117. (Value: clBtnShadow; Name: 'clBtnShadow'),
  118. (Value: clGrayText; Name: 'clGrayText'),
  119. (Value: clBtnText; Name: 'clBtnText'),
  120. (Value: clInactiveCaptionText; Name: 'clInactiveCaptionText'),
  121. (Value: clBtnHighlight; Name: 'clBtnHighlight'),
  122. (Value: cl3DDkShadow; Name: 'cl3DDkShadow'),
  123. (Value: cl3DLight; Name: 'cl3DLight'),
  124. (Value: clInfoText; Name: 'clInfoText'),
  125. (Value: clInfoBk; Name: 'clInfoBk'),
  126. (Value: clNone; Name: 'clNone'));
  127. function IdentToColor(const Ident: string; var Color: Longint): Boolean;
  128. var
  129. I: Integer;
  130. begin
  131. for I := Low(Colors) to High(Colors) do
  132. if CompareText(Colors[I].Name, Ident) = 0 then
  133. begin
  134. Result := True;
  135. Color := Longint(Colors[I].Value);
  136. Exit;
  137. end;
  138. Result := False;
  139. end;
  140. function StringToColor(const S: string): TColor;
  141. begin
  142. if not IdentToColor(S, Longint(Result)) then
  143. Result := TColor(StrToInt(S));
  144. end;
  145. function IsRelativePath(const Filename: String): Boolean;
  146. var
  147. L: Integer;
  148. begin
  149. Result := True;
  150. L := Length(Filename);
  151. if ((L >= 1) and (Filename[1] = '\')) or
  152. ((L >= 2) and CharInSet(Filename[1], ['A'..'Z', 'a'..'z']) and (Filename[2] = ':')) then
  153. Result := False;
  154. end;
  155. function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean;
  156. const OnCheckedTrust: TProc<Boolean>): TMemoryStream;
  157. { Creates a TMemoryStream and loads the contents of the specified file into it }
  158. var
  159. F: TFile;
  160. SizeOfFile: Cardinal;
  161. begin
  162. Result := TMemoryStream.Create;
  163. try
  164. var FS: TFileStream;
  165. if CheckTrust then begin
  166. try
  167. FS := CheckFileTrust(Filename, [cftoKeepOpen]);
  168. except
  169. raise Exception.CreateFmt(SCompilerCheckPrecompiledFileTrustError, [GetExceptMessage]);
  170. end;
  171. end else
  172. FS := nil;
  173. if Assigned(OnCheckedTrust) then
  174. OnCheckedTrust(CheckTrust);
  175. try
  176. { Why not use TMemoryStream.LoadFromFile here?
  177. 1. On Delphi 2 it opens files for exclusive access (not good).
  178. 2. It doesn't give specific error messages. }
  179. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  180. try
  181. SizeOfFile := F.CappedSize;
  182. Result.SetSize(SizeOfFile);
  183. F.ReadBuffer(Result.Memory^, SizeOfFile);
  184. finally
  185. F.Free;
  186. end;
  187. finally
  188. FS.Free;
  189. end;
  190. except
  191. Result.Free;
  192. raise Exception.CreateFmt(SCompilerReadError, [Filename, GetExceptMessage]);
  193. end;
  194. end;
  195. function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
  196. const CRC: Longint): Boolean;
  197. var
  198. F: TFile;
  199. SizeOfFile: Integer64;
  200. Buf: AnsiString;
  201. begin
  202. Result := False;
  203. try
  204. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  205. try
  206. SizeOfFile := F.Size;
  207. if (SizeOfFile.Lo = Size) and (SizeOfFile.Hi = 0) then begin
  208. SetLength(Buf, Size);
  209. F.ReadBuffer(Buf[1], Size);
  210. if GetCRC32(Buf[1], Size) = CRC then
  211. Result := True;
  212. end;
  213. finally
  214. F.Free;
  215. end;
  216. except
  217. end;
  218. end;
  219. const
  220. IMAGE_NT_SIGNATURE = $00004550; { 'PE'#0#0 }
  221. IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b;
  222. type
  223. TImageFileHeader = packed record
  224. Machine: Word;
  225. NumberOfSections: Word;
  226. TimeDateStamp: DWORD;
  227. PointerToSymbolTable: DWORD;
  228. NumberOfSymbols: DWORD;
  229. SizeOfOptionalHeader: Word;
  230. Characteristics: Word;
  231. end;
  232. function IsX86OrX64Executable(const F: TFile): Boolean;
  233. const
  234. IMAGE_FILE_MACHINE_I386 = $014C;
  235. IMAGE_FILE_MACHINE_AMD64 = $8664;
  236. var
  237. DosHeader: array[0..63] of Byte;
  238. PEHeaderOffset: Longint;
  239. PESigAndHeader: packed record
  240. Sig: DWORD;
  241. Machine: Word;
  242. end;
  243. begin
  244. Result := False;
  245. if F.Read(DosHeader, SizeOf(DosHeader)) = SizeOf(DosHeader) then begin
  246. if (DosHeader[0] = Ord('M')) and (DosHeader[1] = Ord('Z')) then begin
  247. PEHeaderOffset := PLongint(@DosHeader[60])^;
  248. if PEHeaderOffset > 0 then begin
  249. F.Seek(PEHeaderOffset);
  250. if F.Read(PESigAndHeader, SizeOf(PESigAndHeader)) = SizeOf(PESigAndHeader) then begin
  251. if (PESigAndHeader.Sig = IMAGE_NT_SIGNATURE) and
  252. ((PESigAndHeader.Machine = IMAGE_FILE_MACHINE_I386) or
  253. (PESigAndHeader.Machine = IMAGE_FILE_MACHINE_AMD64)) then
  254. Result := True;
  255. end;
  256. end;
  257. end;
  258. end;
  259. F.Seek(0);
  260. end;
  261. function CountChars(const S: String; C: Char): Integer;
  262. var
  263. I: Integer;
  264. begin
  265. Result := 0;
  266. for I := 1 to Length(S) do
  267. if S[I] = C then
  268. Inc(Result);
  269. end;
  270. function IsValidIdentString(const S: String; AllowBackslash, AllowOperators: Boolean): Boolean;
  271. var
  272. I, N: Integer;
  273. begin
  274. if S = '' then
  275. Result := False
  276. else if not AllowOperators and ((CompareText(S, 'not') = 0) or
  277. (CompareText(S, 'and') = 0) or (CompareText(S, 'or') = 0)) then
  278. Result := False
  279. else begin
  280. N := Length(S);
  281. for I := 1 to N do
  282. if not (CharInSet(S[I], ['A'..'Z', 'a'..'z', '_']) or
  283. ((I > 1) and CharInSet(S[I], ['0'..'9'])) or
  284. (AllowBackslash and (I > 1) and (I < N) and (S[I] = '\'))) then begin
  285. Result := False;
  286. Exit;
  287. end;
  288. Result := True;
  289. end;
  290. end;
  291. procedure SkipWhitespace(var S: PChar);
  292. begin
  293. while CharInSet(S^, [#1..' ']) do
  294. Inc(S);
  295. end;
  296. function ExtractWords(var S: PChar; const Sep: Char): String;
  297. { Extracts characters from S until it reaches the character Sep or the end
  298. of S. The returned string has trailing whitespace characters trimmed off. }
  299. var
  300. StartPos, EndPos: PChar;
  301. begin
  302. StartPos := S;
  303. EndPos := S;
  304. while (S^ <> #0) and (S^ <> Sep) do begin
  305. if S^ > ' ' then
  306. EndPos := S + 1;
  307. Inc(S);
  308. end;
  309. SetString(Result, StartPos, EndPos - StartPos);
  310. end;
  311. function UnescapeBraces(const S: String): String;
  312. { Changes all '{{' to '{'. Assumes that S does not contain any constants; you
  313. should check before calling. }
  314. var
  315. I: Integer;
  316. begin
  317. Result := S;
  318. I := 1;
  319. while I < Length(Result) do begin
  320. if Result[I] = '{' then begin
  321. Inc(I);
  322. if Result[I] = '{' then
  323. Delete(Result, I, 1);
  324. end
  325. else
  326. Inc(I);
  327. end;
  328. end;
  329. type
  330. HCRYPTPROV = DWORD;
  331. const
  332. PROV_RSA_FULL = 1;
  333. CRYPT_VERIFYCONTEXT = $F0000000;
  334. function CryptAcquireContext(var phProv: HCRYPTPROV; pszContainer: PAnsiChar;
  335. pszProvider: PAnsiChar; dwProvType: DWORD; dwFlags: DWORD): BOOL;
  336. stdcall; external advapi32 name 'CryptAcquireContextA';
  337. function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL;
  338. stdcall; external advapi32 name 'CryptReleaseContext';
  339. function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; pbBuffer: Pointer): BOOL;
  340. stdcall; external advapi32 name 'CryptGenRandom';
  341. var
  342. CryptProv: HCRYPTPROV;
  343. procedure GenerateRandomBytes(var Buffer; Bytes: Cardinal);
  344. var
  345. ErrorCode: DWORD;
  346. begin
  347. if CryptProv = 0 then begin
  348. if not CryptAcquireContext(CryptProv, nil, nil, PROV_RSA_FULL,
  349. CRYPT_VERIFYCONTEXT) then begin
  350. ErrorCode := GetLastError;
  351. raise Exception.CreateFmt(SCompilerFunctionFailedWithCode,
  352. ['CryptAcquireContext', ErrorCode, Win32ErrorString(ErrorCode)]);
  353. end;
  354. { Note: CryptProv is released in the 'finalization' section of this unit }
  355. end;
  356. FillChar(Buffer, Bytes, 0);
  357. if not CryptGenRandom(CryptProv, Bytes, @Buffer) then begin
  358. ErrorCode := GetLastError;
  359. raise Exception.CreateFmt(SCompilerFunctionFailedWithCode,
  360. ['CryptGenRandom', ErrorCode, Win32ErrorString(ErrorCode)]);
  361. end;
  362. end;
  363. initialization
  364. finalization
  365. if CryptProv <> 0 then begin
  366. CryptReleaseContext(CryptProv, 0);
  367. CryptProv := 0;
  368. end;
  369. end.