{ This file is part of the Free Pascal run time library. Copyright (c) 2008 by Giulio Bernardi Resource support for non-PECOFF targets (ELF, Mach-O) See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} const {$if defined(CPUWASM)} { Since WebAssembly is a Harvard architecture, the code is invisible in linear memory and the data section starts at address 0. Resources reside after the initialized data section, just before the bss (uninitialized data) section, therefore it's perfectly possible that their data exist on a relatively low address (less than 64KB). So, for WebAssembly we check whether the pointer resides in the first 4KB of linear memory, instead of the first 64KB. Note that the first 4KB of linear memory in WebAssembly aren't used by Free Pascal. } MaxIntResource=4095; {$else} MaxIntResource=65535; {$endif} type PResInfoNode = ^TResInfoNode; TResInfoNode = packed record nameid : PAnsiChar; //name / integer ID / languageID ncounthandle : longword; //named sub-entries count / resource handle idcountsize : longword; //id sub-entries count / resource size subptr : PResInfoNode; //first sub-entry pointer end; TResHdr = packed record rootptr : PResInfoNode; //pointer to root node count : longword; //number of resources in the file usedhandles : longword; //last resource handle used handles : PPtrUint; //pointer to handles end; PResHdr = ^TResHdr; PPResHdr = ^PResHdr; TLibGetResHdr=function():PResHdr; var {$ifdef FPC_HAS_WINLIKERESOURCES} {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION} ResHeader : PPResHdr; external name '_FPC_ResLocation'; {$else} ResHeaderVar: PResHdr; external name 'FPC_RESLOCATION'; ResHeader : PPResHdr = @ResHeaderVar; {$endif} {$else} ResHeaderVar : PResHdr = nil; ResHeader : PPResHdr= @ResHeaderVar; {$endif} (***************************************************************************** Private Helper Functions *****************************************************************************) function ExtGetResHdr(ModuleHandle : TFPResourceHMODULE):PResHdr; var p:TLibGetResHdr; pp:pointer; begin ExtGetResHdr:=nil; if ModuleHandle=0 then ExtGetResHdr:=ResHeader^ // internal else begin // 1-st way to get resource location p:=TLibGetResHdr(GetProcAddress(ModuleHandle,'rsrc')); if p<>nil then // there is public ExtGetResHdr:=p(); if ExtGetResHdr=nil then // try another way begin // 2-nd way to get resource location pp:=GetProcAddress(ModuleHandle,'FPC_RESLOCATION'); if pp<>nil then ExtGetResHdr:=PResHDR(pp^); end; end; end; //resource functions are case insensitive... copied from genstr.inc function ResStrIComp(Str1, Str2 : PAnsiChar): SizeInt; var counter: SizeInt; c1, c2: AnsiChar; begin counter := 0; c1 := upcase(str1[counter]); c2 := upcase(str2[counter]); while c1 = c2 do begin if (c1 = #0) or (c2 = #0) then break; inc(counter); c1 := upcase(str1[counter]); c2 := upcase(str2[counter]); end; ResStrIComp := ord(c1) - ord(c2); end; {!fixme!} //function InternalIsIntResource(aStr : PAnsiChar; out aInt : PtrUint) : boolean; function InternalIsIntResource(aStr : pansichar; var aInt : PtrUint) : boolean; var i : integer; s : shortstring; code : word; begin InternalIsIntResource:=PtrUInt(aStr)<=MaxIntResource; if InternalIsIntResource then aInt:=PtrUInt(aStr) else begin //a string like #number specifies an integer id if aStr[0]='#' then begin i:=1; while aStr[i]<>#0 do inc(i); if i>256 then i:=256; s[0]:=chr(i-1); Move(aStr[1],s[1],i-1); Val(s,aInt,code); InternalIsIntResource:=code=0; end; end; end; function BinSearchStr(arr : PResInfoNode; query : pansichar; left, right : integer) : PResInfoNode; var pivot, res : integer; resstr : pansichar; begin BinSearchStr:=nil; while left<=right do begin pivot:=(left+right) div 2; resstr:=arr[pivot].nameid; res:=ResStrIComp(resstr,query); if res<0 then left:=pivot+1 else if res>0 then right:=pivot-1 else begin BinSearchStr:=@arr[pivot]; exit; end; end; end; function BinSearchInt(arr : PResInfoNode; query : pansichar; left, right : integer) : PResInfoNode; var pivot : integer; begin BinSearchInt:=nil; while left<=right do begin pivot:=(left+right) div 2; if PtrUint(arr[pivot].nameid)PtrUInt(query) then right:=pivot-1 else begin BinSearchInt:=@arr[pivot]; exit; end; end; end; function BinSearchRes(root : PResInfoNode; aDesc : PAnsiChar) : PResInfoNode; var aID : PtrUint; begin if InternalIsIntResource(aDesc,aID) then BinSearchRes:=BinSearchInt(root^.subptr,PAnsiChar(aID),root^.ncounthandle, root^.ncounthandle+root^.idcountsize-1) else BinSearchRes:=BinSearchStr(root^.subptr,aDesc,0,root^.ncounthandle-1); end; //Returns a pointer to a name node. function InternalFindResource(ResHdr:PResHdr;ResourceName, ResourceType: PAnsiChar): PResInfoNode; begin InternalFindResource:=nil; if ResHdr=nil then exit; InternalFindResource:=ResHdr^.rootptr; InternalFindResource:=BinSearchRes(InternalFindResource,ResourceType); if InternalFindResource<>nil then InternalFindResource:=BinSearchRes(InternalFindResource,ResourceName); end; function FindSubLanguage(aPtr : PResInfoNode; aLangID : word; aMask: word) : PResInfoNode; var arr : PResInfoNode; i : longword; begin FindSubLanguage:=nil; arr:=aPtr^.subptr; i:=0; while ires_hdr^.usedhandles) then exit; IntLoadResource:=TFPResourceHGLOBAL(PResInfoNode(res_hdr^.handles[ResHandle-1])^.subptr); end; Function IntSizeofResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): LongWord; var res_hdr: PResHdr; begin IntSizeofResource:=0; res_hdr:=ExtGetResHdr(ModuleHandle); if res_hdr=nil then exit; if (ResHandle<=0) or (ResHandle>res_hdr^.usedhandles) then exit; IntSizeofResource:=PResInfoNode(res_hdr^.handles[ResHandle-1])^.idcountsize; end; Function IntLockResource(ResData: TFPResourceHGLOBAL): Pointer; begin IntLockResource:=Nil; if ResHeader^=nil then exit; IntLockResource:=Pointer(ResData); end; Function IntUnlockResource(ResData: TFPResourceHGLOBAL): LongBool; begin IntUnlockResource:=(ResHeader^<>nil); end; Function IntFreeResource(ResData: TFPResourceHGLOBAL): LongBool; begin IntFreeResource:=(ResHeader^<>nil); end; const InternalResourceManager : TResourceManager = ( HINSTANCEFunc : @IntHINSTANCE; EnumResourceTypesFunc : @IntEnumResourceTypes; EnumResourceNamesFunc : @IntEnumResourceNames; EnumResourceLanguagesFunc : @IntEnumResourceLanguages; FindResourceFunc : @IntFindResource; FindResourceExFunc : @IntFindResourceEx; LoadResourceFunc : @IntLoadResource; SizeofResourceFunc : @IntSizeofResource; LockResourceFunc : @IntLockResource; UnlockResourceFunc : @IntUnlockResource; FreeResourceFunc : @IntFreeResource; );