| 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. |