mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-23 06:19:57 +00:00
409 lines
6.8 KiB
ObjectPascal
409 lines
6.8 KiB
ObjectPascal
unit mm_adr_name;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows,
|
|
Classes,
|
|
SysUtils,
|
|
g23tree,
|
|
sys_types;
|
|
|
|
{
|
|
name node:
|
|
[
|
|
offset 12..39:28
|
|
size 12..39:28
|
|
|
|
name[32]
|
|
]
|
|
|
|
}
|
|
|
|
type
|
|
TName=array[0..31] of AnsiChar;
|
|
|
|
TNameAdrNode=packed object
|
|
private
|
|
Function GetOffset:Pointer;
|
|
Procedure SetOffset(q:Pointer);
|
|
Function GetSize:QWORD;
|
|
Procedure SetSize(q:QWORD);
|
|
public
|
|
F:bitpacked record
|
|
Offset:DWORD;
|
|
Size :DWORD;
|
|
end;
|
|
name:TName;
|
|
property Offset:Pointer read GetOffset write SetOffset;
|
|
property Size:QWORD read GetSize write SetSize;
|
|
Function cmp_merge(const n:TNameAdrNode):Boolean;
|
|
end;
|
|
|
|
type
|
|
TNamedAdrAllcCompare=object
|
|
function c(const a,b:TNameAdrNode):Integer; static;
|
|
end;
|
|
|
|
TNamedManager=class
|
|
private
|
|
type
|
|
TAllcPoolNodeSet=specialize T23treeSet<TNameAdrNode,TNamedAdrAllcCompare>;
|
|
|
|
var
|
|
Flo,Fhi:Pointer;
|
|
FMaxSize:QWORD;
|
|
|
|
FAllcSet:TAllcPoolNodeSet;
|
|
public
|
|
property lo:Pointer read Flo;
|
|
property hi:Pointer read Fhi;
|
|
|
|
Constructor Create(_lo,_hi:QWORD);
|
|
private
|
|
procedure _Insert(const key:TNameAdrNode);
|
|
Function _FetchNode_m(mode:Byte;cmp:Pointer;var R:TNameAdrNode):Boolean;
|
|
|
|
procedure _Merge(key:TNameAdrNode);
|
|
procedure _Devide(Offset:Pointer;Size:QWORD;var key:TNameAdrNode);
|
|
public
|
|
Function Mname(Offset:Pointer;Size:QWORD;pname:PChar):Integer;
|
|
Function Query(Offset:Pointer;pname:PChar):Integer;
|
|
|
|
procedure Print;
|
|
end;
|
|
|
|
implementation
|
|
|
|
const
|
|
EINVAL=22;
|
|
|
|
//
|
|
|
|
function TNamedAdrAllcCompare.c(const a,b:TNameAdrNode):Integer;
|
|
begin
|
|
//1 FOffset
|
|
Result:=Integer(a.F.Offset>b.F.Offset)-Integer(a.F.Offset<b.F.Offset);
|
|
end;
|
|
|
|
//
|
|
|
|
function Max(a,b:Pointer):Pointer; inline;
|
|
begin
|
|
if (a>b) then Result:=a else Result:=b;
|
|
end;
|
|
|
|
//
|
|
|
|
Function TNameAdrNode.GetOffset:Pointer;
|
|
begin
|
|
Result:=Pointer(QWORD(F.Offset) shl 12);
|
|
end;
|
|
|
|
Procedure TNameAdrNode.SetOffset(q:Pointer);
|
|
begin
|
|
F.Offset:=DWORD(QWORD(q) shr 12);
|
|
Assert(GetOffset=q);
|
|
end;
|
|
|
|
Function TNameAdrNode.GetSize:QWORD;
|
|
begin
|
|
Result:=QWORD(F.Size) shl 12;
|
|
end;
|
|
|
|
Procedure TNameAdrNode.SetSize(q:QWORD);
|
|
begin
|
|
F.Size:=DWORD(q shr 12);
|
|
Assert(GetSize=q);
|
|
end;
|
|
|
|
Function TNameAdrNode.cmp_merge(const n:TNameAdrNode):Boolean;
|
|
begin
|
|
Result:=False;
|
|
if (CompareChar0(name,n.name,SizeOf(TName))<>0) then Exit;
|
|
Result:=True;
|
|
end;
|
|
|
|
///
|
|
|
|
Constructor TNamedManager.Create(_lo,_hi:QWORD);
|
|
var
|
|
key:TNameAdrNode;
|
|
begin
|
|
Assert(_lo<_hi);
|
|
|
|
Flo:=Pointer(_lo);
|
|
Fhi:=Pointer(_hi);
|
|
|
|
FMaxSize:=(_hi-_lo+1);
|
|
|
|
key:=Default(TNameAdrNode);
|
|
key.Offset:=Pointer(_lo);
|
|
key.Size :=FMaxSize;
|
|
|
|
_Insert(key);
|
|
end;
|
|
|
|
procedure TNamedManager._Insert(const key:TNameAdrNode);
|
|
begin
|
|
Assert(key.Size<>0);
|
|
FAllcSet.Insert(key);
|
|
end;
|
|
|
|
const
|
|
M_LE=0;
|
|
M_BE=1;
|
|
|
|
C_UP=2;
|
|
C_DW=4;
|
|
|
|
C_LE=6;
|
|
C_BE=8;
|
|
|
|
Function TNamedManager._FetchNode_m(mode:Byte;cmp:Pointer;var R:TNameAdrNode):Boolean;
|
|
var
|
|
It:TAllcPoolNodeSet.Iterator;
|
|
key,rkey:TNameAdrNode;
|
|
begin
|
|
Result:=false;
|
|
|
|
key:=R;
|
|
|
|
Case (mode and 1) of
|
|
M_LE:It:=FAllcSet.find_le(key);
|
|
M_BE:It:=FAllcSet.find_be(key);
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
if (It.Item=nil) then Exit;
|
|
|
|
rkey:=It.Item^;
|
|
|
|
Case (mode and (not 1)) of
|
|
C_UP:
|
|
begin
|
|
if not rkey.cmp_merge(key) then Exit;
|
|
if ((rkey.Offset+rkey.Size)<>cmp) then Exit;
|
|
end;
|
|
C_DW:
|
|
begin
|
|
if not rkey.cmp_merge(key) then Exit;
|
|
if (rkey.Offset <>cmp ) then Exit;
|
|
end;
|
|
|
|
C_LE:if ((rkey.Offset+rkey.Size)<=cmp) then Exit;
|
|
C_BE:if (rkey.Offset>=cmp) then Exit;
|
|
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
R:=rkey;
|
|
FAllcSet.erase(It);
|
|
Result:=True;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure TNamedManager._Merge(key:TNameAdrNode);
|
|
var
|
|
rkey:TNameAdrNode;
|
|
begin
|
|
|
|
//prev union
|
|
repeat
|
|
rkey:=key;
|
|
rkey.F.Offset:=rkey.F.Offset-1; //hack
|
|
|
|
if not _FetchNode_m(M_LE or C_UP,key.Offset,rkey) then Break;
|
|
|
|
key.F.Size :=key.F.Size+(key.F.Offset-rkey.F.Offset); //hack
|
|
key.F.Offset:=rkey.F.Offset; //hack
|
|
until false;
|
|
|
|
//next union
|
|
repeat
|
|
rkey:=key;
|
|
rkey.F.Offset:=rkey.F.Offset+rkey.F.Size; //hack
|
|
|
|
if not _FetchNode_m(M_BE or C_DW,(key.Offset+key.Size),rkey) then Break;
|
|
|
|
key.F.Size :=key.F.Size+rkey.F.Size; //hack
|
|
until false;
|
|
|
|
_Insert(key);
|
|
end;
|
|
|
|
procedure TNamedManager._Devide(Offset:Pointer;Size:QWORD;var key:TNameAdrNode);
|
|
var
|
|
FOffset:Pointer;
|
|
FSize:QWORD;
|
|
FEndN,FEndO:Pointer;
|
|
begin
|
|
FOffset:=key.Offset;
|
|
FSize :=key.Size;
|
|
|
|
FEndN:=Offset +Size;
|
|
FEndO:=FOffset+FSize;
|
|
|
|
if (Offset>FOffset) then //prev save
|
|
begin
|
|
key.Size:=Offset-FOffset;
|
|
_Merge(key);
|
|
end;
|
|
|
|
if (FEndO>FEndN) then //next save
|
|
begin
|
|
key.Offset:=FEndN;
|
|
key.Size :=FEndO-FEndN;
|
|
|
|
_Merge(key);
|
|
end else
|
|
if (FEndO<>FEndN) then //tunc size
|
|
begin
|
|
Size:=FEndO-Offset;
|
|
end;
|
|
|
|
//new save
|
|
key.Offset :=Offset;
|
|
key.Size :=Size;
|
|
end;
|
|
|
|
Function TNamedManager.Mname(Offset:Pointer;Size:QWORD;pname:PChar):Integer;
|
|
var
|
|
key:TNameAdrNode;
|
|
FEndN,FEndO:Pointer;
|
|
FSize:QWORD;
|
|
name:TName;
|
|
|
|
function _fetch:Boolean;
|
|
begin
|
|
Result:=False;
|
|
|
|
FEndN:=Offset+Size;
|
|
|
|
if _FetchNode_m(M_LE or C_LE,Offset,key) then
|
|
begin
|
|
FEndO:=key.Offset+key.Size;
|
|
|
|
_Devide(Offset,Size,key);
|
|
|
|
Result:=True;
|
|
end else
|
|
if _FetchNode_m(M_BE or C_BE,FEndN,key) then
|
|
begin
|
|
FEndO:=key.Offset+key.Size;
|
|
|
|
_Devide(key.Offset,FEndN-key.Offset,key);
|
|
|
|
Result:=True;
|
|
end;
|
|
end;
|
|
|
|
function _map:Boolean;
|
|
begin
|
|
Result:=False;
|
|
Assert(key.Size<>0);
|
|
|
|
//new save
|
|
key.name:=name;
|
|
_Merge(key);
|
|
|
|
if (FEndO>=FEndN) then Exit(True);
|
|
|
|
FSize:=FEndO-Offset;
|
|
Assert(FSize<>0);
|
|
|
|
Offset:=Offset+FSize;
|
|
Size :=Size -Min(FSize,Size);
|
|
end;
|
|
|
|
begin
|
|
Result:=0;
|
|
if (Size=0) or (Size>FMaxSize) then Exit(EINVAL);
|
|
if (Offset<Flo) or (Offset>Fhi) then Exit(EINVAL);
|
|
|
|
FEndO:=AlignDw(Offset,PHYSICAL_PAGE_SIZE);
|
|
Size:=Size+(Offset-FEndO);
|
|
|
|
Offset:=FEndO;
|
|
Size:=AlignUp(Size,PHYSICAL_PAGE_SIZE);
|
|
|
|
name:=Default(TName);
|
|
if (pname<>nil) then
|
|
begin
|
|
MoveChar0(pname^,name,SizeOf(TName));
|
|
end;
|
|
|
|
repeat
|
|
|
|
key:=Default(TNameAdrNode);
|
|
key.Offset:=Offset;
|
|
|
|
if _fetch then
|
|
begin
|
|
if _map then Break;
|
|
end else
|
|
begin
|
|
Result:=EINVAL;
|
|
Break;
|
|
end;
|
|
|
|
until false;
|
|
end;
|
|
|
|
Function TNamedManager.Query(Offset:Pointer;pname:PChar):Integer;
|
|
var
|
|
It:TAllcPoolNodeSet.Iterator;
|
|
key:TNameAdrNode;
|
|
begin
|
|
Result:=0;
|
|
|
|
if (pname=nil) then Exit(EINVAL);
|
|
|
|
Offset:=AlignDw(Offset,PHYSICAL_PAGE_SIZE);
|
|
|
|
key:=Default(TNameAdrNode);
|
|
key.Offset:=Offset;
|
|
|
|
It:=FAllcSet.find_le(key);
|
|
|
|
if (It.Item=nil) then Exit(EINVAL);
|
|
|
|
key:=It.Item^;
|
|
|
|
if (Offset>=(key.Size+key.Offset)) then Exit(EINVAL);
|
|
|
|
MoveChar0(key.name,pname^,SizeOf(TName));
|
|
end;
|
|
|
|
procedure TNamedManager.Print;
|
|
var
|
|
key:TNameAdrNode;
|
|
It:TAllcPoolNodeSet.Iterator;
|
|
begin
|
|
It:=FAllcSet.cbegin;
|
|
While (It.Item<>nil) do
|
|
begin
|
|
key:=It.Item^;
|
|
|
|
Writeln(HexStr(QWORD(key.Offset),11),'..',
|
|
HexStr(QWORD(key.Offset+key.Size),11),':',
|
|
HexStr(key.Size,11),'#',
|
|
Pchar(@key.name));
|
|
|
|
It.Next;
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
|
|
end.
|
|
|
|
|
|
|
|
|