1 |
unit DatStructureLoader; |
2 |
|
3 |
interface |
4 |
|
5 |
type |
6 |
TStructureEntry = record |
7 |
Name: String; |
8 |
offset: Integer; |
9 |
datatype: Word; |
10 |
// 1..4 : Integer[1..4] dec |
11 |
// 5..8 : Integer[1..4] hex |
12 |
// 9 : float |
13 |
// 10 : bitset |
14 |
// 11 : raw-addr |
15 |
// 12 : untyped-dat-file-ID-link |
16 |
// 13..16: Signed Integer[1..4] |
17 |
// 17 : level-ID |
18 |
// 100..300: dat-file-name[0..200] |
19 |
// 501..614: typed-dat-file-ID-link |
20 |
// 1000..9999: Unused data[0-8999] |
21 |
// 10000+: string[0+] |
22 |
description: String; |
23 |
end; |
24 |
|
25 |
TStructDefSub = record |
26 |
SubName: String; |
27 |
SubDesc: String; |
28 |
Entries: array of TStructureEntry; |
29 |
end; |
30 |
|
31 |
TStructDef = record |
32 |
Data: Boolean; |
33 |
Global: array of TStructureEntry; |
34 |
Subs: array of TStructDefSub; |
35 |
end; |
36 |
|
37 |
|
38 |
function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef; |
39 |
function GetDataType(TypeID: Word): String; |
40 |
function GetDataTypeLength(DataType: Word): Word; |
41 |
|
42 |
implementation |
43 |
|
44 |
uses |
45 |
SysUtils, Classes, Functions, ConnectionManager, TypeDefs, Forms, StrUtils, Data; |
46 |
|
47 |
type |
48 |
TStringArray = array of String; |
49 |
|
50 |
function GetDataTypeLength(DataType: Word): Word; |
51 |
begin |
52 |
case datatype of |
53 |
1..4: |
54 |
Result := datatype; |
55 |
5..8: |
56 |
Result := datatype - 4; |
57 |
9: |
58 |
Result := 4; |
59 |
10: |
60 |
Result := 1; |
61 |
11: |
62 |
Result := 4; |
63 |
12: |
64 |
Result := 4; |
65 |
13..16: |
66 |
Result := datatype - 12; |
67 |
17: |
68 |
Result := 4; |
69 |
100..300: |
70 |
Result := datatype - 100; |
71 |
500..614: |
72 |
Result := 4; |
73 |
1000..9999: |
74 |
Result := datatype - 1000; |
75 |
10000..65535: |
76 |
Result := datatype - 10000; |
77 |
end; |
78 |
end; |
79 |
|
80 |
|
81 |
|
82 |
function GetDataType(typeid: Word): String; |
83 |
begin |
84 |
case typeid of |
85 |
1..4: |
86 |
Result := 'Int' + IntToStr(typeid * 8); |
87 |
5..8: |
88 |
Result := 'Int' + IntToStr((typeid - 4) * 8); |
89 |
9: |
90 |
Result := 'Float'; |
91 |
10: |
92 |
Result := 'BitSet'; |
93 |
11: |
94 |
Result := 'Raw-Address'; |
95 |
12: |
96 |
Result := '.dat-file-ID'; |
97 |
13..16: |
98 |
Result := 'SignedInt' + IntToStr((typeid - 12) * 8); |
99 |
17: |
100 |
Result := 'LevelID'; |
101 |
100..300: |
102 |
Result := '.dat-file-name(' + IntToStr(typeid - 100) + ')'; |
103 |
1000..9999: |
104 |
Result := 'Unused(' + IntToStr(typeid - 1000) + ')'; |
105 |
10000..65535: |
106 |
Result := 'String(' + IntToStr(typeid - 10000) + ')'; |
107 |
end; |
108 |
end; |
109 |
|
110 |
|
111 |
|
112 |
function Explode(_string: String; delimiter: Char): TStringArray; |
113 |
var |
114 |
start, len: Word; |
115 |
begin |
116 |
SetLength(Result, 0); |
117 |
start := 1; |
118 |
while PosEx(delimiter, _string, start) > 0 do |
119 |
begin |
120 |
SetLength(Result, Length(Result) + 1); |
121 |
len := PosEx(delimiter, _string, start) - start; |
122 |
Result[High(Result)] := MidStr(_string, start, len); |
123 |
start := start + len + 1; |
124 |
end; |
125 |
SetLength(Result, Length(Result) + 1); |
126 |
Result[High(Result)] := MidStr(_string, start, Length(_string) - start + 1); |
127 |
end; |
128 |
|
129 |
|
130 |
|
131 |
function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef; |
132 |
var |
133 |
current_type: Byte; //0: Global, 1: Undynamic, 2: Dynamic |
134 |
current_base, current_package, current_package_size: Integer; |
135 |
packages: Integer; |
136 |
deffile: Text; |
137 |
structentry: TStructureEntry; |
138 |
fields: TStringArray; |
139 |
filename: String; |
140 |
ext: String[4]; |
141 |
temps: String; |
142 |
Data: TByteData; |
143 |
begin |
144 |
SetLength(Result.Global, 0); |
145 |
SetLength(Result.Subs, 0); |
146 |
Result.Data := False; |
147 |
ext := ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension; |
148 |
filename := ExtractFilePath(Application.ExeName) + '\StructDefs\' + ext + '.txt'; |
149 |
if FileExists(filename) then |
150 |
begin |
151 |
ConManager.Connection[ConnectionID].LoadDatFile(FileID, Data); |
152 |
AssignFile(deffile, filename); |
153 |
Reset(deffile); |
154 |
current_type := 0; |
155 |
Result.Data := True; |
156 |
if not EOF(deffile) then |
157 |
begin |
158 |
ReadLn(deffile, temps); |
159 |
while not EOF(deffile) do |
160 |
begin |
161 |
ReadLn(deffile, temps); |
162 |
if (Length(temps) > 0) and (temps[1] <> '#') then |
163 |
begin |
164 |
if temps[1] = '*' then |
165 |
begin |
166 |
fields := Explode(temps, #9); |
167 |
case Length(fields) of |
168 |
1..2: |
169 |
begin |
170 |
current_type := 1; |
171 |
current_base := 0; |
172 |
SetLength(Result.Subs, Length(Result.Subs) + 1); |
173 |
Result.Subs[High(Result.Subs)].SubName := |
174 |
MidStr(fields[0], 2, Length(fields[0]) - 1); |
175 |
if Length(fields) = 2 then |
176 |
Result.Subs[High(Result.Subs)].SubDesc := fields[1]; |
177 |
end; |
178 |
3: |
179 |
begin |
180 |
current_type := 1; |
181 |
current_base := StrToInt(fields[2]); |
182 |
SetLength(Result.Subs, Length(Result.Subs) + 1); |
183 |
Result.Subs[High(Result.Subs)].SubName := |
184 |
MidStr(fields[0], 2, Length(fields[0]) - 1); |
185 |
Result.Subs[High(Result.Subs)].SubDesc := fields[1]; |
186 |
end; |
187 |
6: |
188 |
begin |
189 |
current_type := 2; |
190 |
current_base := StrToInt(fields[2]); |
191 |
current_package := 0; |
192 |
current_package_size := StrToInt(fields[5]); |
193 |
if fields[4][1] <> '$' then |
194 |
begin |
195 |
case StrToInt(fields[4]) of |
196 |
1: |
197 |
packages := Data[StrToInt(fields[3])]; |
198 |
2: |
199 |
packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * 256; |
200 |
4: |
201 |
packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * |
202 |
256 + Data[StrToInt(fields[3]) + 2] * 256 * 256 + Data[StrToInt(fields[3]) + 3] * 256 * 256 * 256; |
203 |
end; |
204 |
end |
205 |
else |
206 |
begin |
207 |
packages := StrToInt(fields[4]); |
208 |
end; |
209 |
SetLength(Result.Subs, Length(Result.Subs) + packages); |
210 |
for current_package := 0 to packages - 1 do |
211 |
begin |
212 |
Result.Subs[High(Result.Subs) - packages + |
213 |
current_package + 1].SubName := |
214 |
MidStr(fields[0], 2, Length(fields[0]) - 1) + |
215 |
'[' + IntToStr(current_package) + ']' + '#' + |
216 |
IntToHex(current_base + current_package * current_package_size, 8) + |
217 |
'#' + IntToHex(current_package_size, 8); |
218 |
Result.Subs[High(Result.Subs) - packages + |
219 |
current_package + 1].SubDesc := |
220 |
fields[1]; |
221 |
end; |
222 |
end; |
223 |
end; |
224 |
end |
225 |
else |
226 |
begin |
227 |
fields := Explode(temps, #9); |
228 |
if (Length(fields) = 3) or (Length(fields) = 4) then |
229 |
begin |
230 |
if not AppSettings.HideUnusedData or |
231 |
((StrToInt(fields[2]) < 1000) or (StrToInt(fields[2]) > 9999)) then |
232 |
begin |
233 |
structentry.Name := fields[0]; |
234 |
structentry.datatype := StrToInt(fields[2]); |
235 |
if Length(fields) = 4 then |
236 |
structentry.description := fields[3] |
237 |
else |
238 |
structentry.description := ''; |
239 |
if current_type in [0, 1] then |
240 |
begin |
241 |
structentry.offset := StrToInt(fields[1]) + current_base; |
242 |
if Length(Result.Subs) = 0 then |
243 |
begin |
244 |
SetLength(Result.Global, Length(Result.Global) + 1); |
245 |
Result.Global[High(Result.Global)] := structentry; |
246 |
end |
247 |
else |
248 |
begin |
249 |
SetLength(Result.Subs[High(Result.Subs)].Entries, |
250 |
Length(Result.Subs[High(Result.Subs)].Entries) + 1); |
251 |
Result.Subs[High(Result.Subs)].Entries[High( |
252 |
Result.Subs[High(Result.Subs)].Entries)] := structentry; |
253 |
end; |
254 |
end |
255 |
else |
256 |
begin |
257 |
for current_package := 0 to packages - 1 do |
258 |
begin |
259 |
structentry.offset := |
260 |
current_base + current_package * current_package_size + StrToInt(fields[1]); |
261 |
with Result.Subs[High(Result.Subs) - packages + current_package + 1] do |
262 |
begin |
263 |
SetLength(Entries, Length(Entries) + 1); |
264 |
Entries[High(Entries)] := structentry; |
265 |
end; |
266 |
end; |
267 |
end; |
268 |
end; |
269 |
end; |
270 |
end; |
271 |
end; |
272 |
end; |
273 |
end; |
274 |
CloseFile(deffile); |
275 |
end; |
276 |
end; |
277 |
|
278 |
|
279 |
end. |