Compiler.HelperFunc.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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, UITypes,
  12. Shared.FileClass;
  13. const
  14. clScrollBar = TColors.SysScrollBar;
  15. clBackground = TColors.SysBackground;
  16. clActiveCaption = TColors.SysActiveCaption;
  17. clInactiveCaption = TColors.SysInactiveCaption;
  18. clMenu = TColors.SysMenu;
  19. clWindow = TColors.SysWindow;
  20. clWindowFrame = TColors.SysWindowFrame;
  21. clMenuText = TColors.SysMenuText;
  22. clWindowText = TColors.SysWindowText;
  23. clCaptionText = TColors.SysCaptionText;
  24. clActiveBorder = TColors.SysActiveBorder;
  25. clInactiveBorder = TColors.SysInactiveBorder;
  26. clAppWorkSpace = TColors.SysAppWorkSpace;
  27. clHighlight = TColors.SysHighlight;
  28. clHighlightText = TColors.SysHighlightText;
  29. clBtnFace = TColors.SysBtnFace;
  30. clBtnShadow = TColors.SysBtnShadow;
  31. clGrayText = TColors.SysGrayText;
  32. clBtnText = TColors.SysBtnText;
  33. clInactiveCaptionText = TColors.SysInactiveCaptionText;
  34. clBtnHighlight = TColors.SysBtnHighlight;
  35. cl3DDkShadow = TColors.Sys3DDkShadow;
  36. cl3DLight = TColors.Sys3DLight;
  37. clInfoText = TColors.SysInfoText;
  38. clInfoBk = TColors.SysInfoBk;
  39. clBlack = TColors.Black;
  40. clMaroon = TColors.Maroon;
  41. clGreen = TColors.Green;
  42. clOlive = TColors.Olive;
  43. clNavy = TColors.Navy;
  44. clPurple = TColors.Purple;
  45. clTeal = TColors.Teal;
  46. clGray = TColors.Gray;
  47. clSilver = TColors.Silver;
  48. clRed = TColors.Red;
  49. clLime = TColors.Lime;
  50. clYellow = TColors.Yellow;
  51. clBlue = TColors.Blue;
  52. clFuchsia = TColors.Fuchsia;
  53. clAqua = TColors.Aqua;
  54. clLtGray = TColors.LtGray;
  55. clDkGray = TColors.DkGray;
  56. clWhite = TColors.White;
  57. clNone = TColors.SysNone;
  58. clDefault = TColors.SysDefault;
  59. function StringToColor(const S: string): TColor;
  60. function IsRelativePath(const Filename: String): Boolean;
  61. function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean = False;
  62. const OnCheckedTrust: TProc<Boolean> = nil): TMemoryStream;
  63. function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
  64. const CRC: Longint): Boolean;
  65. function IsX86OrX64Executable(const F: TFile): Boolean;
  66. function CountChars(const S: String; C: Char): Integer;
  67. function IsValidIdentString(const S: String; AllowBackslash, AllowOperators: Boolean): Boolean;
  68. procedure SkipWhitespace(var S: PChar);
  69. function ExtractWords(var S: PChar; const Sep: Char): String;
  70. function UnescapeBraces(const S: String): String;
  71. implementation
  72. uses
  73. PathFunc, TrustFunc, Shared.CommonFunc,
  74. Compression.Base, Compiler.Messages;
  75. type
  76. TColorEntry = record
  77. Value: TColor;
  78. Name: string;
  79. end;
  80. const
  81. Colors: array[0..41] of TColorEntry = (
  82. (Value: clBlack; Name: 'clBlack'),
  83. (Value: clMaroon; Name: 'clMaroon'),
  84. (Value: clGreen; Name: 'clGreen'),
  85. (Value: clOlive; Name: 'clOlive'),
  86. (Value: clNavy; Name: 'clNavy'),
  87. (Value: clPurple; Name: 'clPurple'),
  88. (Value: clTeal; Name: 'clTeal'),
  89. (Value: clGray; Name: 'clGray'),
  90. (Value: clSilver; Name: 'clSilver'),
  91. (Value: clRed; Name: 'clRed'),
  92. (Value: clLime; Name: 'clLime'),
  93. (Value: clYellow; Name: 'clYellow'),
  94. (Value: clBlue; Name: 'clBlue'),
  95. (Value: clFuchsia; Name: 'clFuchsia'),
  96. (Value: clAqua; Name: 'clAqua'),
  97. (Value: clWhite; Name: 'clWhite'),
  98. (Value: clScrollBar; Name: 'clScrollBar'),
  99. (Value: clBackground; Name: 'clBackground'),
  100. (Value: clActiveCaption; Name: 'clActiveCaption'),
  101. (Value: clInactiveCaption; Name: 'clInactiveCaption'),
  102. (Value: clMenu; Name: 'clMenu'),
  103. (Value: clWindow; Name: 'clWindow'),
  104. (Value: clWindowFrame; Name: 'clWindowFrame'),
  105. (Value: clMenuText; Name: 'clMenuText'),
  106. (Value: clWindowText; Name: 'clWindowText'),
  107. (Value: clCaptionText; Name: 'clCaptionText'),
  108. (Value: clActiveBorder; Name: 'clActiveBorder'),
  109. (Value: clInactiveBorder; Name: 'clInactiveBorder'),
  110. (Value: clAppWorkSpace; Name: 'clAppWorkSpace'),
  111. (Value: clHighlight; Name: 'clHighlight'),
  112. (Value: clHighlightText; Name: 'clHighlightText'),
  113. (Value: clBtnFace; Name: 'clBtnFace'),
  114. (Value: clBtnShadow; Name: 'clBtnShadow'),
  115. (Value: clGrayText; Name: 'clGrayText'),
  116. (Value: clBtnText; Name: 'clBtnText'),
  117. (Value: clInactiveCaptionText; Name: 'clInactiveCaptionText'),
  118. (Value: clBtnHighlight; Name: 'clBtnHighlight'),
  119. (Value: cl3DDkShadow; Name: 'cl3DDkShadow'),
  120. (Value: cl3DLight; Name: 'cl3DLight'),
  121. (Value: clInfoText; Name: 'clInfoText'),
  122. (Value: clInfoBk; Name: 'clInfoBk'),
  123. (Value: clNone; Name: 'clNone'));
  124. function StringToColor(const S: string): TColor;
  125. function IdentToColor(Ident: string; var Color: Integer): Boolean;
  126. begin
  127. if not PathStartsWith(Ident, 'cl') then
  128. Ident := 'cl' + Ident;
  129. for var I := Low(Colors) to High(Colors) do
  130. if SameText(Colors[I].Name, Ident) then begin
  131. Color := Integer(Colors[I].Value);
  132. Exit(True);
  133. end;
  134. Result := False;
  135. end;
  136. begin
  137. if not IdentToColor(S, Integer(Result)) then begin
  138. var Hex := S;
  139. if (Length(Hex) = 7) and (Hex[1] = '#') then
  140. Hex := '$' + Copy(Hex, 6, 2) + Copy(Hex, 4, 2) + Copy(Hex, 2, 2);
  141. Result := TColor(StrToInt(Hex));
  142. end;
  143. end;
  144. function IsRelativePath(const Filename: String): Boolean;
  145. var
  146. L: Integer;
  147. begin
  148. Result := True;
  149. L := Length(Filename);
  150. if ((L >= 1) and (Filename[1] = '\')) or
  151. ((L >= 2) and CharInSet(Filename[1], ['A'..'Z', 'a'..'z']) and (Filename[2] = ':')) then
  152. Result := False;
  153. end;
  154. function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean;
  155. const OnCheckedTrust: TProc<Boolean>): TMemoryStream;
  156. { Creates a TMemoryStream and loads the contents of the specified file into it }
  157. var
  158. F: TFile;
  159. SizeOfFile: Cardinal;
  160. begin
  161. Result := TMemoryStream.Create;
  162. try
  163. var FS: TFileStream;
  164. if CheckTrust then begin
  165. try
  166. FS := CheckFileTrust(Filename, [cftoKeepOpen]);
  167. except
  168. raise Exception.CreateFmt(SCompilerCheckPrecompiledFileTrustError, [GetExceptMessage]);
  169. end;
  170. end else
  171. FS := nil;
  172. if Assigned(OnCheckedTrust) then
  173. OnCheckedTrust(CheckTrust);
  174. try
  175. { Why not use TMemoryStream.LoadFromFile here?
  176. 1. On Delphi 2 it opens files for exclusive access (not good).
  177. 2. It doesn't give specific error messages. }
  178. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  179. try
  180. SizeOfFile := F.CappedSize;
  181. Result.SetSize(SizeOfFile);
  182. F.ReadBuffer(Result.Memory^, SizeOfFile);
  183. finally
  184. F.Free;
  185. end;
  186. finally
  187. FS.Free;
  188. end;
  189. except
  190. Result.Free;
  191. raise Exception.CreateFmt(SCompilerReadError, [Filename, GetExceptMessage]);
  192. end;
  193. end;
  194. function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
  195. const CRC: Longint): Boolean;
  196. var
  197. F: TFile;
  198. Buf: AnsiString;
  199. begin
  200. Result := False;
  201. try
  202. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  203. try
  204. if F.Size = Size then begin
  205. SetLength(Buf, Size);
  206. F.ReadBuffer(Buf[1], Size);
  207. if GetCRC32(Buf[1], Size) = CRC then
  208. Result := True;
  209. end;
  210. finally
  211. F.Free;
  212. end;
  213. except
  214. end;
  215. end;
  216. const
  217. IMAGE_NT_SIGNATURE = $00004550; { 'PE'#0#0 }
  218. IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b;
  219. type
  220. TImageFileHeader = packed record
  221. Machine: Word;
  222. NumberOfSections: Word;
  223. TimeDateStamp: DWORD;
  224. PointerToSymbolTable: DWORD;
  225. NumberOfSymbols: DWORD;
  226. SizeOfOptionalHeader: Word;
  227. Characteristics: Word;
  228. end;
  229. function IsX86OrX64Executable(const F: TFile): Boolean;
  230. const
  231. IMAGE_FILE_MACHINE_I386 = $014C;
  232. IMAGE_FILE_MACHINE_AMD64 = $8664;
  233. var
  234. DosHeader: array[0..63] of Byte;
  235. PEHeaderOffset: Longint;
  236. PESigAndHeader: packed record
  237. Sig: DWORD;
  238. Machine: Word;
  239. end;
  240. begin
  241. Result := False;
  242. if F.Read(DosHeader, SizeOf(DosHeader)) = SizeOf(DosHeader) then begin
  243. if (DosHeader[0] = Ord('M')) and (DosHeader[1] = Ord('Z')) then begin
  244. PEHeaderOffset := PLongint(@DosHeader[60])^;
  245. if PEHeaderOffset > 0 then begin
  246. F.Seek(PEHeaderOffset);
  247. if F.Read(PESigAndHeader, SizeOf(PESigAndHeader)) = SizeOf(PESigAndHeader) then begin
  248. if (PESigAndHeader.Sig = IMAGE_NT_SIGNATURE) and
  249. ((PESigAndHeader.Machine = IMAGE_FILE_MACHINE_I386) or
  250. (PESigAndHeader.Machine = IMAGE_FILE_MACHINE_AMD64)) then
  251. Result := True;
  252. end;
  253. end;
  254. end;
  255. end;
  256. F.Seek(0);
  257. end;
  258. function CountChars(const S: String; C: Char): Integer;
  259. var
  260. I: Integer;
  261. begin
  262. Result := 0;
  263. for I := 1 to Length(S) do
  264. if S[I] = C then
  265. Inc(Result);
  266. end;
  267. function IsValidIdentString(const S: String; AllowBackslash, AllowOperators: Boolean): Boolean;
  268. var
  269. I, N: Integer;
  270. begin
  271. if S = '' then
  272. Result := False
  273. else if not AllowOperators and ((CompareText(S, 'not') = 0) or
  274. (CompareText(S, 'and') = 0) or (CompareText(S, 'or') = 0)) then
  275. Result := False
  276. else begin
  277. N := Length(S);
  278. for I := 1 to N do
  279. if not (CharInSet(S[I], ['A'..'Z', 'a'..'z', '_']) or
  280. ((I > 1) and CharInSet(S[I], ['0'..'9'])) or
  281. (AllowBackslash and (I > 1) and (I < N) and (S[I] = '\'))) then begin
  282. Result := False;
  283. Exit;
  284. end;
  285. Result := True;
  286. end;
  287. end;
  288. procedure SkipWhitespace(var S: PChar);
  289. begin
  290. while CharInSet(S^, [#1..' ']) do
  291. Inc(S);
  292. end;
  293. function ExtractWords(var S: PChar; const Sep: Char): String;
  294. { Extracts characters from S until it reaches the character Sep or the end
  295. of S. The returned string has trailing whitespace characters trimmed off. }
  296. var
  297. StartPos, EndPos: PChar;
  298. begin
  299. StartPos := S;
  300. EndPos := S;
  301. while (S^ <> #0) and (S^ <> Sep) do begin
  302. if S^ > ' ' then
  303. EndPos := S + 1;
  304. Inc(S);
  305. end;
  306. SetString(Result, StartPos, EndPos - StartPos);
  307. end;
  308. function UnescapeBraces(const S: String): String;
  309. { Changes all '{{' to '{'. Assumes that S does not contain any constants; you
  310. should check before calling. }
  311. var
  312. I: Integer;
  313. begin
  314. Result := S;
  315. I := 1;
  316. while I < Length(Result) do begin
  317. if Result[I] = '{' then begin
  318. Inc(I);
  319. if Result[I] = '{' then
  320. Delete(Result, I, 1);
  321. end
  322. else
  323. Inc(I);
  324. end;
  325. end;
  326. end.