extres_multiarch.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource support as external files, for Mac OS X
  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. {
  12. This file is similar to extres.inc when EXTRES_MMAP is defined.
  13. However, two files are searched (an architecture-dependent one and a shared
  14. one). They are searched first in Contents/Resources directory of the program
  15. application bundle and then in the same directory of the program.
  16. }
  17. const
  18. FPCRES_MAGIC = 'FPCRES';
  19. FPCRES_VERSION = 1;
  20. {$IFDEF ENDIAN_BIG}
  21. FPCRES_ENDIAN = 1;
  22. {$ENDIF}
  23. {$IFDEF ENDIAN_LITTLE}
  24. FPCRES_ENDIAN = 2;
  25. {$ENDIF}
  26. FPCRES_EXT = '.fpcres';
  27. FPCRES_ARCH =
  28. {$if defined(cpui386)}
  29. '.i386';
  30. {$elseif defined(cpux86_64)}
  31. '.x86_64';
  32. {$elseif defined(cpupowerpc32)}
  33. '.powerpc';
  34. {$elseif defined(cpupowerpc64)}
  35. '.powerpc64';
  36. {$elseif defined(cpuarm)}
  37. '.arm';
  38. {$elseif defined(cpuaarch64)}
  39. '.aarch64';
  40. {$else}
  41. {$error add support for cpu architecture}
  42. {$endif}
  43. type
  44. TExtHeader = packed record
  45. magic : array[0..5] of char;//'FPCRES'
  46. version : byte; //EXT_CURRENT_VERSION
  47. endianess : byte; //EXT_ENDIAN_BIG or EXT_ENDIAN_LITTLE
  48. count : longword; //resource count
  49. nodesize : longword; //size of header (up to string table, excluded)
  50. hdrsize : longword; //size of header (up to string table, included)
  51. reserved1 : longword;
  52. reserved2 : longword;
  53. reserved3 : longword;
  54. end;
  55. PExtHeader = ^TExtHeader;
  56. TResInfoNode = packed record
  57. nameid : longword; //name offset / integer ID / languageID
  58. ncounthandle : longword; //named sub-entries count/resource handle
  59. idcountsize : longword; //id sub-entries count / resource size
  60. subptr : longword; //first sub-entry offset
  61. end;
  62. PResInfoNode = ^TResInfoNode;
  63. TResFileInfo = record
  64. ResHeader : PExtHeader;
  65. fd : integer;
  66. size : longword;
  67. end;
  68. var
  69. ResFileInfo : TResFileInfo = (ResHeader : nil; fd : 0; size : 0);
  70. ResFileInfoArch : TResFileInfo = (ResHeader : nil; fd : 0; size : 0);
  71. reshandles : PPointer = nil;
  72. usedhandles : longword = 0;
  73. rescount : longword = 0;
  74. (*****************************************************************************
  75. Private Helper Functions
  76. *****************************************************************************)
  77. //resource functions are case insensitive... copied from genstr.inc
  78. function ResStrIComp(Str1, Str2 : PChar): SizeInt;
  79. var
  80. counter: SizeInt;
  81. c1, c2: char;
  82. begin
  83. counter := 0;
  84. c1 := upcase(str1[counter]);
  85. c2 := upcase(str2[counter]);
  86. while c1 = c2 do
  87. begin
  88. if (c1 = #0) or (c2 = #0) then break;
  89. inc(counter);
  90. c1 := upcase(str1[counter]);
  91. c2 := upcase(str2[counter]);
  92. end;
  93. ResStrIComp := ord(c1) - ord(c2);
  94. end;
  95. {!fixme!}
  96. //function InternalIsIntResource(aStr : pchar; out aInt : PtrUint) : boolean;
  97. function InternalIsIntResource(aStr : pchar; var aInt : PtrUint) : boolean;
  98. var i : integer;
  99. s : shortstring;
  100. code : word;
  101. begin
  102. InternalIsIntResource:=((PtrUInt(aStr) shr 16)=0);
  103. if InternalIsIntResource then aInt:=PtrUInt(aStr)
  104. else
  105. begin
  106. //a string like #number specifies an integer id
  107. if aStr[0]='#' then
  108. begin
  109. i:=1;
  110. while aStr[i]<>#0 do
  111. inc(i);
  112. if i>256 then i:=256;
  113. s[0]:=chr(i-1);
  114. Move(aStr[1],s[1],i-1);
  115. Val(s,aInt,code);
  116. InternalIsIntResource:=code=0;
  117. end;
  118. end;
  119. end;
  120. function GetResInfoPtr(base : PExtHeader; const offset : longword) : PResInfoNode; inline;
  121. begin
  122. GetResInfoPtr:=PResInfoNode(PtrUInt(base)+offset);
  123. end;
  124. function GetPchar(base : PExtHeader; const offset : longword) : Pchar; inline;
  125. begin
  126. GetPchar:=Pchar(PtrUInt(base)+offset);
  127. end;
  128. function GetPtr(base : PExtHeader; const offset : longword) : Pointer; inline;
  129. begin
  130. GetPtr:=Pointer(PtrUInt(base)+offset);
  131. end;
  132. procedure FixResEndian(ResHeader : PExtHeader);
  133. var ptr : plongword;
  134. blockend : plongword;
  135. begin
  136. //all info nodes reside in a contiguos block of memory.
  137. //they are all 16 bytes long and made by longwords
  138. //so, simply swap each longword in the block
  139. ptr:=GetPtr(ResHeader,sizeof(TExtHeader));
  140. blockend:=GetPtr(ResHeader,ResHeader^.nodesize);
  141. while ptr<blockend do
  142. begin
  143. ptr^:=SwapEndian(ptr^);
  144. inc(ptr);
  145. end;
  146. end;
  147. function GetExtResBasePath : shortstring;
  148. var exename : shortstring;
  149. len, i, extpos, namepos: integer;
  150. begin
  151. GetExtResBasePath:=paramstr(0);
  152. len:=byte(GetExtResBasePath[0]);
  153. i:=len;
  154. // writeln('exe name is ',GetExtResBasePath);
  155. //find position of extension
  156. while (i>0) and (not (GetExtResBasePath[i] in ['.',DirectorySeparator])) do
  157. dec(i);
  158. //find position of last directory separator
  159. if (i>0) and (GetExtResBasePath[i]='.') then extpos:=i-1
  160. else extpos:=len;
  161. while (i>0) and (GetExtResBasePath[i] <> DirectorySeparator) do
  162. dec(i);
  163. namepos:=i;
  164. exename:=copy(GetExtResBasePath,i+1,extpos-i);
  165. dec(i);
  166. //is executable in 'MacOS' directory? find previous dir separator...
  167. while (i>0) and (GetExtResBasePath[i] <> DirectorySeparator) do
  168. dec(i);
  169. if i<0 then i:=0;
  170. //yes, search file in <bundle>/Contents/Resources directory
  171. if (namepos>i) and (copy(GetExtResBasePath,i+1,namepos-i-1)='MacOS') then
  172. begin
  173. GetExtResBasePath[0]:=Chr(i);
  174. GetExtResBasePath:=GetExtResBasePath+'Resources'+DirectorySeparator+exename;
  175. end
  176. else //no, search file in exe directory
  177. GetExtResBasePath[0]:=Chr(extpos);
  178. // writeln('base path is ',GetExtResBasePath);
  179. end;
  180. function GetExtResPathArch(const base : shortstring) : pchar;
  181. var len : integer;
  182. begin
  183. len:=byte(base[0]);
  184. GetExtResPathArch:=GetMem(len+length(FPCRES_ARCH)+length(FPCRES_EXT)+1);
  185. Move(base[1],GetExtResPathArch[0],len);
  186. Move(FPCRES_ARCH[1],GetExtResPathArch[len],length(FPCRES_ARCH));
  187. inc(len,length(FPCRES_ARCH));
  188. Move(FPCRES_EXT[1],GetExtResPathArch[len],length(FPCRES_EXT));
  189. inc(len,length(FPCRES_EXT));
  190. GetExtResPathArch[len]:=#0;
  191. // writeln('Arch-dependent resource file is ',GetExtResPathArch);
  192. end;
  193. function GetExtResPath(const base : shortstring) : pchar;
  194. var len : integer;
  195. begin
  196. len:=byte(base[0]);
  197. GetExtResPath:=GetMem(len+length(FPCRES_EXT)+1);
  198. Move(base[1],GetExtResPath[0],len);
  199. Move(FPCRES_EXT[1],GetExtResPath[len],length(FPCRES_EXT));
  200. inc(len,length(FPCRES_EXT));
  201. GetExtResPath[len]:=#0;
  202. // writeln('Shared resource file is ',GetExtResPath);
  203. end;
  204. procedure MapResFile(var aInfo : TResFileInfo; aName : pchar);
  205. const
  206. PROT_READ = 1;
  207. PROT_WRITE = 2;
  208. var fdstat : stat;
  209. begin
  210. aInfo.fd:=FpOpen(aName,O_RDONLY,0);
  211. FreeMem(aName);
  212. // writeln('fpopen returned ',aInfo.fd);
  213. if (aInfo.fd=-1) then exit;
  214. if FpFStat(aInfo.fd,fdstat)<>0 then
  215. begin
  216. // writeln('fpfstat failed');
  217. FpClose(aInfo.fd);
  218. exit;
  219. end;
  220. // writeln('fpfstat suceeded');
  221. aInfo.size:=fdstat.st_size;
  222. aInfo.ResHeader:=PExtHeader(Fpmmap(nil,aInfo.size,PROT_READ or PROT_WRITE,
  223. MAP_PRIVATE,aInfo.fd,0));
  224. // writeln('fpmmap returned ',PtrInt(aInfo.ResHeader));
  225. if PtrInt(aInfo.ResHeader)=-1 then
  226. begin
  227. FpClose(aInfo.fd);
  228. exit;
  229. end;
  230. if (aInfo.ResHeader^.magic<>FPCRES_MAGIC) or
  231. (aInfo.ResHeader^.version<>FPCRES_VERSION) then
  232. begin
  233. FpClose(aInfo.fd);
  234. exit;
  235. end;
  236. // writeln('magic ok');
  237. if aInfo.ResHeader^.endianess<>FPCRES_ENDIAN then
  238. begin
  239. aInfo.ResHeader^.count:=SwapEndian(aInfo.ResHeader^.count);
  240. aInfo.ResHeader^.nodesize:=SwapEndian(aInfo.ResHeader^.nodesize);
  241. aInfo.ResHeader^.hdrsize:=SwapEndian(aInfo.ResHeader^.hdrsize);
  242. FixResEndian(aInfo.ResHeader);
  243. end;
  244. inc(rescount,aInfo.ResHeader^.count);
  245. end;
  246. procedure InitResources;
  247. var respathArch : pchar;
  248. respath : pchar;
  249. basepath : shortstring;
  250. begin
  251. basepath:=GetExtResBasePath;
  252. respathArch:=GetExtResPathArch(basepath);
  253. respath:=GetExtResPath(basepath);
  254. MapResFile(ResFileInfoArch,respathArch);
  255. MapResFile(ResFileInfo,respath);
  256. if rescount=0 then exit;
  257. reshandles:=GetMem(sizeof(Pointer)*rescount);
  258. FillByte(reshandles^,sizeof(Pointer)*rescount,0);
  259. end;
  260. procedure FinalizeResources;
  261. begin
  262. if (ResFileInfoArch.Resheader=nil) and (ResFileInfo.Resheader=nil) then exit;
  263. FreeMem(reshandles);
  264. if ResFileInfoArch.Resheader<>nil then
  265. begin
  266. Fpmunmap(ResFileInfoArch.ResHeader,ResFileInfoArch.size);
  267. FpClose(ResFileInfoArch.fd);
  268. end;
  269. if ResFileInfo.Resheader<>nil then
  270. begin
  271. Fpmunmap(ResFileInfo.ResHeader,ResFileInfo.size);
  272. FpClose(ResFileInfo.fd);
  273. end;
  274. end;
  275. function BinSearchStr(base : PExtHeader; arr : PResInfoNode; query : pchar;
  276. left, right : integer) : PResInfoNode;
  277. var pivot, res : integer;
  278. resstr : pchar;
  279. begin
  280. BinSearchStr:=nil;
  281. while left<=right do
  282. begin
  283. pivot:=(left+right) div 2;
  284. resstr:=GetPchar(base,arr[pivot].nameid);
  285. res:=ResStrIComp(resstr,query);
  286. if res<0 then left:=pivot+1
  287. else if res>0 then right:=pivot-1
  288. else
  289. begin
  290. BinSearchStr:=@arr[pivot];
  291. exit;
  292. end;
  293. end;
  294. end;
  295. function BinSearchInt(arr : PResInfoNode; query : pchar; left, right : integer)
  296. : PResInfoNode;
  297. var pivot : integer;
  298. begin
  299. BinSearchInt:=nil;
  300. while left<=right do
  301. begin
  302. pivot:=(left+right) div 2;
  303. if arr[pivot].nameid<PtrUInt(query) then left:=pivot+1
  304. else if arr[pivot].nameid>PtrUInt(query) then right:=pivot-1
  305. else
  306. begin
  307. BinSearchInt:=@arr[pivot];
  308. exit;
  309. end;
  310. end;
  311. end;
  312. function BinSearchRes(base : PExtHeader; root : PResInfoNode; aDesc : PChar)
  313. : PResInfoNode;
  314. var aID : PtrUint;
  315. begin
  316. if InternalIsIntResource(aDesc,aID) then
  317. BinSearchRes:=BinSearchInt(GetResInfoPtr(base,root^.subptr),PChar(aID),
  318. root^.ncounthandle,root^.ncounthandle+root^.idcountsize-1)
  319. else
  320. BinSearchRes:=BinSearchStr(base,GetResInfoPtr(base,root^.subptr),aDesc,0,
  321. root^.ncounthandle-1);
  322. end;
  323. function FindSubLanguage(base : PExtHeader; aPtr : PResInfoNode; aLangID : word;
  324. aMask: word) : PResInfoNode;
  325. var arr : PResInfoNode;
  326. i : longword;
  327. begin
  328. FindSubLanguage:=nil;
  329. arr:=GetResInfoPtr(base,aPtr^.subptr);
  330. i:=0;
  331. while i<aPtr^.idcountsize do
  332. begin
  333. if (PtrUInt(arr[i].nameid) and aMask)=(aLangID and aMask) then
  334. begin
  335. FindSubLanguage:=@arr[i];
  336. exit;
  337. end;
  338. inc(i);
  339. end;
  340. end;
  341. //Returns a pointer to a name node.
  342. function InternalFindResource(base : PExtHeader; ResourceName, ResourceType: PChar):
  343. PResInfoNode;
  344. begin
  345. InternalFindResource:=nil;
  346. if base=nil then exit;
  347. InternalFindResource:=GetResInfoPtr(base,sizeof(TExtHeader));
  348. InternalFindResource:=BinSearchRes(base,InternalFindResource,ResourceType);
  349. if InternalFindResource<>nil then
  350. InternalFindResource:=BinSearchRes(base,InternalFindResource,ResourceName);
  351. end;
  352. function FindResourceSingleFile(ResHeader : PExtHeader; ResourceName,
  353. ResourceType: PChar) : TFPResourceHandle;
  354. var ptr : PResInfoNode;
  355. begin
  356. FindResourceSingleFile:=0;
  357. ptr:=InternalFindResource(ResHeader,ResourceName,ResourceType);
  358. if ptr=nil then exit;
  359. //first language id
  360. ptr:=GetResInfoPtr(ResHeader,ptr^.subptr);
  361. if ptr^.ncounthandle=0 then
  362. begin
  363. reshandles[usedhandles]:=ptr;
  364. inc(usedhandles);
  365. ptr^.ncounthandle:=usedhandles;
  366. end;
  367. FindResourceSingleFile:=ptr^.ncounthandle;
  368. end;
  369. {!fixme!}
  370. //function FindResourceExSingleFile(ResHeader : PExtHeader; ResourceType,
  371. // ResourceName: PChar; Language : word; out precision : integer): TFPResourceHandle;
  372. function FindResourceExSingleFile(ResHeader : PExtHeader; ResourceType,
  373. ResourceName: PChar; Language : word; var precision : integer): TFPResourceHandle;
  374. const LANG_NEUTRAL = 0;
  375. LANG_ENGLISH = 9;
  376. var nameptr,ptr : PResInfoNode;
  377. begin
  378. FindResourceExSingleFile:=0;
  379. precision:=-1;
  380. nameptr:=InternalFindResource(ResHeader,ResourceName,ResourceType);
  381. if nameptr=nil then exit;
  382. precision:=4;
  383. //try exact match
  384. ptr:=FindSubLanguage(ResHeader,nameptr,Language,$FFFF);
  385. //try primary language
  386. if ptr=nil then
  387. begin
  388. dec(precision);
  389. ptr:=FindSubLanguage(ResHeader,nameptr,Language,$3FF);
  390. end;
  391. //try language neutral
  392. if ptr=nil then
  393. begin
  394. dec(precision);
  395. ptr:=FindSubLanguage(ResHeader,nameptr,LANG_NEUTRAL,$3FF);
  396. end;
  397. //try english
  398. if ptr=nil then
  399. begin
  400. dec(precision);
  401. ptr:=FindSubLanguage(ResHeader,nameptr,LANG_ENGLISH,$3FF);
  402. end;
  403. //nothing found, return the first one
  404. if ptr=nil then
  405. begin
  406. dec(precision);
  407. ptr:=GetResInfoPtr(ResHeader,nameptr^.subptr);
  408. end;
  409. if ptr^.ncounthandle=0 then
  410. begin
  411. reshandles[usedhandles]:=ptr;
  412. inc(usedhandles);
  413. ptr^.ncounthandle:=usedhandles;
  414. end;
  415. FindResourceExSingleFile:=ptr^.ncounthandle;
  416. end;
  417. function EnumResourceTypesSingleFile(ResHeader,Other : PExtHeader; ModuleHandle
  418. : TFPResourceHMODULE; EnumFunc : EnumResTypeProc; lParam : PtrInt) : LongBool;
  419. var ptr,otarr : PResInfoNode;
  420. totn, totid, ottotn, ottotid, i : longword;
  421. pc : pchar;
  422. begin
  423. EnumResourceTypesSingleFile:=false;
  424. if ResHeader=nil then exit;
  425. ptr:=GetResInfoPtr(Resheader,sizeof(TExtHeader));
  426. totn:=ptr^.ncounthandle;
  427. totid:=totn+ptr^.idcountsize;
  428. ptr:=GetResInfoPtr(Resheader,ptr^.subptr);
  429. if Other<>nil then
  430. begin
  431. otarr:=GetResInfoPtr(Other,sizeof(TExtHeader));
  432. ottotn:=otarr^.ncounthandle;
  433. ottotid:=ottotn+otarr^.idcountsize-1;
  434. otarr:=GetResInfoPtr(Other,otarr^.subptr)
  435. end;
  436. EnumResourceTypesSingleFile:=true;
  437. i:=0;
  438. while i<totn do //named entries
  439. begin
  440. pc:=GetPChar(Resheader,ptr[i].nameid);
  441. if (Other=nil) or (BinSearchStr(Other,otarr,pc,0,ottotn-1)=nil) then
  442. if not EnumFunc(ModuleHandle,pc,lParam) then exit;
  443. inc(i);
  444. end;
  445. while i<totid do
  446. begin
  447. if (Other=nil) or (BinSearchInt(otarr,PChar(ptr[i].nameid),ottotn,ottotid)=nil) then
  448. if not EnumFunc(ModuleHandle,PChar(ptr[i].nameid),lParam) then exit;
  449. inc(i);
  450. end;
  451. end;
  452. function EnumResourceNamesSingleFile(ResHeader,Other : PExtHeader;
  453. ModuleHandle : TFPResourceHMODULE; ResourceType : PChar;
  454. EnumFunc : EnumResNameProc; lParam : PtrInt) : LongBool;
  455. var ptr,otarr : PResInfoNode;
  456. totn, totid, ottotn, ottotid, i : longword;
  457. pc : pchar;
  458. begin
  459. EnumResourceNamesSingleFile:=False;
  460. if ResHeader=nil then exit;
  461. ptr:=GetResInfoPtr(ResHeader,sizeof(TExtHeader));
  462. ptr:=BinSearchRes(ResHeader,ptr,ResourceType);
  463. if ptr=nil then exit;
  464. totn:=ptr^.ncounthandle;
  465. totid:=totn+ptr^.idcountsize;
  466. ptr:=GetResInfoPtr(ResHeader,ptr^.subptr);
  467. if Other<>nil then
  468. begin
  469. otarr:=GetResInfoPtr(Other,sizeof(TExtHeader));
  470. otarr:=BinSearchRes(Other,otarr,ResourceType);
  471. if otarr<>nil then
  472. begin
  473. ottotn:=otarr^.ncounthandle;
  474. ottotid:=ottotn+otarr^.idcountsize-1;
  475. otarr:=GetResInfoPtr(Other,otarr^.subptr)
  476. end;
  477. end
  478. else otarr:=nil;
  479. EnumResourceNamesSingleFile:=true;
  480. i:=0;
  481. while i<totn do //named entries
  482. begin
  483. pc:=GetPChar(ResHeader,ptr[i].nameid);
  484. if (otarr=nil) or (BinSearchStr(Other,otarr,pc,0,ottotn-1)=nil) then
  485. if not EnumFunc(ModuleHandle,ResourceType,pc,lParam) then exit;
  486. inc(i);
  487. end;
  488. while i<totid do
  489. begin
  490. if (otarr=nil) or (BinSearchInt(otarr,PChar(ptr[i].nameid),ottotn,ottotid)=nil) then
  491. if not EnumFunc(ModuleHandle,ResourceType,PChar(ptr[i].nameid),lParam) then exit;
  492. inc(i);
  493. end;
  494. end;
  495. function EnumResourceLanguagesSingleFile(ResHeader,Other : PExtHeader;
  496. ModuleHandle : TFPResourceHMODULE; ResourceType, ResourceName : PChar;
  497. EnumFunc : EnumResLangProc; lParam : PtrInt) : LongBool;
  498. var ptr, otarr : PResInfoNode;
  499. tot, ottot, i : integer;
  500. begin
  501. EnumResourceLanguagesSingleFile:=False;
  502. ptr:=InternalFindResource(ResHeader,ResourceName,ResourceType);
  503. if ptr=nil then exit;
  504. tot:=ptr^.idcountsize;
  505. ptr:=GetResInfoPtr(ResHeader,ptr^.subptr);
  506. if Other<>nil then
  507. begin
  508. otarr:=InternalFindResource(Other,ResourceName,ResourceType);
  509. if otarr<>nil then
  510. begin
  511. ottot:=otarr^.idcountsize-1;
  512. otarr:=GetResInfoPtr(Other,otarr^.subptr)
  513. end;
  514. end
  515. else otarr:=nil;
  516. EnumResourceLanguagesSingleFile:=true;
  517. i:=0;
  518. while i<tot do
  519. begin
  520. if (otarr=nil) or (BinSearchInt(otarr,PChar(ptr[i].nameid),0,ottot)=nil) then
  521. if not EnumFunc(ModuleHandle,ResourceType,ResourceName,PtrUInt(
  522. ptr[i].nameid),lParam) then exit;
  523. inc(i);
  524. end;
  525. end;
  526. (*****************************************************************************
  527. Public Resource Functions
  528. *****************************************************************************)
  529. function ExtHINSTANCE : TFPResourceHMODULE;
  530. begin
  531. ExtHINSTANCE:=0;
  532. end;
  533. function ExtEnumResourceTypes(ModuleHandle : TFPResourceHMODULE; EnumFunc : EnumResTypeProc; lParam : PtrInt) : LongBool;
  534. begin
  535. ExtEnumResourceTypes:=false;
  536. if EnumResourceTypesSingleFile(ResFileInfoArch.Resheader,nil,ModuleHandle,
  537. EnumFunc,lParam) then ExtEnumResourceTypes:=true;
  538. if EnumResourceTypesSingleFile(ResFileInfo.Resheader,
  539. ResFileInfoArch.Resheader,ModuleHandle,EnumFunc,lParam) then ExtEnumResourceTypes:=true;
  540. end;
  541. function ExtEnumResourceNames(ModuleHandle : TFPResourceHMODULE; ResourceType : PChar; EnumFunc : EnumResNameProc; lParam : PtrInt) : LongBool;
  542. begin
  543. ExtEnumResourceNames:=False;
  544. if EnumResourceNamesSingleFile(ResFileInfoArch.Resheader,nil,ModuleHandle,
  545. ResourceType,EnumFunc,lParam) then ExtEnumResourceNames:=true;
  546. if EnumResourceNamesSingleFile(ResFileInfo.Resheader,
  547. ResFileInfoArch.Resheader,ModuleHandle,ResourceType,EnumFunc,lParam) then ExtEnumResourceNames:=true;
  548. end;
  549. function ExtEnumResourceLanguages(ModuleHandle : TFPResourceHMODULE; ResourceType, ResourceName : PChar; EnumFunc : EnumResLangProc; lParam : PtrInt) : LongBool;
  550. begin
  551. ExtEnumResourceLanguages:=False;
  552. if EnumResourceLanguagesSingleFile(ResFileInfoArch.Resheader,nil,ModuleHandle,
  553. ResourceType,ResourceName,EnumFunc,lParam) then ExtEnumResourceLanguages:=true;
  554. if EnumResourceLanguagesSingleFile(ResFileInfo.Resheader,
  555. ResFileInfoArch.Resheader,ModuleHandle,ResourceType,ResourceName,EnumFunc,
  556. lParam) then ExtEnumResourceLanguages:=true;
  557. end;
  558. function ExtFindResource(ModuleHandle: TFPResourceHMODULE; ResourceName, ResourceType: PChar): TFPResourceHandle;
  559. begin
  560. //search for resource in architecture-dependent res file first
  561. ExtFindResource:=FindResourceSingleFile(ResFileInfoArch.ResHeader,ResourceName,ResourceType);
  562. if ExtFindResource=0 then
  563. ExtFindResource:=FindResourceSingleFile(ResFileInfo.ResHeader,ResourceName,ResourceType);
  564. end;
  565. function ExtFindResourceEx(ModuleHandle: TFPResourceHMODULE; ResourceType, ResourceName: PChar; Language : word): TFPResourceHandle;
  566. var precar, precsh : integer;
  567. handlear, handlesh : TResourceHandle;
  568. begin
  569. //architecture-dependent res file
  570. handlear:=FindResourceExSingleFile(ResFileInfoArch.ResHeader,ResourceType,
  571. ResourceName,Language,precar);
  572. //architecture-independent res file
  573. handlesh:=FindResourceExSingleFile(ResFileInfo.ResHeader,ResourceType,
  574. ResourceName,Language,precsh);
  575. //return architecture-independent resource only if its language id is closer
  576. //to the one user asked for
  577. if precsh>precar then ExtFindResourceEx:=handlesh
  578. else ExtFindResourceEx:=handlear;
  579. end;
  580. function ExtLoadResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): TFPResourceHGLOBAL;
  581. var ptr : PResInfoNode;
  582. base : PExtHeader;
  583. begin
  584. ExtLoadResource:=0;
  585. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  586. ptr:=PResInfoNode(reshandles[ResHandle-1]);
  587. base:=ResFileInfoArch.ResHeader;
  588. //if ptr isn't in architecture-dependent file memory area...
  589. if (base=nil) or (pointer(ptr)<=pointer(base))
  590. or (pointer(ptr)>=GetPtr(base,base^.hdrsize)) then
  591. base:=ResFileInfo.ResHeader;
  592. ExtLoadResource:=TFPResourceHGLOBAL(GetPtr(base,ptr^.subptr));
  593. end;
  594. function ExtSizeofResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): LongWord;
  595. begin
  596. ExtSizeofResource:=0;
  597. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  598. ExtSizeofResource:=PResInfoNode(reshandles[ResHandle-1])^.idcountsize;
  599. end;
  600. function ExtLockResource(ResData: TFPResourceHGLOBAL): Pointer;
  601. begin
  602. ExtLockResource:=Nil;
  603. if (ResFileInfoArch.Resheader=nil) and (ResFileInfo.Resheader=nil) then exit;
  604. ExtLockResource:=Pointer(ResData);
  605. end;
  606. function ExtUnlockResource(ResData: TFPResourceHGLOBAL): LongBool;
  607. begin
  608. ExtUnlockResource:=(ResFileInfoArch.Resheader<>nil) or (ResFileInfo.Resheader<>nil);
  609. end;
  610. function ExtFreeResource(ResData: TFPResourceHGLOBAL): LongBool;
  611. begin
  612. ExtFreeResource:=(ResFileInfoArch.Resheader<>nil) or (ResFileInfo.Resheader<>nil);
  613. end;
  614. const
  615. ExternalResourceManager : TResourceManager =
  616. (
  617. HINSTANCEFunc : @ExtHINSTANCE;
  618. EnumResourceTypesFunc : @ExtEnumResourceTypes;
  619. EnumResourceNamesFunc : @ExtEnumResourceNames;
  620. EnumResourceLanguagesFunc : @ExtEnumResourceLanguages;
  621. FindResourceFunc : @ExtFindResource;
  622. FindResourceExFunc : @ExtFindResourceEx;
  623. LoadResourceFunc : @ExtLoadResource;
  624. SizeofResourceFunc : @ExtSizeofResource;
  625. LockResourceFunc : @ExtLockResource;
  626. UnlockResourceFunc : @ExtUnlockResource;
  627. FreeResourceFunc : @ExtFreeResource;
  628. );