intres.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource support for non-PECOFF targets (ELF, Mach-O)
  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. type
  12. PResInfoNode = ^TResInfoNode;
  13. TResInfoNode = packed record
  14. nameid : PChar; //name / integer ID / languageID
  15. ncounthandle : longword; //named sub-entries count / resource handle
  16. idcountsize : longword; //id sub-entries count / resource size
  17. subptr : PResInfoNode; //first sub-entry pointer
  18. end;
  19. TResHdr = packed record
  20. rootptr : PResInfoNode; //pointer to root node
  21. count : longword; //number of resources in the file
  22. usedhandles : longword; //last resource handle used
  23. handles : PPtrUint; //pointer to handles
  24. end;
  25. PResHdr = ^TResHdr;
  26. TLibGetResHdr=function():PResHdr;
  27. var
  28. {$ifdef FPC_HAS_WINLIKERESOURCES}
  29. ResHeader : PResHdr; external name 'FPC_RESLOCATION';
  30. {$else}
  31. ResHeader : PResHdr= nil;
  32. {$endif}
  33. (*****************************************************************************
  34. Private Helper Functions
  35. *****************************************************************************)
  36. function ExtGetResHdr(ModuleHandle : TFPResourceHMODULE):PResHdr;
  37. var
  38. p:TLibGetResHdr;
  39. pp:pointer;
  40. begin
  41. ExtGetResHdr:=nil;
  42. if ModuleHandle=0 then
  43. ExtGetResHdr:=ResHeader // internal
  44. else
  45. begin
  46. // 1-st way to get resource location
  47. p:=TLibGetResHdr(GetProcAddress(ModuleHandle,'rsrc'));
  48. if p<>nil then // there is public
  49. ExtGetResHdr:=p();
  50. if ExtGetResHdr=nil then // try another way
  51. begin
  52. // 2-nd way to get resource location
  53. pp:=GetProcAddress(ModuleHandle,'FPC_RESLOCATION');
  54. if pp<>nil then
  55. ExtGetResHdr:=PResHDR(pp^);
  56. end;
  57. end;
  58. end;
  59. //resource functions are case insensitive... copied from genstr.inc
  60. function ResStrIComp(Str1, Str2 : PChar): SizeInt;
  61. var
  62. counter: SizeInt;
  63. c1, c2: char;
  64. begin
  65. counter := 0;
  66. c1 := upcase(str1[counter]);
  67. c2 := upcase(str2[counter]);
  68. while c1 = c2 do
  69. begin
  70. if (c1 = #0) or (c2 = #0) then break;
  71. inc(counter);
  72. c1 := upcase(str1[counter]);
  73. c2 := upcase(str2[counter]);
  74. end;
  75. ResStrIComp := ord(c1) - ord(c2);
  76. end;
  77. {!fixme!}
  78. //function InternalIsIntResource(aStr : pchar; out aInt : PtrUint) : boolean;
  79. function InternalIsIntResource(aStr : pchar; var aInt : PtrUint) : boolean;
  80. var i : integer;
  81. s : shortstring;
  82. code : word;
  83. begin
  84. InternalIsIntResource:=((PtrUInt(aStr) shr 16)=0);
  85. if InternalIsIntResource then aInt:=PtrUInt(aStr)
  86. else
  87. begin
  88. //a string like #number specifies an integer id
  89. if aStr[0]='#' then
  90. begin
  91. i:=1;
  92. while aStr[i]<>#0 do
  93. inc(i);
  94. if i>256 then i:=256;
  95. s[0]:=chr(i-1);
  96. Move(aStr[1],s[1],i-1);
  97. Val(s,aInt,code);
  98. InternalIsIntResource:=code=0;
  99. end;
  100. end;
  101. end;
  102. function BinSearchStr(arr : PResInfoNode; query : pchar; left, right : integer)
  103. : PResInfoNode;
  104. var pivot, res : integer;
  105. resstr : pchar;
  106. begin
  107. BinSearchStr:=nil;
  108. while left<=right do
  109. begin
  110. pivot:=(left+right) div 2;
  111. resstr:=arr[pivot].nameid;
  112. res:=ResStrIComp(resstr,query);
  113. if res<0 then left:=pivot+1
  114. else if res>0 then right:=pivot-1
  115. else
  116. begin
  117. BinSearchStr:=@arr[pivot];
  118. exit;
  119. end;
  120. end;
  121. end;
  122. function BinSearchInt(arr : PResInfoNode; query : pchar; left, right : integer)
  123. : PResInfoNode;
  124. var pivot : integer;
  125. begin
  126. BinSearchInt:=nil;
  127. while left<=right do
  128. begin
  129. pivot:=(left+right) div 2;
  130. if PtrUint(arr[pivot].nameid)<PtrUInt(query) then left:=pivot+1
  131. else if PtrUint(arr[pivot].nameid)>PtrUInt(query) then right:=pivot-1
  132. else
  133. begin
  134. BinSearchInt:=@arr[pivot];
  135. exit;
  136. end;
  137. end;
  138. end;
  139. function BinSearchRes(root : PResInfoNode; aDesc : PChar) : PResInfoNode;
  140. var aID : PtrUint;
  141. begin
  142. if InternalIsIntResource(aDesc,aID) then
  143. BinSearchRes:=BinSearchInt(root^.subptr,PChar(aID),root^.ncounthandle,
  144. root^.ncounthandle+root^.idcountsize-1)
  145. else
  146. BinSearchRes:=BinSearchStr(root^.subptr,aDesc,0,root^.ncounthandle-1);
  147. end;
  148. //Returns a pointer to a name node.
  149. function InternalFindResource(ResHdr:PResHdr;ResourceName, ResourceType: PChar):
  150. PResInfoNode;
  151. begin
  152. InternalFindResource:=nil;
  153. if ResHdr=nil then exit;
  154. InternalFindResource:=ResHdr^.rootptr;
  155. InternalFindResource:=BinSearchRes(InternalFindResource,ResourceType);
  156. if InternalFindResource<>nil then
  157. InternalFindResource:=BinSearchRes(InternalFindResource,ResourceName);
  158. end;
  159. function FindSubLanguage(aPtr : PResInfoNode; aLangID : word; aMask: word) : PResInfoNode;
  160. var arr : PResInfoNode;
  161. i : longword;
  162. begin
  163. FindSubLanguage:=nil;
  164. arr:=aPtr^.subptr;
  165. i:=0;
  166. while i<aPtr^.idcountsize do
  167. begin
  168. if (PtrUInt(arr[i].nameid) and aMask)=(aLangID and aMask) then
  169. begin
  170. FindSubLanguage:=@arr[i];
  171. exit;
  172. end;
  173. inc(i);
  174. end;
  175. end;
  176. (*****************************************************************************
  177. Public Resource Functions
  178. *****************************************************************************)
  179. Function IntHINSTANCE : TFPResourceHMODULE;
  180. begin
  181. IntHINSTANCE:=0;
  182. end;
  183. Function IntEnumResourceTypes(ModuleHandle : TFPResourceHMODULE; EnumFunc : EnumResTypeProc; lParam : PtrInt) : LongBool;
  184. var ptr : PResInfoNode;
  185. tot, i : integer;
  186. res_hdr:PResHdr;
  187. begin
  188. IntEnumResourceTypes:=False;
  189. res_hdr:=ExtGetResHdr(ModuleHandle);
  190. if res_hdr=nil then exit;
  191. tot:=res_hdr^.rootptr^.ncounthandle+res_hdr^.rootptr^.idcountsize;
  192. ptr:=res_hdr^.rootptr^.subptr;
  193. IntEnumResourceTypes:=true;
  194. i:=0;
  195. while i<tot do
  196. begin
  197. if not EnumFunc(ModuleHandle,ptr[i].nameid,lParam) then exit;
  198. inc(i);
  199. end;
  200. end;
  201. Function IntEnumResourceNames(ModuleHandle : TFPResourceHMODULE; ResourceType : PChar; EnumFunc : EnumResNameProc; lParam : PtrInt) : LongBool;
  202. var ptr : PResInfoNode;
  203. tot, i : integer;
  204. res_hdr:PResHdr;
  205. begin
  206. IntEnumResourceNames:=False;
  207. res_hdr:=ExtGetResHdr(ModuleHandle);
  208. if res_hdr=nil then exit;
  209. ptr:=res_hdr^.rootptr;
  210. ptr:=BinSearchRes(ptr,ResourceType);
  211. if ptr=nil then exit;
  212. tot:=ptr^.ncounthandle+ptr^.idcountsize;
  213. ptr:=ptr^.subptr;
  214. IntEnumResourceNames:=true;
  215. i:=0;
  216. while i<tot do
  217. begin
  218. if not EnumFunc(ModuleHandle,ResourceType,ptr[i].nameid,lParam) then exit;
  219. inc(i);
  220. end;
  221. end;
  222. Function IntEnumResourceLanguages(ModuleHandle : TFPResourceHMODULE; ResourceType, ResourceName : PChar; EnumFunc : EnumResLangProc; lParam : PtrInt) : LongBool;
  223. var ptr : PResInfoNode;
  224. tot, i : integer;
  225. res_hdr:PResHdr;
  226. begin
  227. IntEnumResourceLanguages:=False;
  228. res_hdr:=ExtGetResHdr(ModuleHandle);
  229. if res_hdr=nil then exit;
  230. ptr:=InternalFindResource(res_hdr,ResourceName,ResourceType);
  231. if ptr=nil then exit;
  232. tot:=ptr^.idcountsize;
  233. ptr:=ptr^.subptr;
  234. IntEnumResourceLanguages:=true;
  235. i:=0;
  236. while i<tot do
  237. begin
  238. if not EnumFunc(ModuleHandle,ResourceType,ResourceName,PtrUInt(ptr[i].nameid),lParam) then exit;
  239. inc(i);
  240. end;
  241. end;
  242. Function IntFindResource(ModuleHandle: TFPResourceHMODULE; ResourceName,
  243. ResourceType: PChar): TFPResourceHandle;
  244. var ptr : PResInfoNode;
  245. res_hdr: PresHdr;
  246. begin
  247. IntFindResource:=0;
  248. res_hdr:=ExtGetResHdr(ModuleHandle);
  249. if res_hdr=nil then exit;
  250. ptr:=InternalFindResource(res_hdr,ResourceName,ResourceType);
  251. if ptr=nil then exit;
  252. //first language id
  253. ptr:=ptr^.subptr;
  254. if ptr^.ncounthandle=0 then
  255. begin
  256. res_hdr^.handles[res_hdr^.usedhandles]:=PtrUint(ptr);
  257. inc(res_hdr^.usedhandles);
  258. ptr^.ncounthandle:=res_hdr^.usedhandles;
  259. end;
  260. IntFindResource:=ptr^.ncounthandle;
  261. end;
  262. Function IntFindResourceEx(ModuleHandle: TFPResourceHMODULE; ResourceType,
  263. ResourceName: PChar; Language : word): TFPResourceHandle;
  264. const LANG_NEUTRAL = 0;
  265. LANG_ENGLISH = 9;
  266. var nameptr,ptr : PResInfoNode;
  267. res_hdr: PResHdr;
  268. begin
  269. IntFindResourceEx:=0;
  270. res_hdr:=ExtGetResHdr(ModuleHandle);
  271. if res_hdr=nil then exit;
  272. nameptr:=InternalFindResource(res_hdr,ResourceName,ResourceType);
  273. if nameptr=nil then exit;
  274. //try exact match
  275. ptr:=FindSubLanguage(nameptr,Language,$FFFF);
  276. //try primary language
  277. if ptr=nil then
  278. ptr:=FindSubLanguage(nameptr,Language,$3FF);
  279. //try language neutral
  280. if ptr=nil then
  281. ptr:=FindSubLanguage(nameptr,LANG_NEUTRAL,$3FF);
  282. //try english
  283. if ptr=nil then
  284. ptr:=FindSubLanguage(nameptr,LANG_ENGLISH,$3FF);
  285. //nothing found, return the first one
  286. if ptr=nil then
  287. ptr:=nameptr^.subptr;
  288. if ptr^.ncounthandle=0 then
  289. begin
  290. res_hdr^.handles[res_hdr^.usedhandles]:=PtrUint(ptr);
  291. inc(res_hdr^.usedhandles);
  292. ptr^.ncounthandle:=res_hdr^.usedhandles;
  293. end;
  294. IntFindResourceEx:=ptr^.ncounthandle;
  295. end;
  296. Function IntLoadResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): TFPResourceHGLOBAL;
  297. var res_hdr: PResHdr;
  298. begin
  299. IntLoadResource:=0;
  300. res_hdr:=ExtGetResHdr(ModuleHandle);
  301. if res_hdr=nil then exit;
  302. if (ResHandle<=0) or (ResHandle>res_hdr^.usedhandles) then exit;
  303. IntLoadResource:=TFPResourceHGLOBAL(PResInfoNode(res_hdr^.handles[ResHandle-1])^.subptr);
  304. end;
  305. Function IntSizeofResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): LongWord;
  306. var res_hdr: PResHdr;
  307. begin
  308. IntSizeofResource:=0;
  309. res_hdr:=ExtGetResHdr(ModuleHandle);
  310. if res_hdr=nil then exit;
  311. if (ResHandle<=0) or (ResHandle>res_hdr^.usedhandles) then exit;
  312. IntSizeofResource:=PResInfoNode(res_hdr^.handles[ResHandle-1])^.idcountsize;
  313. end;
  314. Function IntLockResource(ResData: TFPResourceHGLOBAL): Pointer;
  315. begin
  316. IntLockResource:=Nil;
  317. if ResHeader=nil then exit;
  318. IntLockResource:=Pointer(ResData);
  319. end;
  320. Function IntUnlockResource(ResData: TFPResourceHGLOBAL): LongBool;
  321. begin
  322. IntUnlockResource:=(ResHeader<>nil);
  323. end;
  324. Function IntFreeResource(ResData: TFPResourceHGLOBAL): LongBool;
  325. begin
  326. IntFreeResource:=(ResHeader<>nil);
  327. end;
  328. const
  329. InternalResourceManager : TResourceManager =
  330. (
  331. HINSTANCEFunc : @IntHINSTANCE;
  332. EnumResourceTypesFunc : @IntEnumResourceTypes;
  333. EnumResourceNamesFunc : @IntEnumResourceNames;
  334. EnumResourceLanguagesFunc : @IntEnumResourceLanguages;
  335. FindResourceFunc : @IntFindResource;
  336. FindResourceExFunc : @IntFindResourceEx;
  337. LoadResourceFunc : @IntLoadResource;
  338. SizeofResourceFunc : @IntSizeofResource;
  339. LockResourceFunc : @IntLockResource;
  340. UnlockResourceFunc : @IntUnlockResource;
  341. FreeResourceFunc : @IntFreeResource;
  342. );