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 |
else |
78 |
Result := 0; |
79 |
end; |
80 |
end; |
81 |
|
82 |
|
83 |
|
84 |
function GetDataType(typeid: Word): String; |
85 |
begin |
86 |
case typeid of |
87 |
1..4: |
88 |
Result := 'Int' + IntToStr(typeid * 8); |
89 |
5..8: |
90 |
Result := 'Int' + IntToStr((typeid - 4) * 8); |
91 |
9: |
92 |
Result := 'Float'; |
93 |
10: |
94 |
Result := 'BitSet'; |
95 |
11: |
96 |
Result := 'Raw-Address'; |
97 |
12: |
98 |
Result := '.dat-file-ID'; |
99 |
13..16: |
100 |
Result := 'SignedInt' + IntToStr((typeid - 12) * 8); |
101 |
17: |
102 |
Result := 'LevelID'; |
103 |
100..300: |
104 |
Result := '.dat-file-name(' + IntToStr(typeid - 100) + ')'; |
105 |
1000..9999: |
106 |
Result := 'Unused(' + IntToStr(typeid - 1000) + ')'; |
107 |
10000..65535: |
108 |
Result := 'String(' + IntToStr(typeid - 10000) + ')'; |
109 |
end; |
110 |
end; |
111 |
|
112 |
|
113 |
|
114 |
function Explode(_string: String; delimiter: Char): TStringArray; |
115 |
var |
116 |
start, len: Word; |
117 |
begin |
118 |
SetLength(Result, 0); |
119 |
start := 1; |
120 |
while PosEx(delimiter, _string, start) > 0 do |
121 |
begin |
122 |
SetLength(Result, Length(Result) + 1); |
123 |
len := PosEx(delimiter, _string, start) - start; |
124 |
Result[High(Result)] := MidStr(_string, start, len); |
125 |
start := start + len + 1; |
126 |
end; |
127 |
SetLength(Result, Length(Result) + 1); |
128 |
Result[High(Result)] := MidStr(_string, start, Length(_string) - start + 1); |
129 |
end; |
130 |
|
131 |
|
132 |
|
133 |
function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef; |
134 |
var |
135 |
current_type: Byte; //0: Global, 1: Undynamic, 2: Dynamic |
136 |
current_base, current_package, current_package_size: Integer; |
137 |
packages: Integer; |
138 |
deffile: Text; |
139 |
structentry: TStructureEntry; |
140 |
fields: TStringArray; |
141 |
filename: String; |
142 |
ext: String[4]; |
143 |
temps: String; |
144 |
Data: TByteData; |
145 |
begin |
146 |
SetLength(Result.Global, 0); |
147 |
SetLength(Result.Subs, 0); |
148 |
Result.Data := False; |
149 |
ext := ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension; |
150 |
filename := ExtractFilePath(Application.ExeName) + '\StructDefs\' + ext + '.txt'; |
151 |
if FileExists(filename) then |
152 |
begin |
153 |
ConManager.Connection[ConnectionID].LoadDatFile(FileID, Data); |
154 |
AssignFile(deffile, filename); |
155 |
Reset(deffile); |
156 |
current_type := 0; |
157 |
Result.Data := True; |
158 |
if not EOF(deffile) then |
159 |
begin |
160 |
ReadLn(deffile, temps); |
161 |
while not EOF(deffile) do |
162 |
begin |
163 |
ReadLn(deffile, temps); |
164 |
if (Length(temps) > 0) and (temps[1] <> '#') then |
165 |
begin |
166 |
if temps[1] = '*' then |
167 |
begin |
168 |
fields := Explode(temps, #9); |
169 |
case Length(fields) of |
170 |
1..2: |
171 |
begin |
172 |
current_type := 1; |
173 |
current_base := 0; |
174 |
SetLength(Result.Subs, Length(Result.Subs) + 1); |
175 |
Result.Subs[High(Result.Subs)].SubName := |
176 |
MidStr(fields[0], 2, Length(fields[0]) - 1); |
177 |
if Length(fields) = 2 then |
178 |
Result.Subs[High(Result.Subs)].SubDesc := fields[1]; |
179 |
end; |
180 |
3: |
181 |
begin |
182 |
current_type := 1; |
183 |
current_base := StrToInt(fields[2]); |
184 |
SetLength(Result.Subs, Length(Result.Subs) + 1); |
185 |
Result.Subs[High(Result.Subs)].SubName := |
186 |
MidStr(fields[0], 2, Length(fields[0]) - 1); |
187 |
Result.Subs[High(Result.Subs)].SubDesc := fields[1]; |
188 |
end; |
189 |
6: |
190 |
begin |
191 |
current_type := 2; |
192 |
current_base := StrToInt(fields[2]); |
193 |
current_package := 0; |
194 |
current_package_size := StrToInt(fields[5]); |
195 |
if fields[4][1] <> '$' then |
196 |
begin |
197 |
case StrToInt(fields[4]) of |
198 |
1: |
199 |
packages := Data[StrToInt(fields[3])]; |
200 |
2: |
201 |
packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * 256; |
202 |
4: |
203 |
packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * |
204 |
256 + Data[StrToInt(fields[3]) + 2] * 256 * 256 + Data[StrToInt(fields[3]) + 3] * 256 * 256 * 256; |
205 |
end; |
206 |
end |
207 |
else |
208 |
begin |
209 |
packages := StrToInt(fields[4]); |
210 |
end; |
211 |
SetLength(Result.Subs, Length(Result.Subs) + packages); |
212 |
for current_package := 0 to packages - 1 do |
213 |
begin |
214 |
Result.Subs[High(Result.Subs) - packages + |
215 |
current_package + 1].SubName := |
216 |
MidStr(fields[0], 2, Length(fields[0]) - 1) + |
217 |
'[' + IntToStr(current_package) + ']' + '#' + |
218 |
IntToHex(current_base + current_package * current_package_size, 8) + |
219 |
'#' + IntToHex(current_package_size, 8); |
220 |
Result.Subs[High(Result.Subs) - packages + |
221 |
current_package + 1].SubDesc := |
222 |
fields[1]; |
223 |
end; |
224 |
end; |
225 |
end; |
226 |
end |
227 |
else |
228 |
begin |
229 |
fields := Explode(temps, #9); |
230 |
if (Length(fields) = 3) or (Length(fields) = 4) then |
231 |
begin |
232 |
if not AppSettings.HideUnusedData or |
233 |
((StrToInt(fields[2]) < 1000) or (StrToInt(fields[2]) > 9999)) then |
234 |
begin |
235 |
structentry.Name := fields[0]; |
236 |
structentry.datatype := StrToInt(fields[2]); |
237 |
if Length(fields) = 4 then |
238 |
structentry.description := fields[3] |
239 |
else |
240 |
structentry.description := ''; |
241 |
if current_type in [0, 1] then |
242 |
begin |
243 |
structentry.offset := StrToInt(fields[1]) + current_base; |
244 |
if Length(Result.Subs) = 0 then |
245 |
begin |
246 |
SetLength(Result.Global, Length(Result.Global) + 1); |
247 |
Result.Global[High(Result.Global)] := structentry; |
248 |
end |
249 |
else |
250 |
begin |
251 |
SetLength(Result.Subs[High(Result.Subs)].Entries, |
252 |
Length(Result.Subs[High(Result.Subs)].Entries) + 1); |
253 |
Result.Subs[High(Result.Subs)].Entries[High( |
254 |
Result.Subs[High(Result.Subs)].Entries)] := structentry; |
255 |
end; |
256 |
end |
257 |
else |
258 |
begin |
259 |
for current_package := 0 to packages - 1 do |
260 |
begin |
261 |
structentry.offset := |
262 |
current_base + current_package * current_package_size + StrToInt(fields[1]); |
263 |
with Result.Subs[High(Result.Subs) - packages + current_package + 1] do |
264 |
begin |
265 |
SetLength(Entries, Length(Entries) + 1); |
266 |
Entries[High(Entries)] := structentry; |
267 |
end; |
268 |
end; |
269 |
end; |
270 |
end; |
271 |
end; |
272 |
end; |
273 |
end; |
274 |
end; |
275 |
end; |
276 |
CloseFile(deffile); |
277 |
end; |
278 |
end; |
279 |
|
280 |
|
281 |
end. |