groupresource.pp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Base classes for group cursor and group icon resource types
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit groupresource;
  12. {$MODE OBJFPC}
  13. interface
  14. uses
  15. Classes, SysUtils, resource, resdatastream;
  16. type
  17. { TGroupResource }
  18. TGroupResource = class(TAbstractResource)
  19. protected
  20. fType : TResourceDesc;
  21. fName : TResourceDesc;
  22. fItemData : TStream;
  23. fItemList : TFPList;
  24. dummyType : TResourceDesc;
  25. dummyName : TResourceDesc;
  26. procedure FindSubResources;
  27. procedure ReadResourceItemHeader; virtual; abstract;
  28. procedure CheckBuildItemStream;
  29. function GetItemData : TStream;
  30. procedure WriteHeader(aStream : TStream); virtual; abstract;
  31. function WriteResHeader : word;
  32. procedure CreateSubItems;
  33. procedure CreateSubItem; virtual; abstract;
  34. procedure UpdateItemOwner(index : integer); virtual; abstract;
  35. procedure ClearItemList; virtual; abstract;
  36. procedure DeleteSubItems; virtual; abstract;
  37. function GetSubStreamCount : integer;
  38. function GetSubStream(const index : integer; out aSize : int64) : TStream; virtual; abstract;
  39. procedure SetOwnerList(aResources : TResources); override;
  40. procedure NotifyResourcesLoaded; override;
  41. public
  42. destructor Destroy; override;
  43. function CompareContents(aResource: TAbstractResource): boolean; override;
  44. procedure SetCustomItemDataStream(aStream : TStream);
  45. procedure UpdateRawData; override;
  46. property ItemData : TStream read GetItemData;
  47. end;
  48. { TGroupCachedDataStream }
  49. TGroupCachedDataStream = class(TCachedDataStream)
  50. private
  51. fHeader : TMemoryStream;
  52. fStreams : TFPList;
  53. function ReadFromSubStream(aStream : TStream; var Buffer; aPosition : int64; aCount : longint) : longint;
  54. protected
  55. public
  56. constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64); override;
  57. destructor Destroy; override;
  58. function Read(var Buffer; Count: Longint): Longint; override;
  59. end;
  60. implementation
  61. uses
  62. icocurtypes;
  63. { TGroupResource }
  64. procedure TGroupResource.FindSubResources;
  65. var nh : TNewHeader;
  66. i : integer;
  67. begin
  68. if fItemList<>nil then exit;
  69. fItemList:=TFPList.Create;
  70. //read NewHeader from resource
  71. RawData.Position:=0;
  72. try
  73. RawData.ReadBuffer(nh,sizeof(nh));
  74. except
  75. on e : EReadError do exit; //empty stream
  76. end;
  77. {$IFDEF ENDIAN_BIG}
  78. nh.reserved:=SwapEndian(nh.reserved);
  79. nh.restype:=SwapEndian(nh.restype);
  80. nh.rescount:=SwapEndian(nh.rescount);
  81. {$ENDIF}
  82. for i:=1 to nh.rescount do
  83. ReadResourceItemHeader;
  84. end;
  85. procedure TGroupResource.CheckBuildItemStream;
  86. begin
  87. if fItemData<>nil then exit;
  88. FindSubResources;
  89. fItemData:=TResourceDataStream.Create(RawData,self,DataSize,TGroupCachedDataStream);
  90. end;
  91. function TGroupResource.GetItemData: TStream;
  92. begin
  93. CheckBuildItemStream;
  94. Result:=fItemData;
  95. end;
  96. function TGroupResource.WriteResHeader: word;
  97. var nh : TNewHeader;
  98. begin
  99. //copy RES header from the ICO/CUR one (they are identical)
  100. ItemData.Position:=0;
  101. ItemData.ReadBuffer(nh,sizeof(nh));
  102. RawData.Size:=0;
  103. RawData.Position:=0;
  104. RawData.WriteBuffer(nh,sizeof(nh));
  105. Result:=nh.rescount;
  106. {$IFDEF ENDIAN_BIG}
  107. Result:=SwapEndian(Result);
  108. {$ENDIF}
  109. end;
  110. procedure TGroupResource.CreateSubItems;
  111. var itemcount : word;
  112. i : integer;
  113. begin
  114. if fItemList=nil then fItemList:=TFPList.Create;
  115. itemcount:=WriteResHeader;
  116. for i:=1 to itemcount do
  117. CreateSubItem;
  118. end;
  119. function TGroupResource.GetSubStreamCount: integer;
  120. begin
  121. Result:=fItemList.Count;
  122. end;
  123. procedure TGroupResource.SetOwnerList(aResources: TResources);
  124. var i : integer;
  125. begin
  126. inherited SetOwnerList(aResources);
  127. if fItemList=nil then exit;
  128. for i:=0 to fItemList.Count-1 do
  129. UpdateItemOwner(i);
  130. end;
  131. procedure TGroupResource.NotifyResourcesLoaded;
  132. begin
  133. //all resources have been loaded, so find all sub resources and tell them
  134. //we are the owners
  135. FindSubResources;
  136. end;
  137. destructor TGroupResource.Destroy;
  138. begin
  139. if fItemData<>nil then fItemData.Free;
  140. ClearItemList;
  141. fItemList.Free;
  142. fType.Free;
  143. fName.Free;
  144. dummyType.Free;
  145. dummyName.Free;
  146. inherited Destroy;
  147. end;
  148. function TGroupResource.CompareContents(aResource: TAbstractResource): boolean;
  149. begin
  150. if aResource is TGroupResource then
  151. Result:=TResourceDataStream(ItemData).Compare(TGroupResource(aResource).ItemData)
  152. else
  153. Result:=inherited CompareContents(aResource);
  154. end;
  155. procedure TGroupResource.SetCustomItemDataStream(aStream: TStream);
  156. begin
  157. TResourceDataStream(ItemData).SetCustomStream(aStream);
  158. end;
  159. procedure TGroupResource.UpdateRawData;
  160. begin
  161. if (fItemData=nil) or TResourceDataStream(ItemData).Cached then exit; //no need to update rawdata
  162. DeleteSubItems;
  163. CreateSubItems;
  164. FreeAndNil(fItemData);
  165. end;
  166. { TGroupCachedDataStream }
  167. function TGroupCachedDataStream.ReadFromSubStream(aStream: TStream;
  168. var Buffer; aPosition: int64; aCount: longint): longint;
  169. var oldpos : int64;
  170. begin
  171. Result:=aStream.Size-aPosition;
  172. if aCount<Result then Result:=aCount;
  173. if Result<0 then Result:=0;
  174. oldpos:=aStream.Position;
  175. aStream.Position:=aPosition;
  176. Result:=aStream.Read(Buffer,Result);
  177. aStream.Position:=oldpos;
  178. end;
  179. constructor TGroupCachedDataStream.Create(aStream: TStream; aResource : TAbstractResource; aSize: int64);
  180. var i, strcount : integer;
  181. tmpstr : TStream;
  182. begin
  183. inherited Create(aStream,aResource,aSize);
  184. fHeader:=TMemoryStream.Create;
  185. fStreams:=TFPList.Create;
  186. TGroupResource(aResource).WriteHeader(fHeader);
  187. strcount:=TGroupResource(aResource).GetSubStreamCount;
  188. fSize:=fHeader.Size;
  189. for i:=0 to strcount-1 do
  190. begin
  191. tmpstr:=TGroupResource(aResource).GetSubStream(i,aSize);
  192. tmpstr:=TCachedResourceDataStream.Create(tmpstr,aResource,aSize);
  193. fStreams.Add(tmpstr);
  194. inc(fSize,aSize);
  195. end;
  196. end;
  197. destructor TGroupCachedDataStream.Destroy;
  198. var i : integer;
  199. begin
  200. for i:=0 to fStreams.Count-1 do
  201. TStream(fStreams[i]).Free; //free the cached streams
  202. fStreams.Free;
  203. fHeader.Free;
  204. end;
  205. function TGroupCachedDataStream.Read(var Buffer; Count: Longint): Longint;
  206. var toread,read_in,delta : longint;
  207. b : pbyte;
  208. i : integer;
  209. begin
  210. Result:=0;
  211. toread:=fSize-Position;
  212. if Count<toread then toread:=Count;
  213. if toread<0 then toread:=0;
  214. b:=@buffer;
  215. read_in:=ReadFromSubStream(fHeader,b^,fPosition,toread);
  216. inc(fPosition,read_in);
  217. inc(b,read_in);
  218. inc(Result,read_in);
  219. dec(toread,read_in);
  220. delta:=fHeader.Size;
  221. for i:=0 to fStreams.Count-1 do
  222. begin
  223. if toread<=0 then exit;
  224. read_in:=ReadFromSubStream(TStream(fStreams[i]),b^,fPosition-delta,toread);
  225. inc(fPosition,read_in);
  226. inc(b,read_in);
  227. inc(Result,read_in);
  228. dec(toread,read_in);
  229. inc(delta,TStream(fStreams[i]).Size);
  230. end;
  231. end;
  232. end.