unit DatStructureLoader; interface type TStructureEntry = record Name: String; offset: Integer; datatype: Word; // 1..4 : Integer[1..4] dec // 5..8 : Integer[1..4] hex // 9 : float // 10 : bitset // 11 : raw-addr // 12 : untyped-dat-file-ID-link // 13..16: Signed Integer[1..4] // 17 : level-ID // 100..300: dat-file-name[0..200] // 501..614: typed-dat-file-ID-link // 1000..9999: Unused data[0-8999] // 10000+: string[0+] description: String; end; TStructDefSub = record SubName: String; SubDesc: String; Entries: array of TStructureEntry; end; TStructDef = record Data: Boolean; Global: array of TStructureEntry; Subs: array of TStructDefSub; end; function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef; function GetDataType(TypeID: Word): String; function GetDataTypeLength(DataType: Word): Word; implementation uses SysUtils, Classes, Functions, ConnectionManager, TypeDefs, Forms, StrUtils, Data; type TStringArray = array of String; function GetDataTypeLength(DataType: Word): Word; begin case datatype of 1..4: Result := datatype; 5..8: Result := datatype - 4; 9: Result := 4; 10: Result := 1; 11: Result := 4; 12: Result := 4; 13..16: Result := datatype - 12; 17: Result := 4; 100..300: Result := datatype - 100; 500..614: Result := 4; 1000..9999: Result := datatype - 1000; 10000..65535: Result := datatype - 10000; end; end; function GetDataType(typeid: Word): String; begin case typeid of 1..4: Result := 'Int' + IntToStr(typeid * 8); 5..8: Result := 'Int' + IntToStr((typeid - 4) * 8); 9: Result := 'Float'; 10: Result := 'BitSet'; 11: Result := 'Raw-Address'; 12: Result := '.dat-file-ID'; 13..16: Result := 'SignedInt' + IntToStr((typeid - 12) * 8); 17: Result := 'LevelID'; 100..300: Result := '.dat-file-name(' + IntToStr(typeid - 100) + ')'; 1000..9999: Result := 'Unused(' + IntToStr(typeid - 1000) + ')'; 10000..65535: Result := 'String(' + IntToStr(typeid - 10000) + ')'; end; end; function Explode(_string: String; delimiter: Char): TStringArray; var start, len: Word; begin SetLength(Result, 0); start := 1; while PosEx(delimiter, _string, start) > 0 do begin SetLength(Result, Length(Result) + 1); len := PosEx(delimiter, _string, start) - start; Result[High(Result)] := MidStr(_string, start, len); start := start + len + 1; end; SetLength(Result, Length(Result) + 1); Result[High(Result)] := MidStr(_string, start, Length(_string) - start + 1); end; function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef; var current_type: Byte; //0: Global, 1: Undynamic, 2: Dynamic current_base, current_package, current_package_size: Integer; packages: Integer; deffile: Text; structentry: TStructureEntry; fields: TStringArray; filename: String; ext: String[4]; temps: String; Data: TByteData; begin SetLength(Result.Global, 0); SetLength(Result.Subs, 0); Result.Data := False; ext := ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension; filename := ExtractFilePath(Application.ExeName) + '\StructDefs\' + ext + '.txt'; if FileExists(filename) then begin ConManager.Connection[ConnectionID].LoadDatFile(FileID, Data); AssignFile(deffile, filename); Reset(deffile); current_type := 0; Result.Data := True; if not EOF(deffile) then begin ReadLn(deffile, temps); while not EOF(deffile) do begin ReadLn(deffile, temps); if (Length(temps) > 0) and (temps[1] <> '#') then begin if temps[1] = '*' then begin fields := Explode(temps, #9); case Length(fields) of 1..2: begin current_type := 1; current_base := 0; SetLength(Result.Subs, Length(Result.Subs) + 1); Result.Subs[High(Result.Subs)].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1); if Length(fields) = 2 then Result.Subs[High(Result.Subs)].SubDesc := fields[1]; end; 3: begin current_type := 1; current_base := StrToInt(fields[2]); SetLength(Result.Subs, Length(Result.Subs) + 1); Result.Subs[High(Result.Subs)].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1); Result.Subs[High(Result.Subs)].SubDesc := fields[1]; end; 6: begin current_type := 2; current_base := StrToInt(fields[2]); current_package := 0; current_package_size := StrToInt(fields[5]); if fields[4][1] <> '$' then begin case StrToInt(fields[4]) of 1: packages := Data[StrToInt(fields[3])]; 2: packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * 256; 4: packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * 256 + Data[StrToInt(fields[3]) + 2] * 256 * 256 + Data[StrToInt(fields[3]) + 3] * 256 * 256 * 256; end; end else begin packages := StrToInt(fields[4]); end; SetLength(Result.Subs, Length(Result.Subs) + packages); for current_package := 0 to packages - 1 do begin Result.Subs[High(Result.Subs) - packages + current_package + 1].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1) + '[' + IntToStr(current_package) + ']' + '#' + IntToHex(current_base + current_package * current_package_size, 8) + '#' + IntToHex(current_package_size, 8); Result.Subs[High(Result.Subs) - packages + current_package + 1].SubDesc := fields[1]; end; end; end; end else begin fields := Explode(temps, #9); if (Length(fields) = 3) or (Length(fields) = 4) then begin if not AppSettings.HideUnusedData or ((StrToInt(fields[2]) < 1000) or (StrToInt(fields[2]) > 9999)) then begin structentry.Name := fields[0]; structentry.datatype := StrToInt(fields[2]); if Length(fields) = 4 then structentry.description := fields[3] else structentry.description := ''; if current_type in [0, 1] then begin structentry.offset := StrToInt(fields[1]) + current_base; if Length(Result.Subs) = 0 then begin SetLength(Result.Global, Length(Result.Global) + 1); Result.Global[High(Result.Global)] := structentry; end else begin SetLength(Result.Subs[High(Result.Subs)].Entries, Length(Result.Subs[High(Result.Subs)].Entries) + 1); Result.Subs[High(Result.Subs)].Entries[High( Result.Subs[High(Result.Subs)].Entries)] := structentry; end; end else begin for current_package := 0 to packages - 1 do begin structentry.offset := current_base + current_package * current_package_size + StrToInt(fields[1]); with Result.Subs[High(Result.Subs) - packages + current_package + 1] do begin SetLength(Entries, Length(Entries) + 1); Entries[High(Entries)] := structentry; end; end; end; end; end; end; end; end; end; CloseFile(deffile); end; end; end.