groupcursorresource.pp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Group cursor resource type
  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 groupcursorresource;
  12. {$MODE OBJFPC}
  13. interface
  14. uses
  15. Classes, SysUtils, resource, groupresource;
  16. type
  17. { TGroupCursorResource }
  18. TGroupCursorResource = class(TGroupResource)
  19. private
  20. function WriteCurCursorHeader(aStream : TStream; const index : integer; const start : longword) : longword;
  21. protected
  22. procedure ReadResourceItemHeader; override;
  23. procedure WriteHeader(aStream : TStream); override;
  24. procedure CreateSubItem; override;
  25. procedure UpdateItemOwner(index : integer); override;
  26. procedure ClearItemList; override;
  27. procedure DeleteSubItems; override;
  28. function GetSubStream(const index : integer; out aSize : int64) : TStream; override;
  29. function GetType : TResourceDesc; override;
  30. function GetName : TResourceDesc; override;
  31. function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
  32. function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
  33. public
  34. constructor Create; override;
  35. constructor Create(aType,aName : TResourceDesc); override;
  36. end;
  37. implementation
  38. uses
  39. resfactory, resdatastream, icocurtypes;
  40. type
  41. TCurInfo = record
  42. res : TAbstractResource;
  43. header : TResCursorDir;
  44. end;
  45. PCurInfo = ^TCurInfo;
  46. { TGroupCursorResource }
  47. procedure TGroupCursorResource.ReadResourceItemHeader;
  48. var pci : PCurInfo;
  49. res : TAbstractResource;
  50. cursorid : word;
  51. begin
  52. if OwnerList=nil then exit;
  53. GetMem(pci,sizeof(TCurInfo));
  54. try
  55. RawData.ReadBuffer(pci^.header,sizeof(TResCursorDir));
  56. cursorid:=pci^.header.cursorId;
  57. {$IFDEF ENDIAN_BIG}
  58. cursorId:=SwapEndian(cursorId);
  59. {$ENDIF}
  60. res:=OwnerList.Find(RT_CURSOR,cursorid,LangID);
  61. pci^.res:=res;
  62. SetChildOwner(res);
  63. fItemList.Add(pci);
  64. except
  65. FreeMem(pci);
  66. raise;
  67. end;
  68. end;
  69. function TGroupCursorResource.WriteCurCursorHeader(aStream: TStream;
  70. const index: integer; const start: longword): longword;
  71. var pci : PCurInfo;
  72. hdr : TCurCursorDir;
  73. tmpw,tmph : word;
  74. begin
  75. pci:=PCurInfo(fItemList[index]);
  76. tmpw:=pci^.header.width;
  77. tmph:=pci^.header.height;
  78. {$IFDEF ENDIAN_BIG}
  79. tmpw:=SwapEndian(tmpw);
  80. tmph:=SwapEndian(tmph);
  81. {$ENDIF}
  82. tmph:=tmph div 2; //in cursor resources, height is doubled.
  83. hdr.width:=tmpw; //it's a byte now, no need to swap
  84. hdr.height:=tmph; //it's a byte now, no need to swap
  85. hdr.reserved:=0;
  86. hdr.bytesincur:=pci^.header.bytesinres;
  87. hdr.curoffset:=start;
  88. pci^.res.RawData.Position:=0;
  89. pci^.res.RawData.ReadBuffer(hdr.xhotspot,2);
  90. pci^.res.RawData.ReadBuffer(hdr.yhotspot,2);
  91. {$IFDEF ENDIAN_BIG}
  92. hdr.curoffset:=SwapEndian(hdr.curoffset);
  93. hdr.bytesincur:=SwapEndian(hdr.bytesincur);
  94. {$ENDIF}
  95. dec(hdr.bytesincur,4); //in resources, cursor has 2 words more for hotspots
  96. {$IFDEF ENDIAN_BIG}
  97. hdr.bytesincur:=SwapEndian(hdr.bytesincur);
  98. {$ENDIF}
  99. aStream.WriteBuffer(hdr,sizeof(hdr));
  100. Result:=start+pci^.res.RawData.Size-4;
  101. end;
  102. procedure TGroupCursorResource.WriteHeader(aStream: TStream);
  103. var nh : TNewHeader;
  104. i : integer;
  105. addrcount : longword;
  106. begin
  107. //write CUR file header (identical to the resource cursor header)
  108. nh.reserved:=0;
  109. nh.restype:=RES_CURSOR;
  110. nh.rescount:=fItemList.Count;
  111. {$IFDEF ENDIAN_BIG}
  112. nh.reserved:=SwapEndian(nh.reserved);
  113. nh.restype:=SwapEndian(nh.restype);
  114. nh.rescount:=SwapEndian(nh.rescount);
  115. {$ENDIF}
  116. aStream.Position:=0;
  117. aStream.WriteBuffer(nh,sizeof(nh));
  118. addrcount:=sizeof(TNewHeader)+sizeof(TCurCursorDir)*fItemList.Count;
  119. for i:=0 to fItemList.Count-1 do
  120. addrcount:=WriteCurCursorHeader(aStream,i,addrcount);
  121. end;
  122. procedure TGroupCursorResource.ClearItemList;
  123. var pci : PCurInfo;
  124. i : integer;
  125. begin
  126. if fItemList=nil then exit;
  127. for i:=0 to fItemList.Count-1 do
  128. begin
  129. pci:=PCurInfo(fItemList[i]);
  130. //if we are not in a TResources, free all subitems by ourselves.
  131. if OwnerList=nil then pci^.res.Free;
  132. FreeMem(pci);
  133. end;
  134. fItemList.Clear;
  135. end;
  136. procedure TGroupCursorResource.DeleteSubItems;
  137. var pci : PCurInfo;
  138. i : integer;
  139. begin
  140. if fItemList=nil then exit;
  141. for i:=0 to fItemList.Count-1 do
  142. begin
  143. pci:=PCurInfo(fItemList[i]);
  144. if OwnerList<>nil then
  145. OwnerList.Remove(pci^.res);
  146. pci^.res.Free;
  147. FreeMem(pci);
  148. end;
  149. fItemList.Clear;
  150. end;
  151. procedure TGroupCursorResource.CreateSubItem;
  152. var res : TAbstractResource;
  153. pci : PCurInfo;
  154. curhdr : TCurCursorDir;
  155. oldpos : int64;
  156. bytesinres : longword;
  157. curoffset : longword;
  158. index : word;
  159. begin
  160. index:=fItemList.Count+1;
  161. dummyName.ID:=index;
  162. res:=TResourceFactory.CreateResource(dummyType,dummyName);
  163. res.LangID:=LangID;
  164. if OwnerList<>nil then
  165. index:=OwnerList.AddAutoID(res);
  166. GetMem(pci,sizeof(TCurInfo));
  167. fItemList.Add(pci);
  168. pci^.res:=res;
  169. ItemData.ReadBuffer(curhdr,sizeof(TCurCursorDir));
  170. pci^.header.width:=curhdr.width; //it was a byte, no need to swap
  171. pci^.header.height:=curhdr.height*2; //in cursor resources, height is doubled.
  172. pci^.header.planes:=1;
  173. pci^.header.bitcount:=1;
  174. pci^.header.cursorId:=index;
  175. bytesinres:=curhdr.bytesincur;
  176. curoffset:=curhdr.curoffset;
  177. {$IFDEF ENDIAN_BIG}
  178. bytesinres:=SwapEndian(bytesinres);
  179. curoffset:=SwapEndian(curoffset);
  180. {$ENDIF}
  181. oldpos:=ItemData.Position;
  182. try
  183. ItemData.Position:=curoffset;
  184. res.RawData.Size:=0;
  185. res.RawData.Position:=0;
  186. res.RawData.WriteBuffer(curhdr.xhotspot,2);
  187. res.RawData.WriteBuffer(curhdr.yhotspot,2);
  188. res.RawData.CopyFrom(ItemData,bytesinres);
  189. finally
  190. ItemData.Position:=oldpos;
  191. end;
  192. inc(bytesinres,4); //in resources, cursor has 2 words more for hotspots
  193. pci^.header.bytesinres:=bytesinres;
  194. {$IFDEF ENDIAN_BIG}
  195. pci^.header.width:=SwapEndian(pci^.header.width);
  196. pci^.header.height:=SwapEndian(pci^.header.height);
  197. pci^.header.planes:=SwapEndian(pci^.header.planes);
  198. pci^.header.bitcount:=SwapEndian(pci^.header.bitcount);
  199. pci^.header.bytesinres:=SwapEndian(pci^.header.bytesinres);
  200. pci^.header.cursorId:=SwapEndian(pci^.header.cursorId);
  201. {$ENDIF}
  202. RawData.WriteBuffer(pci^.header,sizeof(TResCursorDir));
  203. end;
  204. procedure TGroupCursorResource.UpdateItemOwner(index: integer);
  205. var pci : PCurInfo;
  206. theid : word;
  207. oldpos : int64;
  208. begin
  209. pci:=PCurInfo(fItemList[index]);
  210. if pci^.res.OwnerList=OwnerList then exit;
  211. if OwnerList=nil then
  212. begin
  213. pci^.res.OwnerList.Remove(pci^.res);
  214. exit;
  215. end;
  216. theid:=pci^.res.Name.ID;
  217. OwnerList.AddAutoID(pci^.res);
  218. if theid<>pci^.res.Name.ID then //id changed, update
  219. begin
  220. theid:=pci^.res.Name.ID;
  221. pci^.header.cursorId:=theid; //update header id value
  222. {$IFDEF ENDIAN_BIG}
  223. pci^.header.cursorId:=SwapEndian(pci^.header.cursorId);
  224. {$ENDIF}
  225. //update id in rawdata (ItemStream, if present, is ok)
  226. if (fItemData=nil) or TResourceDataStream(ItemData).Cached then
  227. begin
  228. oldpos:=RawData.Position;
  229. try
  230. RawData.Position:=sizeof(TNewHeader)+(index+1)*sizeof(TResCursorDir)-2;
  231. RawData.WriteBuffer(pci^.header.cursorId,2);
  232. finally
  233. RawData.Position:=oldpos;
  234. end;
  235. end;
  236. end;
  237. end;
  238. function TGroupCursorResource.GetSubStream(const index: integer; out aSize : int64): TStream;
  239. begin
  240. Result:=PCurInfo(fItemList[index])^.res.RawData;
  241. Result.Position:=4;
  242. aSize:=Result.Size-4;
  243. end;
  244. function TGroupCursorResource.GetType: TResourceDesc;
  245. begin
  246. Result:=fType;
  247. end;
  248. function TGroupCursorResource.GetName: TResourceDesc;
  249. begin
  250. Result:=fName;
  251. end;
  252. function TGroupCursorResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
  253. ): boolean;
  254. begin
  255. Result:=aDesc=fName;
  256. end;
  257. function TGroupCursorResource.ChangeDescValueAllowed(aDesc: TResourceDesc
  258. ): boolean;
  259. begin
  260. Result:=aDesc=fName;
  261. end;
  262. constructor TGroupCursorResource.Create;
  263. begin
  264. inherited Create;
  265. fItemList:=nil;
  266. fItemData:=nil;
  267. fType:=TResourceDesc.Create(RT_GROUP_CURSOR);
  268. fName:=TResourceDesc.Create(1);
  269. SetDescOwner(fType);
  270. SetDescOwner(fName);
  271. dummyType:=TResourceDesc.Create(RT_CURSOR);
  272. dummyName:=TResourceDesc.Create(1);
  273. end;
  274. constructor TGroupCursorResource.Create(aType, aName: TResourceDesc);
  275. begin
  276. Create;
  277. fName.Assign(aName);
  278. end;
  279. initialization
  280. TResourceFactory.RegisterResourceClass(RT_GROUP_CURSOR,TGroupCursorResource);
  281. end.