FPPS4/tools/readself/elf_nid_utils.pas

155 lines
3.3 KiB
Plaintext

unit elf_nid_utils;
{$mode ObjFPC}{$H+}
interface
uses
sha1;
function ps4_nid_hash (const name:RawByteString):QWORD;
function EncodeValue64(nVal:QWORD):RawByteString;
function DecodeValue64(strEnc:PAnsiChar;len:SizeUint;var nVal:QWORD):Boolean;
function DecodeValue16(strEnc:PAnsiChar;len:SizeUint;var nVal:WORD):Boolean;
function DecodeEncName(strEncName:PAnsiChar;var nModuleId,nLibraryId:WORD;var nNid:QWORD):Boolean;
function BaseEncName (strEncName:PAnsiChar):RawByteString;
implementation
function ps4_nid_hash(const name:RawByteString):QWORD;
const
salt:array[0..15] of Byte=($51,$8D,$64,$A6,$35,$DE,$D8,$C1,$E6,$B0,$39,$B1,$C3,$E5,$52,$30);
var
Context:TSHA1Context;
Digest:TSHA1Digest;
begin
SHA1Init(Context);
SHA1Update(Context,PChar(name)^,Length(name));
SHA1Update(Context,salt,Length(salt));
SHA1Final(Context,Digest);
Result:=PQWORD(@Digest)^;
end;
function EncodeValue64(nVal:QWORD):RawByteString;
const
nEncLenMax=11;
var
i,nIndex:Integer;
begin
SetLength(Result,nEncLenMax);
For i:=nEncLenMax downto 1 do
begin
if (i<>nEncLenMax) then
begin
nIndex:=nVal and 63;
nVal:=nVal shr 6;
end else
begin
nIndex:=(nVal and 15) shl 2;
nVal:=nVal shr 4;
end;
case nIndex of
0..25:Result[i]:=Char(nIndex+Byte('A')-0);
26..51:Result[i]:=Char(nIndex+Byte('a')-26);
52..61:Result[i]:=Char(nIndex+Byte('0')-52);
62:Result[i]:='+';
63:Result[i]:='-';
end;
end;
end;
function DecodeValue64(strEnc:PAnsiChar;len:SizeUint;var nVal:QWORD):Boolean;
const
nEncLenMax=11;
var
i,nIndex:Integer;
begin
Result:=False;
nVal:=0;
if (len>nEncLenMax) or (len=0) then Exit;
For i:=0 to len-1 do
begin
case strEnc[i] of
'A'..'Z':nIndex:=Byte(strEnc[i])-Byte('A')+0;
'a'..'z':nIndex:=Byte(strEnc[i])-Byte('a')+26;
'0'..'9':nIndex:=Byte(strEnc[i])-Byte('0')+52;
'+':nIndex:=62;
'-':nIndex:=63;
else Exit;
end;
if (i<(nEncLenMax-1)) then
begin
nVal:=nVal shl 6;
nVal:=nVal or nIndex;
end else
begin
nVal:=nVal shl 4;
nVal:=nVal or (nIndex shr 2);
end;
end;
Result:=True;
end;
function DecodeValue16(strEnc:PAnsiChar;len:SizeUint;var nVal:WORD):Boolean;
const
nEncLenMax=3;
var
i,nIndex:Integer;
begin
Result:=False;
nVal:=0;
if (len>nEncLenMax) or (len=0) then Exit;
For i:=0 to len-1 do
begin
case strEnc[i] of
'A'..'Z':nIndex:=Byte(strEnc[i])-Byte('A')+0;
'a'..'z':nIndex:=Byte(strEnc[i])-Byte('a')+26;
'0'..'9':nIndex:=Byte(strEnc[i])-Byte('0')+52;
'+':nIndex:=62;
'-':nIndex:=63;
else Exit;
end;
begin
nVal:=nVal shl 6;
nVal:=nVal or nIndex;
end;
end;
Result:=True;
end;
function DecodeEncName(strEncName:PAnsiChar;var nModuleId,nLibraryId:WORD;var nNid:QWORD):Boolean;
var
i,len:Integer;
begin
Result:=False;
len:=StrLen(strEncName);
i:=IndexByte(strEncName^,len,Byte('#'));
if (i=-1) then Exit;
if not DecodeValue64(strEncName,i,nNid) then Exit;
Inc(i);
Inc(strEncName,i);
Dec(len,i);
i:=IndexByte(strEncName^,len,Byte('#'));
if (i=-1) then Exit;
if not DecodeValue16(strEncName,i,nLibraryId) then Exit;
Inc(i);
Inc(strEncName,i);
Dec(len,i);
if not DecodeValue16(strEncName,len,nModuleId) then Exit;
Result:=True;
end;
function BaseEncName(strEncName:PAnsiChar):RawByteString;
var
i,len:Integer;
begin
Result:=strEncName;
len:=StrLen(strEncName);
i:=IndexByte(strEncName^,len,Byte('#'));
if (i=-1) then Exit;
SetLength(Result,i);
end;
end.