CnSMRBplUtils.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. unit CnSMRBplUtils;
  2. interface
  3. {$I CnWizards.inc}
  4. uses
  5. SysUtils, Windows, Classes, CnBaseUtils;
  6. const
  7. csDefaultPackageExt = '.bpl';
  8. cssExecutableFiles = ' Executable Files ';
  9. cssUnits = 'Units:';
  10. cssRequiredPackages = 'Required Packages:';
  11. { DO NOT LOCALIZE }
  12. csFileNotExists = 'File %s not exists.';
  13. csCanNotAnalyseFile = 'Analyze "%s" failed: ';
  14. type
  15. PPackageInfos = ^TPackageInfos;
  16. TPackageInfos = record
  17. Units: TStrings;
  18. RequiredPackages: TStrings;
  19. end;
  20. TPackageInfosList = class(TStringList)
  21. private
  22. FStringProcessProc: TStringProcessProc;
  23. function GetPackageInfos(Index: Integer): PPackageInfos;
  24. procedure SetPackageInfos(Index: Integer; const Value: PPackageInfos);
  25. function ProcessString(const s: string): string;
  26. procedure ClearPackageInfos;
  27. procedure InternalSaveToText(var Stream: Text);
  28. public
  29. constructor Create;
  30. destructor Destroy; override;
  31. function GetRequiredPackagesSectionName(const s: string): string; virtual;
  32. function GetUnitsSectionName(const s: string): string; virtual;
  33. procedure AddFile(const FileName: string);
  34. procedure Clear; override;
  35. procedure Delete(Index: Integer); override;
  36. procedure BuildPackageUsedBy(UsedByPackagesList: TStringObjectList); overload;
  37. procedure BuildPackageUsedBy(UsedByPackagesList: TStringObjectList; TempStrings: TStrings); overload;
  38. procedure BuildUnits(Units: TStringObjectList);
  39. procedure GetAllAffectedPackages(UsedByPackagesList: TStringObjectList; ssUsedByPackages, ssAllAffectedPackages: TStrings);
  40. procedure GetAllRequiredPackages(ssRequiredPackages, ssAllRequiredPackages: TStrings);
  41. procedure GetAllUsedByPackages(UsedByPackagesList: TStringObjectList; ssUsedByPackages, ssAllUsedByPackages: TStrings);
  42. procedure GetRequiredPackages(const s: string; ssAllRequiredPackages: TStrings);
  43. procedure GetUsedByPackages(UsedByPackagesList: TStringObjectList; const s: string; ssAllUsedByPackages: TStrings);
  44. procedure AppendToFile(const FileName: string);
  45. procedure LoadFromFile(const FileName: string); override;
  46. procedure SaveToFile(const FileName: string); override;
  47. property PackageInfos[Index: Integer]: PPackageInfos read GetPackageInfos write SetPackageInfos;
  48. property StringProcessProc: TStringProcessProc read FStringProcessProc write FStringProcessProc;
  49. end;
  50. function NewPackageInfos: PPackageInfos;
  51. function NewPackageInfosAndCreateList: PPackageInfos;
  52. procedure DisposePackageInfos(P: PPackageInfos);
  53. function EnumUnits(const FileName: string; ss: TStrings): Boolean; overload;
  54. function EnumUnits(const Module: HMODULE; ss: TStrings): Boolean; overload;
  55. function EnumRequiredPackages(const FileName: string; ss: TStrings): Boolean; overload;
  56. function EnumRequiredPackages(const Module: HMODULE; ss: TStrings): Boolean; overload;
  57. function EnumPackageInfos(const FileName: string; ssUnits, ssRequiredPackages: TStrings): Boolean; overload;
  58. function EnumPackageInfos(const Module: HMODULE; ssUnits, ssRequiredPackages: TStrings): Boolean; overload;
  59. implementation
  60. {$IFDEF DELPHI7_UP}
  61. {$WARN SYMBOL_PLATFORM OFF}
  62. {$WARN UNIT_PLATFORM OFF}
  63. {$ENDIF}
  64. uses
  65. FileCtrl, CnBuffStr, CnSMRPEUtils;
  66. function NewPackageInfos: PPackageInfos;
  67. begin
  68. New(Result);
  69. Result.Units := nil;
  70. Result.RequiredPackages := nil;
  71. end;
  72. function NewPackageInfosAndCreateList: PPackageInfos;
  73. begin
  74. New(Result);
  75. Result.Units := TStringList.Create;
  76. TStringList(Result.Units).Sorted := True;
  77. Result.RequiredPackages := TStringList.Create;
  78. TStringList(Result.RequiredPackages).Sorted := True;
  79. end;
  80. procedure DisposePackageInfos(P: PPackageInfos);
  81. begin
  82. if P <> nil then
  83. begin
  84. if Assigned(P.Units) then
  85. begin
  86. FreeAndNil(P.Units);
  87. end;
  88. if Assigned(P.RequiredPackages) then
  89. begin
  90. FreeAndNil(P.RequiredPackages);
  91. end;
  92. Dispose(P);
  93. end;
  94. end;
  95. procedure GetPackageInfosProc(const Name: string; NameType: TNameType; Flags: Byte;
  96. Param: Pointer);
  97. var
  98. P: PPackageInfos;
  99. begin
  100. P := PPackageInfos(Param);
  101. if not Assigned(P) then
  102. begin
  103. Exit;
  104. end;
  105. if (NameType = ntContainsUnit) and (Assigned(P.Units)) then
  106. begin
  107. P.Units.Add(Name);
  108. end
  109. else if (NameType = ntRequiresPackage) and (Assigned(P.RequiredPackages)) then
  110. begin
  111. P.RequiredPackages.Add(Name);
  112. end;
  113. end;
  114. function EnumUnits(const FileName: string; ss: TStrings): Boolean;
  115. begin
  116. Result := EnumPackageInfos(FileName, ss, nil);
  117. end;
  118. function EnumUnits(const Module: HMODULE; ss: TStrings): Boolean;
  119. begin
  120. Result := EnumPackageInfos(Module, ss, nil);
  121. end;
  122. function EnumRequiredPackages(const FileName: string; ss: TStrings): Boolean;
  123. begin
  124. Result := EnumPackageInfos(FileName, nil, ss);
  125. end;
  126. function EnumRequiredPackages(const Module: HMODULE; ss: TStrings): Boolean;
  127. begin
  128. Result := EnumPackageInfos(Module, nil, ss);
  129. end;
  130. function EnumPackageInfos(const FileName: string; ssUnits, ssRequiredPackages: TStrings): Boolean;
  131. var
  132. Module: HMODULE;
  133. begin
  134. Result := False;
  135. if not FileExists(FileName) then
  136. begin
  137. Exit;
  138. end;
  139. Module := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
  140. if Module = 0 then
  141. begin
  142. RaiseLastWin32Error;
  143. end;
  144. try
  145. Result := EnumPackageInfos(Module, ssUnits, ssRequiredPackages);
  146. finally
  147. FreeLibrary(Module);
  148. end;
  149. end;
  150. function EnumPackageInfos(const Module: HMODULE; ssUnits, ssRequiredPackages: TStrings): Boolean;
  151. var
  152. Flags: Integer;
  153. PI: TPackageInfos;
  154. begin
  155. Result := False;
  156. if FindResource(Module, 'PACKAGEINFO', RT_RCDATA) <> 0 then
  157. begin
  158. PI.Units := ssUnits;
  159. PI.RequiredPackages := ssRequiredPackages;
  160. GetPackageInfo(Module, @PI, Flags, GetPackageInfosProc);
  161. Result := True;
  162. end;
  163. end;
  164. { TPackageInfosList }
  165. procedure TPackageInfosList.AddFile(const FileName: string);
  166. var
  167. P: PPackageInfos;
  168. begin
  169. if not FileExists(FileName) then
  170. begin
  171. raise Exception.CreateFmt(csFileNotExists, [AnsiQuotedStr(FileName, '"')]);
  172. end;
  173. P := NewPackageInfosAndCreateList;
  174. try
  175. EnumPackageInfos(FileName, P.Units, P.RequiredPackages);
  176. if P.RequiredPackages.Count = 0 then
  177. GetImportTable(P.RequiredPackages, FileName);
  178. except
  179. on E: Exception do
  180. begin
  181. DisposePackageInfos(P);
  182. E.Message := Format(csCanNotAnalyseFile, [FileName]) + E.Message;
  183. raise;
  184. end;
  185. end;
  186. AddObject(FileName, Pointer(P));
  187. end;
  188. procedure TPackageInfosList.AppendToFile(const FileName: string);
  189. var
  190. Stream: TextFile;
  191. begin
  192. AssignFile(Stream, FileName);
  193. try
  194. if FileExists(FileName) then
  195. begin
  196. System.Append(Stream);
  197. end
  198. else
  199. begin
  200. Rewrite(Stream);
  201. end;
  202. InternalSaveToText(Stream);
  203. finally
  204. CloseFile(Stream);
  205. end;
  206. end;
  207. procedure TPackageInfosList.BuildPackageUsedBy(
  208. UsedByPackagesList: TStringObjectList; TempStrings: TStrings);
  209. var
  210. i, j: Integer;
  211. idx: Integer;
  212. P: PPackageInfos;
  213. sRequiredPackage, sPackages, s: string;
  214. begin
  215. if not (Assigned(UsedByPackagesList) and Assigned(TempStrings)) then
  216. begin
  217. Exit;
  218. end;
  219. UsedByPackagesList.BeginUpdate;
  220. try
  221. UsedByPackagesList.Clear;
  222. for i := 0 to Self.Count - 1 do
  223. begin
  224. P := Self.PackageInfos[i];
  225. if (P <> nil) and (P.RequiredPackages <> nil) then
  226. begin
  227. for j := 0 to P.RequiredPackages.Count - 1 do
  228. begin
  229. sRequiredPackage := P.RequiredPackages[j];
  230. if ExtractFileExt(sRequiredPackage) = '' then
  231. begin
  232. sRequiredPackage := sRequiredPackage + csDefaultPackageExt;
  233. end;
  234. with UsedByPackagesList do
  235. begin
  236. idx := IndexOf(sRequiredPackage);
  237. if idx >= 0 then
  238. begin
  239. s := Strings[idx];
  240. SetCommaText(StringObjects[idx], TempStrings);
  241. TempStrings.Add(Self[i]);
  242. sPackages := TempStrings.CommaText;
  243. Delete(idx);
  244. end
  245. else
  246. begin
  247. sPackages := AnsiQuotedStr(Self[i], '"');
  248. end;
  249. AddStringObject(sRequiredPackage, sPackages);
  250. end;
  251. end;
  252. end;
  253. end;
  254. finally
  255. UsedByPackagesList.EndUpdate;
  256. end;
  257. end;
  258. procedure TPackageInfosList.BuildUnits(Units: TStringObjectList);
  259. var
  260. i, j: Integer;
  261. idx: Integer;
  262. P: PPackageInfos;
  263. sUnit, sPackages, s: string;
  264. begin
  265. Units.BeginUpdate;
  266. try
  267. Units.Clear;
  268. for i := 0 to Self.Count - 1 do
  269. begin
  270. P := Self.PackageInfos[i];
  271. if (P <> nil) and (P.Units <> nil) then
  272. begin
  273. for j := 0 to P.Units.Count - 1 do
  274. begin
  275. sUnit := P.Units[j];
  276. with Units do
  277. begin
  278. idx := IndexOf(sUnit);
  279. if idx >= 0 then
  280. begin
  281. s := Strings[idx];
  282. sPackages := StringObjects[idx] + ',' + AnsiQuotedStr(Self[i], '"');
  283. Delete(idx);
  284. end
  285. else
  286. begin
  287. sPackages := AnsiQuotedStr(Self[i], '"');
  288. end;
  289. AddStringObject(sUnit, sPackages);
  290. end;
  291. end;
  292. end;
  293. end;
  294. finally
  295. Units.EndUpdate;
  296. end;
  297. end;
  298. procedure TPackageInfosList.BuildPackageUsedBy(UsedByPackagesList: TStringObjectList);
  299. var
  300. sstmp: TStringList;
  301. begin
  302. sstmp := TStringList.Create;
  303. try
  304. sstmp.Sorted := True;
  305. BuildPackageUsedBy(UsedByPackagesList, sstmp);
  306. finally
  307. sstmp.Free;
  308. end;
  309. end;
  310. procedure TPackageInfosList.Clear;
  311. begin
  312. ClearPackageInfos;
  313. inherited;
  314. end;
  315. procedure TPackageInfosList.ClearPackageInfos;
  316. var
  317. i: Integer;
  318. begin
  319. for i := 0 to Count - 1 do
  320. begin
  321. DisposePackageInfos(PPackageInfos(Objects[i]));
  322. end;
  323. end;
  324. constructor TPackageInfosList.Create;
  325. begin
  326. inherited;
  327. end;
  328. procedure TPackageInfosList.Delete(Index: Integer);
  329. begin
  330. if (Index < 0) or (Index >= Count) then
  331. begin
  332. Exit;
  333. end;
  334. DisposePackageInfos(PackageInfos[Index]);
  335. inherited;
  336. end;
  337. destructor TPackageInfosList.Destroy;
  338. begin
  339. Clear;
  340. inherited;
  341. end;
  342. procedure TPackageInfosList.GetAllAffectedPackages(
  343. UsedByPackagesList: TStringObjectList;
  344. ssUsedByPackages, ssAllAffectedPackages: TStrings);
  345. var
  346. i, j, idx: Integer;
  347. ss: TStringList;
  348. begin
  349. if not (Assigned(ssUsedByPackages) and Assigned(ssAllAffectedPackages) and
  350. Assigned(UsedByPackagesList)) then
  351. begin
  352. Exit;
  353. end;
  354. ssAllAffectedPackages.Clear;
  355. for i := 0 to ssUsedByPackages.Count - 1 do
  356. begin
  357. ssAllAffectedPackages.Add(ssUsedByPackages[i]);
  358. end;
  359. ss := TStringList.Create;
  360. try
  361. for i := 0 to ssUsedByPackages.Count - 1 do
  362. begin
  363. idx := UsedByPackagesList.IndexOf(ssUsedByPackages[i]);
  364. if idx >= 0 then
  365. begin
  366. SetCommaText(UsedByPackagesList.StringObjects[idx], ss);
  367. for j := 0 to ss.Count - 1 do
  368. begin
  369. if ssAllAffectedPackages.IndexOf(ss[j]) < 0 then
  370. ssAllAffectedPackages.Add(ss[j]);
  371. end;
  372. end;
  373. end;
  374. finally
  375. ss.Free;
  376. end;
  377. end;
  378. procedure TPackageInfosList.GetAllRequiredPackages(ssRequiredPackages,
  379. ssAllRequiredPackages: TStrings);
  380. var
  381. i: Integer;
  382. s: string;
  383. begin
  384. if not (Assigned(ssRequiredPackages) and Assigned(ssAllRequiredPackages)) then
  385. begin
  386. Exit;
  387. end;
  388. for i := 0 to ssRequiredPackages.Count - 1 do
  389. begin
  390. s := ssRequiredPackages[i];
  391. if ssAllRequiredPackages.IndexOf(s) >= 0 then
  392. begin
  393. Continue;
  394. end;
  395. ssAllRequiredPackages.Add(s);
  396. GetRequiredPackages(s, ssAllRequiredPackages);
  397. end;
  398. end;
  399. procedure TPackageInfosList.GetAllUsedByPackages(UsedByPackagesList: TStringObjectList;
  400. ssUsedByPackages, ssAllUsedByPackages: TStrings);
  401. var
  402. i: Integer;
  403. s: string;
  404. begin
  405. if not (Assigned(ssUsedByPackages) and Assigned(ssAllUsedByPackages) and Assigned(UsedByPackagesList)) then
  406. begin
  407. Exit;
  408. end;
  409. for i := 0 to ssUsedByPackages.Count - 1 do
  410. begin
  411. s := ssUsedByPackages[i];
  412. if ssAllUsedByPackages.IndexOf(s) >= 0 then
  413. begin
  414. Continue;
  415. end;
  416. ssAllUsedByPackages.Add(s);
  417. GetUsedByPackages(UsedByPackagesList, s, ssAllUsedByPackages);
  418. end;
  419. end;
  420. function TPackageInfosList.GetPackageInfos(Index: Integer): PPackageInfos;
  421. begin
  422. if (Index < 0) or (Index >= Count) then
  423. begin
  424. Result := nil;
  425. Exit;
  426. end;
  427. Result := Pointer(Objects[Index]);
  428. end;
  429. function TPackageInfosList.GetRequiredPackagesSectionName(
  430. const s: string): string;
  431. begin
  432. Result := cssRequiredPackages + s;
  433. end;
  434. procedure TPackageInfosList.GetRequiredPackages(const s: string;
  435. ssAllRequiredPackages: TStrings);
  436. var
  437. P: PPackageInfos;
  438. begin
  439. P := Self.PackageInfos[Self.IndexOf(s)];
  440. if not (Assigned(ssAllRequiredPackages) and Assigned(P)) then
  441. begin
  442. Exit;
  443. end;
  444. GetAllRequiredPackages(P.RequiredPackages, ssAllRequiredPackages);
  445. end;
  446. function TPackageInfosList.GetUnitsSectionName(const s: string): string;
  447. begin
  448. Result := cssUnits + s;
  449. end;
  450. procedure TPackageInfosList.GetUsedByPackages(UsedByPackagesList: TStringObjectList;
  451. const s: string; ssAllUsedByPackages: TStrings);
  452. var
  453. idx: Integer;
  454. ss: TStringList;
  455. begin
  456. if not (Assigned(ssAllUsedByPackages) and Assigned(UsedByPackagesList)) then
  457. begin
  458. Exit;
  459. end;
  460. idx := UsedByPackagesList.IndexOf(s);
  461. if idx < 0 then
  462. begin
  463. Exit;
  464. end;
  465. ss := TStringList.Create;
  466. try
  467. SetCommaText(UsedByPackagesList.StringObjects[idx], ss);
  468. GetAllUsedByPackages(UsedByPackagesList, ss, ssAllUsedByPackages);
  469. finally
  470. ss.Free;
  471. end;
  472. end;
  473. procedure TPackageInfosList.InternalSaveToText(var Stream: Text);
  474. var
  475. i: Integer;
  476. begin
  477. //Save Head
  478. StringsSaveToTextWithSection(Self, Stream, cssExecutableFiles, False, StringProcessProc);
  479. //Save Results
  480. for i := 0 to Count - 1 do
  481. begin
  482. if PackageInfos[i] <> nil then
  483. begin
  484. with PackageInfos[i]^ do
  485. begin
  486. StringsSaveToTextWithSection(
  487. Units,
  488. Stream,
  489. GetUnitsSectionName(ProcessString(Strings[i])));
  490. StringsSaveToTextWithSection(
  491. RequiredPackages,
  492. Stream,
  493. GetRequiredPackagesSectionName(ProcessString(Strings[i])));
  494. end;
  495. end;
  496. end;
  497. end;
  498. procedure TPackageInfosList.LoadFromFile(const FileName: string);
  499. var
  500. P: PPackageInfos;
  501. Stream: TStringReader;
  502. i: Integer;
  503. sl: TSectionList;
  504. begin
  505. Stream := TStringReader.Create;
  506. try
  507. Stream.LoadFromFile(FileName);
  508. BulidSectionList(Stream, sl);
  509. // sl := nil;
  510. BeginUpdate;
  511. try
  512. Clear;
  513. //Load Head
  514. StringsLoadFromTextWithSection(Self, Stream, cssExecutableFiles, sl);
  515. //Load Results
  516. for i := 0 to Count - 1 do
  517. begin
  518. P := NewPackageInfosAndCreateList;
  519. try
  520. PackageInfos[i] := P;
  521. StringsLoadFromTextWithSection(P.Units,
  522. Stream,
  523. GetUnitsSectionName(Strings[i]),
  524. sl);
  525. StringsLoadFromTextWithSection(
  526. P.RequiredPackages,
  527. Stream,
  528. GetRequiredPackagesSectionName(Strings[i]),
  529. sl);
  530. except
  531. DisposePackageInfos(P);
  532. raise;
  533. end;
  534. end;
  535. finally
  536. EndUpdate;
  537. end;
  538. finally
  539. Stream.Free;
  540. FreeSectionList(sl);
  541. end;
  542. end;
  543. function TPackageInfosList.ProcessString(const s: string): string;
  544. begin
  545. if Assigned(StringProcessProc) then
  546. begin
  547. Result := StringProcessProc(s);
  548. end
  549. else
  550. begin
  551. Result := s;
  552. end;
  553. end;
  554. procedure TPackageInfosList.SaveToFile(const FileName: string);
  555. var
  556. Stream: TextFile;
  557. begin
  558. AssignFile(Stream, FileName);
  559. try
  560. Rewrite(Stream);
  561. InternalSaveToText(Stream);
  562. finally
  563. CloseFile(Stream);
  564. end;
  565. end;
  566. procedure TPackageInfosList.SetPackageInfos(Index: Integer;
  567. const Value: PPackageInfos);
  568. begin
  569. if (Index < 0) or (Index >= Count) then
  570. begin
  571. Exit;
  572. end;
  573. PutObject(Index, Pointer(Value));
  574. end;
  575. end.