-
Notifications
You must be signed in to change notification settings - Fork 28
/
PE.RTTI.pas
107 lines (87 loc) · 2.47 KB
/
PE.RTTI.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
unit PE.RTTI;
interface
uses
System.Classes;
type
TRecordFieldDesc = record
Flags: uint32;
FieldName: PChar;
end;
PRecordFieldDesc = ^TRecordFieldDesc;
// TRttiReadFunc must return:
// - OutFieldSize: size of field.
// - OutReadSize size to read into field.
TRttiFieldResolveProc = procedure(Desc: PRecordFieldDesc;
OutFieldSize, OutReadWriteSize: PInteger; ud: pointer);
TRttiOperation = (RttiRead, RttiWrite, RttiCalcSize);
// MaxSize: -1 means no limit.
function RTTI_Process(Stream: TStream; Op: TRttiOperation; Buf: PByte;
FieldDesc: PRecordFieldDesc; FieldDescCnt: integer; MaxSize: integer;
ResolveProc: TRttiFieldResolveProc; ud: pointer): uint32;
implementation
{$IFDEF DIAG}
uses
System.SysUtils;
procedure DbgLogData(Desc: PRecordFieldDesc; Stream: TStream;
FieldSize: integer; IOSize: integer);
begin
writeln(Format('"%s" @ %x FieldSize: %x IOSize: %x',
[Desc.FieldName, Stream.Position, FieldSize, IOSize]));
end;
{$ENDIF}
function RTTI_Process;
var
i: integer;
FieldSize, ReadWriteSize, tmp: integer;
begin
Result := 0;
if (Buf = nil) or (FieldDesc = nil) or (FieldDescCnt = 0) or (MaxSize = 0)
then
exit;
for i := 0 to FieldDescCnt - 1 do
begin
ResolveProc(FieldDesc, @FieldSize, @ReadWriteSize, ud);
{$IFDEF DIAG}
DbgLogData(FieldDesc, Stream, FieldSize, ReadWriteSize);
{$ENDIF}
if ReadWriteSize <> 0 then
begin
case Op of
RttiRead:
begin
if ReadWriteSize < FieldSize then
FillChar(Buf^, FieldSize, 0);
tmp := Stream.Read(Buf^, ReadWriteSize);
end;
RttiWrite:
tmp := Stream.Write(Buf^, ReadWriteSize);
RttiCalcSize:
tmp := ReadWriteSize;
else
tmp := ReadWriteSize;
end;
if tmp <> ReadWriteSize then
break; // read error
{$IFDEF DIAG}
case tmp of
1:
writeln(Format('= %x', [PByte(Buf)^]));
2:
writeln(Format('= %x', [PWord(Buf)^]));
4:
writeln(Format('= %x', [PCardinal(Buf)^]));
8:
writeln(Format('= %x', [PUint64(Buf)^]));
end;
{$ENDIF}
end;
inc(Result, ReadWriteSize);
inc(Buf, FieldSize);
inc(FieldDesc);
{$WARN COMPARING_SIGNED_UNSIGNED OFF}
if (MaxSize <> -1) and (Result >= MaxSize) then
break;
{$WARN COMPARING_SIGNED_UNSIGNED ON}
end;
end;
end.