intres.inc 12 KB

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