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