unit Windows_Resource; {$INCLUDE clinksettings.inc} {$ASSERTIONS ON} interface uses type_fixes, classes; function ParseHeader(aInputStream : TStream; out vWIN16AlignmentShiftCount : TUINT16) : IInterfaceList { of IResourceTypeBlock }; implementation uses data, lowlevel_data; procedure ensure(a : TBoolean); begin if not a then raise EReadError.Create('could not understand the file format'); end; function ParseHeader(aInputStream : TStream; out vWIN16AlignmentShiftCount : TUINT16) : IInterfaceList { of IResourceTypeBlock }; var vMSDOSHeader : TMSDOSHeader; vPEMagic : TPEMagic; vOS2Header : TOS2Header; //vCOFFRVAs : array of TCOFFOptionalHeaderRVAEntry; vWIN16ResourceTypeInformation : TWIN16ResourceTypeInformation; vWIN16ResourceInformation : TWIN16ResourceInformation; i : TUINT16; vResourceTypeInfos : IInterfaceList; // array of IResourceTypeBlock; vStringLength : TByte; vName : ShortString; j : TUINT16; vResourceTypeInfo : IResourceTypeBlock; vNameOffset : TUINT16; vResourceInfo : IResourceBlock; begin aInputStream.ReadBuffer(vMSDOSHeader, Sizeof(vMSDOSHeader)); assert(Sizeof(vMSDosHeader) = 64); ensure(vMSDOSHeader.Signature = $5a4d); aInputStream.Seek(vMSDOSHeader.PEHeaderPosition, soBeginning); assert(Sizeof(vPEMagic) = 4); aInputStream.ReadBuffer(vPEMagic, Sizeof(vPEMagic)); ensure(vPEMagic.Magic = $454E); { "NE" (OS/2, DOS 4.0, old Windows 3.1). } ensure(vPEMagic.MajorVersion = 5); ensure(vPEMagic.MinorVersion in [1, 60]); assert(Sizeof(vOS2Header) = 64 - {magic} 4); aInputStream.ReadBuffer(vOS2Header, Sizeof(vOS2Header)); ensure(vOS2Header.ResourceTableOffset >= 64); //Writeln(vOS2Header.ResourceEntryCount); 0 ... aInputStream.Seek(vMSDOSHeader.PEHeaderPosition + vOS2Header.ResourceTableOffset, soBeginning); aInputStream.ReadBuffer(vWIN16AlignmentShiftCount, Sizeof(vWIN16AlignmentShiftCount)); vResourceTypeInfos := TInterfaceList.Create; repeat aInputStream.ReadBuffer(vWIN16ResourceTypeInformation, Sizeof(vWIN16ResourceTypeInformation)); if vWIN16ResourceTypeInformation.TypeID = 0 then Break; vResourceTypeInfo := TResourceTypeBlock.Create(vWIN16ResourceTypeInformation); vResourceTypeInfos.Add(vResourceTypeInfo); for i := 1 to vWIN16ResourceTypeInformation.Count do begin aInputStream.ReadBuffer(vWIN16ResourceInformation, Sizeof(vWIN16ResourceInformation)); vResourceTypeInfo.Add(TResourceBlock.Create(vWIN16ResourceInformation)); end; until vWIN16ResourceTypeInformation.TypeID = 0; if (vResourceTypeInfos.Count > 0) then begin for i := 0 to vResourceTypeInfos.Count - 1 do begin vResourceTypeInfo := vResourceTypeInfos[i] as IResourceTypeBlock; vNameOffset := vResourceTypeInfo.NameOffset; if vNameOffset <> 0 then begin aInputStream.Seek(vMSDOSHeader.PEHeaderPosition + vOS2Header.ResourceTableOffset + vNameOffset, soBeginning); aInputStream.ReadBuffer(vStringLength, Sizeof(vStringLength)); ensure(vStringLength > 0); SetLength(vName, vStringLength); aInputStream.ReadBuffer(vName[1], vStringLength); vName[0] := Chr(vStringLength); vResourceTypeInfo.TypeID := vName; end; for j := 0 to vResourceTypeInfo.Count - 1 do begin vResourceInfo := vResourceTypeInfo.Item[j]; vNameOffset := vResourceInfo.NameOffset; if vNameOffset <> 0 then begin aInputStream.Seek(vMSDOSHeader.PEHeaderPosition + vOS2Header.ResourceTableOffset + vNameOffset, soBeginning); aInputStream.ReadBuffer(vStringLength, Sizeof(vStringLength)); ensure(vStringLength > 0); SetLength(vName, vStringLength); aInputStream.ReadBuffer(vName[1], vStringLength); vName[0] := Chr(vStringLength); vResourceInfo.ID := vName; end; end; end; end; Result := vResourceTypeInfos; end; end.