extres_multiarch.inc 21 KB

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