2
0

wresourc.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by Berczi Gabor
  5. Resource File support objects and routines
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit WResourc;
  13. interface
  14. uses Objects;
  15. const
  16. TPDataBlockSignature = ord('F')+ord('B')*256;
  17. ResourceBlockSignature = ord('R')+ord('D')*256;
  18. langDefault = 0;
  19. rcBinary = 1;
  20. type
  21. TResourceEntryHeader = packed record
  22. ID : longint;
  23. LangID : longint;
  24. Flags : longint;
  25. DataOfs: longint;
  26. DataLen: longint;
  27. end;
  28. TResourceHeader = packed record
  29. _Class : longint;
  30. Flags : longint;
  31. NameLen : word;
  32. EntryCount : word;
  33. end;
  34. TResourceFileHeader = packed record
  35. Signature : word;
  36. InfoType : word;
  37. InfoSize : longint;
  38. { ---- }
  39. TableOfs : longint;
  40. end;
  41. PResourceEntry = ^TResourceEntry;
  42. TResourceEntry = object(TObject)
  43. constructor Init(AID, ALangID, AFlags, ADataLen: longint);
  44. private
  45. ID : longint;
  46. LangID : longint;
  47. Flags : longint;
  48. DataOfs : longint;
  49. DataLen : longint;
  50. procedure BuildHeader(var Header : TResourceEntryHeader);
  51. end;
  52. PResourceEntryCollection = ^TResourceEntryCollection;
  53. TResourceEntryCollection = object(TSortedCollection)
  54. function At(Index: Sw_Integer): PResourceEntry;
  55. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  56. function SearchEntryForLang(ALangID: longint): PResourceEntry;
  57. end;
  58. PGlobalResourceEntryCollection = ^TGlobalResourceEntryCollection;
  59. TGlobalResourceEntryCollection = object(TSortedCollection)
  60. function At(Index: Sw_Integer): PResourceEntry;
  61. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  62. end;
  63. PResource = ^TResource;
  64. TResource = object(TObject)
  65. constructor Init(const AName: string; AClass, AFlags: longint);
  66. function GetName: string; virtual;
  67. function FirstThatEntry(Func: pointer): PResourceEntry; virtual;
  68. procedure ForEachEntry(Func: pointer); virtual;
  69. destructor Done; virtual;
  70. private
  71. Name : PString;
  72. _Class : longint;
  73. Flags : longint;
  74. Items : PResourceEntryCollection;
  75. procedure BuildHeader(var Header : TResourceHeader);
  76. end;
  77. TResourceCollection = object(TSortedCollection)
  78. function At(Index: Sw_Integer): PResource;
  79. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  80. function SearchResourceByName(const AName: string): PResource;
  81. end;
  82. PResourceCollection = ^TResourceCollection;
  83. TResourceFile = object(TObject)
  84. constructor Init(var RS: TStream; ALoad: boolean);
  85. constructor Create(var RS: TStream);
  86. constructor Load(var RS: TStream);
  87. constructor CreateFile(AFileName: string);
  88. constructor LoadFile(AFileName: string);
  89. function FirstThatResource(Func: pointer): PResource; virtual;
  90. procedure ForEachResource(Func: pointer); virtual;
  91. procedure ForEachResourceEntry(Func: pointer); virtual;
  92. function CreateResource(const Name: string; AClass, AFlags: longint): boolean; virtual;
  93. function AddResourceEntry(const ResName: string; ALangID, AFlags: longint; var Data;
  94. ADataSize: sw_integer): boolean; virtual;
  95. function AddResourceEntryFromStream(const ResName: string; ALangID, AFlags: longint;
  96. var Source: TStream; ADataSize: longint): boolean; virtual;
  97. function DeleteResourceEntry(const ResName: string; ALangID: longint): boolean; virtual;
  98. function DeleteResource(const ResName: string): boolean; virtual;
  99. function ReadResourceEntry(const ResName: string; ALangID: longint; var Buf; var BufSize: sw_word): boolean;
  100. function ReadResourceEntryToStream(const ResName: string; ALangID: longint; var DestS: TStream): boolean;
  101. procedure Flush; virtual;
  102. destructor Done; virtual;
  103. public
  104. BaseOfs: longint;
  105. function FindResource(const ResName: string): PResource;
  106. function FindResourceEntry(const ResName: string; ALangID: longint): PResourceEntry;
  107. private
  108. S : PStream;
  109. MyStream : boolean;
  110. Resources : PResourceCollection;
  111. Entries : PGlobalResourceEntryCollection;
  112. Header : TResourceFileHeader;
  113. Modified : boolean;
  114. procedure UpdateBlockDatas;
  115. function GetNextEntryID: longint;
  116. function GetTotalSize(IncludeHeaders: boolean): longint;
  117. function CalcSizes(IncludeHeaders, UpdatePosData: boolean): longint;
  118. procedure AddResEntryPtr(P: PResource; E: PResourceEntry);
  119. procedure RemoveResEntryPtr(P: PResource; E: PResourceEntry);
  120. function DeleteArea(AreaStart, AreaSize, TotalSize: longint): boolean;
  121. procedure BuildFileHeader;
  122. procedure WriteHeader;
  123. procedure WriteResourceTable;
  124. end;
  125. PResourceFile = ^TResourceFile;
  126. implementation
  127. uses CallSpec,
  128. WUtils;
  129. function TResourceEntryCollection.At(Index: Sw_Integer): PResourceEntry;
  130. begin
  131. At:=inherited At(Index);
  132. end;
  133. function TResourceEntryCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  134. var K1: PResourceEntry absolute Key1;
  135. K2: PResourceEntry absolute Key2;
  136. Re: Sw_integer;
  137. begin
  138. if K1^.LangID<K2^.LangID then Re:=-1 else
  139. if K1^.LangID>K2^.LangID then Re:= 1 else
  140. Re:=0;
  141. Compare:=Re;
  142. end;
  143. function TResourceEntryCollection.SearchEntryForLang(ALangID: longint): PResourceEntry;
  144. var P: PResourceEntry;
  145. E: TResourceEntry;
  146. Index: sw_integer;
  147. begin
  148. E.LangID:=ALangID;
  149. if Search(@E,Index)=false then P:=nil else
  150. P:=At(Index);
  151. SearchEntryForLang:=P;
  152. end;
  153. function TGlobalResourceEntryCollection.At(Index: Sw_Integer): PResourceEntry;
  154. begin
  155. At:=inherited At(Index);
  156. end;
  157. function TGlobalResourceEntryCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  158. var K1: PResourceEntry absolute Key1;
  159. K2: PResourceEntry absolute Key2;
  160. Re: Sw_integer;
  161. begin
  162. if K1^.ID<K2^.ID then Re:=-1 else
  163. if K1^.ID>K2^.ID then Re:= 1 else
  164. Re:=0;
  165. Compare:=Re;
  166. end;
  167. constructor TResourceEntry.Init(AID, ALangID, AFlags, ADataLen: longint);
  168. begin
  169. inherited Init;
  170. ID:=AID;
  171. LangID:=ALangID; Flags:=AFlags; DataLen:=ADataLen;
  172. end;
  173. procedure TResourceEntry.BuildHeader(var Header : TResourceEntryHeader);
  174. begin
  175. FillChar(Header,SizeOf(Header),0);
  176. Header.ID:=ID;
  177. Header.LangID:=LangID;
  178. Header.Flags:=Flags;
  179. Header.DataLen:=DataLen;
  180. Header.DataOfs:=DataOfs;
  181. end;
  182. constructor TResource.Init(const AName: string; AClass, AFlags: longint);
  183. begin
  184. inherited Init;
  185. Name:=NewStr(AName);
  186. _Class:=AClass;
  187. Flags:=AFlags;
  188. New(Items, Init(10,50));
  189. end;
  190. function TResource.GetName: string;
  191. begin
  192. GetName:=GetStr(Name);
  193. end;
  194. function TResource.FirstThatEntry(Func: pointer): PResourceEntry;
  195. var EP,P: PResourceEntry;
  196. I: sw_integer;
  197. begin
  198. P:=nil;
  199. for I:=0 to Items^.Count-1 do
  200. begin
  201. EP:=Items^.At(I);
  202. if Byte(Longint(CallPointerMethodLocal(Func,PreviousFramePointer,@Self,EP)))<>0 then
  203. begin
  204. P := EP;
  205. Break;
  206. end;
  207. end;
  208. FirstThatEntry:=P;
  209. end;
  210. procedure TResource.ForEachEntry(Func: pointer);
  211. var RP: PResourceEntry;
  212. I: sw_integer;
  213. begin
  214. for I:=0 to Items^.Count-1 do
  215. begin
  216. RP:=Items^.At(I);
  217. CallPointerMethodLocal(Func,PreviousFramePointer,@Self,RP);
  218. end;
  219. end;
  220. procedure TResource.BuildHeader(var Header : TResourceHeader);
  221. begin
  222. FillChar(Header,SizeOf(Header),0);
  223. Header._Class:=_Class;
  224. Header.Flags:=Flags;
  225. Header.NameLen:=length(GetName);
  226. Header.EntryCount:=Items^.Count;
  227. end;
  228. destructor TResource.Done;
  229. begin
  230. inherited Done;
  231. if Name<>nil then DisposeStr(Name); Name:=nil;
  232. if Items<>nil then Dispose(Items, Done); Items:=nil;
  233. end;
  234. function TResourceCollection.At(Index: Sw_Integer): PResource;
  235. begin
  236. At:=inherited At(Index);
  237. end;
  238. function TResourceCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  239. var K1: PResource absolute Key1;
  240. K2: PResource absolute Key2;
  241. N1,N2: string;
  242. Re: Sw_integer;
  243. begin
  244. N1:=UpcaseStr(K1^.GetName); N2:=UpcaseStr(K2^.GetName);
  245. if N1<N2 then Re:=-1 else
  246. if N1>N2 then Re:= 1 else
  247. Re:=0;
  248. Compare:=Re;
  249. end;
  250. function TResourceCollection.SearchResourceByName(const AName: string): PResource;
  251. var P,R: PResource;
  252. Index: sw_integer;
  253. begin
  254. New(R, Init(AName,0,0));
  255. if Search(R,Index)=false then P:=nil else
  256. P:=At(Index);
  257. Dispose(R, Done);
  258. SearchResourceByName:=P;
  259. end;
  260. constructor TResourceFile.Create(var RS: TStream);
  261. begin
  262. if Init(RS,false)=false then
  263. Fail;
  264. end;
  265. constructor TResourceFile.Load(var RS: TStream);
  266. begin
  267. if Init(RS,true)=false then
  268. Fail;
  269. end;
  270. constructor TResourceFile.Init(var RS: TStream; ALoad: boolean);
  271. var OK: boolean;
  272. RH: TResourceHeader;
  273. REH: TResourceEntryHeader;
  274. EndPos,I: longint;
  275. P: PResource;
  276. E: PResourceEntry;
  277. St: string;
  278. begin
  279. inherited Init;
  280. S:=@RS;
  281. New(Resources, Init(100, 1000));
  282. New(Entries, Init(500,2000));
  283. OK:=true;
  284. if ALoad=false then
  285. Modified:=true
  286. else
  287. begin
  288. S^.Reset;
  289. BaseOfs:=S^.GetPos;
  290. S^.Read(Header,SizeOf(Header));
  291. OK:=(S^.Status=stOK) and
  292. (Header.Signature=TPDataBlockSignature) and
  293. (Header.InfoType=ResourceBlockSignature);
  294. if OK then begin S^.Seek(BaseOfs+Header.TableOfs); OK:=S^.Status=stOK; end;
  295. EndPos:=BaseOfs+Header.InfoSize;
  296. if OK then
  297. while OK and (S^.GetPos<EndPos) do
  298. begin
  299. S^.Read(RH,SizeOf(RH)); OK:=(S^.Status=stOK);
  300. if OK then begin St[0]:=chr(RH.NameLen); S^.Read(St[1],RH.NameLen); OK:=(S^.Status=stOK); end;
  301. if OK then
  302. begin
  303. New(P, Init(St,RH._Class,RH.Flags));
  304. Resources^.Insert(P);
  305. end;
  306. I:=0;
  307. while OK and (I<RH.EntryCount) do
  308. begin
  309. S^.Read(REH,SizeOf(REH)); OK:=(S^.Status=stOK);
  310. if OK then
  311. begin
  312. New(E, Init(REH.ID,REH.LangID,REH.Flags,REH.DataLen));
  313. AddResEntryPtr(P,E);
  314. end;
  315. if OK then Inc(I);
  316. end;
  317. if OK then UpdateBlockDatas;
  318. end;
  319. end;
  320. if OK=false then
  321. begin
  322. Done;
  323. Fail;
  324. end;
  325. end;
  326. function TResourceFile.FirstThatResource(Func: pointer): PResource;
  327. var RP,P: PResource;
  328. I: sw_integer;
  329. begin
  330. P:=nil;
  331. for I:=0 to Resources^.Count-1 do
  332. begin
  333. RP:=Resources^.At(I);
  334. if Byte(Longint(CallPointerMethodLocal(Func,PreviousFramePointer,@Self,RP)))<>0 then
  335. begin
  336. P := RP;
  337. Break;
  338. end;
  339. end;
  340. FirstThatResource:=P;
  341. end;
  342. procedure TResourceFile.ForEachResource(Func: pointer);
  343. var RP: PResource;
  344. I: sw_integer;
  345. begin
  346. for I:=0 to Resources^.Count-1 do
  347. begin
  348. RP:=Resources^.At(I);
  349. CallPointerMethodLocal(Func,PreviousFramePointer,@Self,RP);
  350. end;
  351. end;
  352. procedure TResourceFile.ForEachResourceEntry(Func: pointer);
  353. var E: PResourceEntry;
  354. I: sw_integer;
  355. begin
  356. for I:=0 to Entries^.Count-1 do
  357. begin
  358. E:=Entries^.At(I);
  359. CallPointerMethodLocal(Func,PreviousFramePointer,@Self,E);
  360. end;
  361. end;
  362. function TResourceFile.CreateResource(const Name: string; AClass, AFlags: longint): boolean;
  363. var OK: boolean;
  364. P: PResource;
  365. begin
  366. OK:=FindResource(Name)=nil;
  367. if OK then
  368. begin
  369. New(P, Init(Name,AClass,AFlags));
  370. Resources^.Insert(P);
  371. Modified:=true;
  372. end;
  373. CreateResource:=OK;
  374. end;
  375. function TResourceFile.AddResourceEntry(const ResName: string; ALangID, AFlags: longint; var Data;
  376. ADataSize: sw_integer): boolean;
  377. const BlockSize = 4096;
  378. var OK: boolean;
  379. P: PResource;
  380. E: PResourceEntry;
  381. RemSize,CurOfs,FragSize: longint;
  382. begin
  383. P:=FindResource(ResName);
  384. OK:=P<>nil;
  385. if OK then
  386. OK:=(P^.Items^.SearchEntryForLang(ALangID)=nil);
  387. if OK then
  388. begin
  389. New(E, Init(GetNextEntryID,ALangID, AFlags, ADataSize));
  390. AddResEntryPtr(P,E);
  391. UpdateBlockDatas;
  392. RemSize:=ADataSize; CurOfs:=0;
  393. S^.Reset;
  394. S^.Seek(BaseOfs+E^.DataOfs);
  395. while (RemSize>0) do
  396. begin
  397. FragSize:=Min(RemSize,BlockSize);
  398. S^.Write(PByteArray(@Data)^[CurOfs],FragSize);
  399. Dec(RemSize,FragSize); Inc(CurOfs,FragSize);
  400. end;
  401. Modified:=true;
  402. end;
  403. AddResourceEntry:=OK;
  404. end;
  405. function TResourceFile.AddResourceEntryFromStream(const ResName: string; ALangID, AFlags: longint;
  406. var Source: TStream; ADataSize: longint): boolean;
  407. const BufSize = 4096;
  408. var OK: boolean;
  409. P: PResource;
  410. E: PResourceEntry;
  411. RemSize,FragSize: longint;
  412. Buf: pointer;
  413. begin
  414. P:=FindResource(ResName);
  415. OK:=P<>nil;
  416. if OK then
  417. OK:=(P^.Items^.SearchEntryForLang(ALangID)=nil);
  418. if OK then
  419. begin
  420. New(E, Init(GetNextEntryID, ALangID, AFlags, ADataSize));
  421. AddResEntryPtr(P,E);
  422. UpdateBlockDatas;
  423. GetMem(Buf,BufSize);
  424. RemSize:=ADataSize;
  425. S^.Reset;
  426. S^.Seek(BaseOfs+E^.DataOfs);
  427. while (RemSize>0) do
  428. begin
  429. FragSize:=Min(RemSize,BufSize);
  430. Source.Read(Buf^,FragSize);
  431. S^.Write(Buf^,FragSize);
  432. Dec(RemSize,FragSize);
  433. end;
  434. FreeMem(Buf,BufSize);
  435. Modified:=true;
  436. end;
  437. AddResourceEntryFromStream:=OK;
  438. end;
  439. function TResourceFile.DeleteResourceEntry(const ResName: string; ALangID: longint): boolean;
  440. var E: PResourceEntry;
  441. P: PResource;
  442. OK: boolean;
  443. begin
  444. P:=FindResource(ResName);
  445. OK:=P<>nil;
  446. if OK then E:=P^.Items^.SearchEntryForLang(ALangID);
  447. OK:=OK and (E<>nil);
  448. if OK then
  449. begin
  450. OK:=DeleteArea(E^.DataOfs,E^.DataLen,GetTotalSize(false));
  451. if OK then begin RemoveResEntryPtr(P,E); Dispose(E, Done); end;
  452. Modified:=true;
  453. end;
  454. DeleteResourceEntry:=OK;
  455. end;
  456. function TResourceFile.DeleteResource(const ResName: string): boolean;
  457. var P: PResource;
  458. E: PResourceEntry;
  459. OK: boolean;
  460. begin
  461. P:=FindResource(ResName);
  462. OK:=P<>nil;
  463. if P<>nil then
  464. begin
  465. while OK and (P^.Items^.Count>0) do
  466. begin
  467. E:=P^.Items^.At(P^.Items^.Count-1);
  468. OK:=OK and DeleteResourceEntry(ResName,E^.LangID);
  469. end;
  470. Modified:=true;
  471. end;
  472. if OK then Resources^.Free(P);
  473. DeleteResource:=OK;
  474. end;
  475. function TResourceFile.ReadResourceEntry(const ResName: string; ALangID: longint; var Buf; var BufSize: sw_word): boolean;
  476. var E: PResourceEntry;
  477. P: PResource;
  478. OK: boolean;
  479. CurOfs,CurFrag: sw_word;
  480. TempBuf: pointer;
  481. const TempBufSize = 4096;
  482. begin
  483. P:=FindResource(ResName);
  484. OK:=P<>nil;
  485. if OK then E:=P^.Items^.SearchEntryForLang(ALangID);
  486. OK:=OK and (E<>nil);
  487. OK:=OK and (E^.DataLen<=BufSize);
  488. if OK then
  489. begin
  490. GetMem(TempBuf,TempBufSize);
  491. S^.Reset;
  492. S^.Seek(BaseOfs+E^.DataOfs);
  493. OK:=(S^.Status=stOK);
  494. CurOfs:=0;
  495. while OK and (CurOfs<E^.DataLen) do
  496. begin
  497. CurFrag:=Min(E^.DataLen-CurOfs,TempBufSize);
  498. S^.Read(TempBuf^,CurFrag);
  499. OK:=OK and (S^.Status=stOK);
  500. if OK then
  501. Move(TempBuf^,PByteArray(@Buf)^[CurOfs],CurFrag);
  502. Inc(CurOfs,CurFrag);
  503. end;
  504. FreeMem(TempBuf,TempBufSize);
  505. end;
  506. ReadResourceEntry:=OK;
  507. end;
  508. function TResourceFile.ReadResourceEntryToStream(const ResName: string; ALangID: longint; var DestS: TStream): boolean;
  509. var E: PResourceEntry;
  510. P: PResource;
  511. OK: boolean;
  512. CurOfs,CurFrag: sw_word;
  513. TempBuf: pointer;
  514. const TempBufSize = 4096;
  515. begin
  516. P:=FindResource(ResName);
  517. OK:=P<>nil;
  518. if OK then E:=P^.Items^.SearchEntryForLang(ALangID);
  519. OK:=OK and (E<>nil);
  520. if OK then
  521. begin
  522. GetMem(TempBuf,TempBufSize);
  523. S^.Reset;
  524. S^.Seek(BaseOfs+E^.DataOfs);
  525. OK:=(S^.Status=stOK);
  526. CurOfs:=0;
  527. { this results sometimes in endless loops
  528. when the resource are changed PM }
  529. if E^.DataLen<0 then
  530. OK:=false;
  531. while OK and (CurOfs<E^.DataLen) do
  532. begin
  533. CurFrag:=Min(E^.DataLen-CurOfs,TempBufSize);
  534. S^.Read(TempBuf^,CurFrag);
  535. OK:=OK and (S^.Status=stOK);
  536. if OK then
  537. DestS.Write(TempBuf^,CurFrag);
  538. OK:=OK and (DestS.Status=stOK);
  539. Inc(CurOfs,CurFrag);
  540. end;
  541. FreeMem(TempBuf,TempBufSize);
  542. end;
  543. ReadResourceEntryToStream:=OK;
  544. end;
  545. function TResourceFile.FindResource(const ResName: string): PResource;
  546. begin
  547. FindResource:=Resources^.SearchResourceByName(ResName);
  548. end;
  549. function TResourceFile.FindResourceEntry(const ResName: string; ALangID: longint): PResourceEntry;
  550. var P: PResource;
  551. E: PResourceEntry;
  552. begin
  553. E:=nil;
  554. P:=FindResource(ResName);
  555. if P<>nil then
  556. E:=P^.Items^.SearchEntryForLang(ALangID);
  557. FindResourceEntry:=E;
  558. end;
  559. procedure TResourceFile.Flush;
  560. begin
  561. if Modified=false then Exit;
  562. BuildFileHeader;
  563. S^.Seek(BaseOfs);
  564. WriteHeader;
  565. S^.Seek(BaseOfs+Header.TableOfs);
  566. WriteResourceTable;
  567. S^.Truncate;
  568. Modified:=false;
  569. end;
  570. procedure TResourceFile.BuildFileHeader;
  571. begin
  572. FillChar(Header,SizeOf(Header),0);
  573. with Header do
  574. begin
  575. Signature:=TPDataBlockSignature;
  576. InfoType:=ResourceBlockSignature;
  577. InfoSize:=GetTotalSize(true);
  578. TableOfs:=GetTotalSize(false);
  579. end;
  580. end;
  581. procedure TResourceFile.WriteHeader;
  582. begin
  583. S^.Write(Header,SizeOf(Header));
  584. end;
  585. procedure TResourceFile.WriteResourceTable;
  586. var RH: TResourceHeader;
  587. REH: TResourceEntryHeader;
  588. procedure WriteResource(P: PResource); {$ifndef FPC}far;{$endif}
  589. procedure WriteResourceEntry(P: PResourceEntry); {$ifndef FPC}far;{$endif}
  590. begin
  591. P^.BuildHeader(REH);
  592. S^.Write(REH,SizeOf(REH));
  593. end;
  594. var N: string;
  595. begin
  596. if P^.Items^.Count=0 then Exit; { do not store resources with no entries }
  597. P^.BuildHeader(RH);
  598. S^.Write(RH,SizeOf(RH));
  599. N:=P^.GetName;
  600. S^.Write(N[1],length(N));
  601. P^.ForEachEntry(@WriteResourceEntry);
  602. end;
  603. begin
  604. ForEachResource(@WriteResource);
  605. end;
  606. procedure TResourceFile.UpdateBlockDatas;
  607. begin
  608. CalcSizes(false,true);
  609. end;
  610. function TResourceFile.GetTotalSize(IncludeHeaders: boolean): longint;
  611. begin
  612. GetTotalSize:=CalcSizes(IncludeHeaders,false);
  613. end;
  614. function TResourceFile.CalcSizes(IncludeHeaders, UpdatePosData: boolean): longint;
  615. var RH : TResourceHeader;
  616. REH : TResourceEntryHeader;
  617. Size: longint;
  618. NamesSize: longint;
  619. procedure AddResourceEntrySize(P: PResourceEntry); {$ifndef FPC}far;{$endif}
  620. begin
  621. if UpdatePosData then P^.DataOfs:=Size;
  622. P^.BuildHeader(REH);
  623. Inc(Size,REH.DataLen);
  624. end;
  625. procedure AddResourceSize(P: PResource); {$ifndef FPC}far;{$endif}
  626. var RH: TResourceHeader;
  627. begin
  628. P^.BuildHeader(RH);
  629. Inc(NamesSize,RH.NameLen);
  630. end;
  631. begin
  632. Size:=0; NamesSize:=0;
  633. Inc(Size,SizeOf(Header)); { this is on start so we always include it }
  634. ForEachResourceEntry(@AddResourceEntrySize);
  635. if IncludeHeaders then
  636. begin
  637. ForEachResource(@AddResourceSize);
  638. Inc(Size,SizeOf(RH)*Resources^.Count);
  639. Inc(Size,SizeOf(REH)*Entries^.Count);
  640. Inc(Size,NamesSize);
  641. end;
  642. CalcSizes:=Size;
  643. end;
  644. function TResourceFile.DeleteArea(AreaStart, AreaSize, TotalSize: longint): boolean;
  645. const BufSize = 4096;
  646. var RemSize,FragSize,CurOfs: longint;
  647. Buf: pointer;
  648. OK: boolean;
  649. begin
  650. GetMem(Buf,BufSize);
  651. RemSize:=TotalSize-(AreaStart+AreaSize); CurOfs:=0;
  652. OK:=RemSize>=0;
  653. while (RemSize>0) do
  654. begin
  655. FragSize:=Min(RemSize,BufSize);
  656. S^.Seek(BaseOfs+AreaStart+AreaSize+CurOfs);
  657. S^.Read(Buf^,BufSize);
  658. OK:=OK and (S^.Status=stOK);
  659. if OK then
  660. begin
  661. S^.Seek(BaseOfs+AreaStart+CurOfs);
  662. S^.Write(Buf^,BufSize);
  663. OK:=OK and (S^.Status=stOK);
  664. end;
  665. Inc(CurOfs,FragSize); Dec(RemSize,FragSize);
  666. end;
  667. FreeMem(Buf,BufSize);
  668. DeleteArea:=OK;
  669. end;
  670. procedure TResourceFile.AddResEntryPtr(P: PResource; E: PResourceEntry);
  671. begin
  672. if (P=nil) or (E=nil) then Exit;
  673. P^.Items^.Insert(E);
  674. Entries^.Insert(E);
  675. end;
  676. procedure TResourceFile.RemoveResEntryPtr(P: PResource; E: PResourceEntry);
  677. begin
  678. if (P=nil) or (E=nil) then Exit;
  679. Entries^.Delete(E);
  680. P^.Items^.Delete(E);
  681. end;
  682. function TResourceFile.GetNextEntryID: longint;
  683. var ID: longint;
  684. begin
  685. if Entries^.Count=0 then ID:=1 else
  686. ID:=Entries^.At(Entries^.Count-1)^.ID+1;
  687. GetNextEntryID:=ID;
  688. end;
  689. destructor TResourceFile.Done;
  690. begin
  691. Flush;
  692. inherited Done;
  693. { if assigned(S) then dispose(S,Done); S:=nil;}
  694. if Resources<>nil then Dispose(Resources, Done); Resources:=nil;
  695. if Entries<>nil then
  696. begin Entries^.DeleteAll; Dispose(Entries, Done); Entries:=nil; end;
  697. if MyStream and Assigned(S) then
  698. Dispose(S, Done);
  699. end;
  700. constructor TResourceFile.CreateFile(AFileName: string);
  701. var B: PFastBufStream;
  702. begin
  703. New(B, Init(AFileName, stCreate, 4096));
  704. if (B<>nil) and (B^.Status<>stOK) then
  705. begin Dispose(B, Done); B:=nil; end;
  706. if B=nil then Fail;
  707. if Create(B^)=false then
  708. Begin
  709. Dispose(B,Done);
  710. Fail;
  711. End;
  712. MyStream:=true;
  713. end;
  714. constructor TResourceFile.LoadFile(AFileName: string);
  715. var B: PFastBufStream;
  716. begin
  717. New(B, Init(AFileName, stOpen, 4096));
  718. if (B<>nil) and (B^.Status<>stOK) then
  719. begin Dispose(B, Done); B:=nil; end;
  720. if B=nil then Fail;
  721. if Load(B^)=false then
  722. Begin
  723. Dispose(B,Done);
  724. Fail;
  725. End;
  726. MyStream:=true;
  727. end;
  728. END.
  729. {
  730. $Log$
  731. Revision 1.2 2002-09-07 15:40:50 peter
  732. * old logs removed and tabs fixed
  733. }