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