extres_multiarch.inc 21 KB

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