unit _DataTypes; interface uses Classes, _TreeElement; type TContainer = class; TDataField = class(TTreeElement) protected FOffset: Integer; FName: String; FType: String; FDescription: String; FDataLength: Integer; FParentFile: TObject; FParentBlock: TContainer; FChanged: Boolean; FExtraArgs: array of TVarRec; function GetChildCount: Integer; override; function GetChild(ID: Integer): TTreeElement; override; function GetCaption: String; override; function GetType: String; override; function GetValueAsString: String; virtual; public constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); virtual; procedure Update(Offset, Length: Integer); virtual; abstract; procedure WriteData(stream: TStream); virtual; abstract; property Offset: Integer read FOffset; property Name: String read FName; property Description: String read FDescription; property DataLength: Integer read FDataLength; property ValueAsString: String read GetValueAsString; end; TFieldType = class of TDataField; TContainer = class(TDataField) public function AddField(fieldtype: TFieldType; Name, Description: String; ExtraArgs: array of const): TDataField; virtual; abstract; procedure UpdateSize; virtual; abstract; end; TBlock = class(TContainer) protected FDataFields: array of TDataField; function GetChildCount: Integer; override; function GetChild(ID: Integer): TTreeElement; override; function GetFieldByOffset(Offset: Integer): TDataField; public // ExtraArgs: Pointer auf Integer: BlockLength <- no longer constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; property FieldByOffset[Offset: Integer]: TDataField read GetFieldByOffset; function AddField(fieldtype: TFieldType; Name, Description: String; ExtraArgs: array of const): TDataField; override; procedure UpdateSize; override; end; TInt = class(TDataField) protected FInt: Integer; function GetValueAsString: String; override; public // ExtraArgs: Pointer auf Integer: Bytes of TInt constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TFloat = class(TDataField) protected FFloat: Single; function GetValueAsString: String; override; public // ExtraArgs: none constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TBitSet = class(TDataField) protected FBits: Byte; FNames: TStringList; function GetValueAsString: String; override; public // ExtraArgs: Pointer auf TStringList constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TLevelID = class(TDataField) protected FLevelID: Integer; function GetValueAsString: String; override; public // ExtraArgs: keine constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TResourceID = class(TDataField) protected FFileID: Integer; function GetValueAsString: String; override; public // ExtraArgs: keine constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TDatLink = class(TDataField) protected FPosExts: String; function GetTarget: TObject; virtual; abstract; public property PosExts: String read FPosExts; property TargetFile: TObject read GetTarget; end; TLinkByID = class(TDatLink) protected FFileID: Integer; function GetChildCount: Integer; override; function GetChild(ID: Integer): TTreeElement; override; function GetValueAsString: String; override; function GetTarget: TObject; override; public // ExtraArgs: Pointer auf String: Possible Exts constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TString = class(TDataField) protected FString: String; function GetValueAsString: String; override; public // ExtraArgs: Pointer auf Integer: Length constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; TArray = class(TContainer) protected FDataFields: array of TBlock; FTemplate: TBlock; FCounterSize: Integer; FBlockCount: Integer; function GetChildCount: Integer; override; function GetChild(ID: Integer): TTreeElement; override; function GetFieldByOffset(Offset: Integer): TDataField; public // ExtraArgs: // 1. Integer: CounterSize (if 0 then 2. integer is required) // 2. Integer: BlockCount (for fixed-size arrays) constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; function AddField(fieldtype: TFieldType; Name, Description: String; ExtraArgs: array of const): TDataField; override; procedure SetCount; overload; procedure SetCount(n: Integer); overload; procedure UpdateSize; override; end; TRawLink = class(TDataField) protected FRawAddress: Integer; FRawType: String; FSep: Boolean; function GetValueAsString: String; override; public // ExtraArgs: String: RawType; Bool: Sep constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; property RawType: String read FRawType; end; TUnused = class(TDataField) protected function GetValueAsString: String; override; public // ExtraArgs: Pointer auf Integer: Length constructor Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); override; procedure Update(Offset, Length: Integer); override; procedure WriteData(stream: TStream); override; end; implementation uses SysUtils, Dialogs, _FileTypes, ConnectionManager, StrUtils; { TDataType } constructor TDataField.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); var i: Integer; begin if Assigned(ParentBlock) then FOffset := ParentBlock.Offset + ParentBlock.DataLength else FOffset := 0; FName := Name; FDescription := Description; FParentFile := ParentFile; FParentBlock := ParentBlock; SetLength(FExtraArgs, Length(ExtraArgs)); if Length(ExtraArgs) > 0 then for i := 0 to High(ExtraArgs) do FExtraArgs[i] := ExtraArgs[i]; FConnectionID := TResource(ParentFile).ConnectionID; end; function TDataField.GetCaption: String; begin Result := FName; end; function TDataField.GetChild(ID: Integer): TTreeElement; begin Result := nil; end; function TDataField.GetChildCount: Integer; begin Result := 0; end; function TDataField.GetType: String; begin Result := FType; end; function TDataField.GetValueAsString: String; begin Result := ''; end; { TString } constructor TString.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := ExtraArgs[0].VInteger; FType := 'String[' + IntToStr(FDataLength) + ']'; end; function TString.GetValueAsString: String; begin Result := FString; end; procedure TString.Update(Offset, Length: Integer); var fstream: TMemoryStream; i: Integer; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); SetLength(FString, FDataLength); fstream.Read(FString[1], FDataLength); for i := 1 to FDataLength do if FString[i] = Chr(0) then begin SetLength(FString, i - 1); Break; end; end; procedure TString.WriteData(stream: TStream); var temps: String; i: Integer; begin temps := FString; SetLength(temps, FDataLength); for i := Length(FString) + 1 to FDataLength do temps[i] := #0; stream.Write(temps[1], FDataLength); end; { TInt } constructor TInt.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := ExtraArgs[0].VInteger; FType := 'Int' + IntToStr(FDataLength * 8); FInt := 0; end; function TInt.GetValueAsString: String; begin Result := IntToStr(FInt); end; procedure TInt.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FInt, FDataLength); end; procedure TInt.WriteData(stream: TStream); begin stream.Write(FInt, FDataLength); end; { TArray } function TArray.AddField(fieldtype: TFieldType; Name, Description: String; ExtraArgs: array of const): TDataField; var i: Integer; begin Result := FTemplate.AddField(fieldtype, Name, Description, ExtraArgs); end; constructor TArray.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FCounterSize := ExtraArgs[0].VInteger; FType := ''; if Length(ExtraArgs) = 2 then FBlockCount := ExtraArgs[1].VInteger else FBlockCount := 0; FTemplate := TBlock.Create(ParentFile, Self, '', '', []); end; function TArray.GetChildCount: Integer; begin Result := Length(FDataFields); end; function TArray.GetChild(ID: Integer): TTreeElement; begin Result := FDataFields[ID]; end; function TArray.GetFieldByOffset(Offset: Integer): TDataField; begin Exit; end; procedure TArray.SetCount; var fstream: TMemoryStream; arr_index: Integer; i: Integer; procedure Add(DestBlock, SrcBlock: TBlock); var fid: Integer; field: TDataField; result: TDataField; begin if Length(SrcBlock.FDataFields) > 0 then begin for fid := 0 to High(SrcBlock.FDataFields) do begin field := SrcBlock.FDataFields[fid]; result := DestBlock.AddField(TFieldType(field.ClassType), field.Name, field.Description, field.FExtraArgs); if result is TBlock then Add(TBlock(result), TBlock(field)); end; end; end; begin if FCounterSize > 0 then begin fstream := TResource(FParentFile).FileStream; fstream.Seek(Offset, soFromBeginning); FBlockCount := 0; fstream.Read(FBlockCount, FCounterSize); end; FDataLength := FCounterSize; if FBlockCount > 0 then begin for arr_index := 0 to FBlockCount - 1 do begin SetLength(FDataFields, arr_index + 1); FDataFields[arr_index] := TBlock.Create(FParentFile, Self, '[' + IntToStr(arr_index) + ']', '', []); Add(FDataFields[arr_index], FTemplate); end; end; if Pos('[', FName) > 0 then begin if Pos(']', FName) = Length(FName) then begin i := Pos('[', ReverseString(FName)); FName := MidStr(FName, 1, Length(FName) - i); end; end; FName := FName + '[' + IntToStr(FBlockCount) + ']'; FParentBlock.UpdateSize; end; procedure TArray.SetCount(n: Integer); var fstream: TMemoryStream; begin FBlockCount := n; if FCounterSize > 0 then begin fstream := TResource(FParentFile).FileStream; fstream.Seek(Offset, soFromBeginning); fstream.Write(FBlockCount, FCounterSize); end; SetCount; end; procedure TArray.Update(Offset, Length: Integer); var i: Integer; field: TDataField; begin if System.Length(FDataFields) > 0 then begin if Length > 0 then begin for i := 0 to High(FDataFields) do begin field := FDataFields[i]; if ((field.Offset < Offset) and (field.Offset + field.DataLength > Offset + Length)) or ((field.Offset > Offset) and (field.Offset < Offset + Length)) or ((field.Offset + field.DataLength > Offset) and (field.Offset+field.DataLength < Offset + Length)) then field.Update(Offset, Length); end; end else begin for i := 0 to High(FDataFields) do FDataFields[i].Update(Offset, Length); end; end; end; procedure TArray.UpdateSize; var i: Integer; begin FDataLength := FCounterSize; if Length(FDataFields) > 0 then for i := 0 to High(FDataFields) do FDataLength := FDataLength + FDataFields[i].DataLength; FParentBlock.UpdateSize; end; procedure TArray.WriteData(stream: TStream); var i: Integer; begin if FCounterSize > 0 then stream.Write(FBlockCount, FCounterSize); if Length(FDataFields) > 0 then for i := 0 to High(FDataFields) do FDataFields[i].WriteData(stream); end; { TBlock } function TBlock.AddField(fieldtype: TFieldType; Name, Description: String; ExtraArgs: array of const): TDataField; begin SetLength(FDataFields, Length(FDataFields) + 1); FDataFields[High(FDataFields)] := TFieldType(fieldtype).Create( FParentFile, Self, Name, Description, ExtraArgs); Result := FDataFields[High(FDataFields)]; FDataLength := FDataLength + Result.DataLength; if Assigned(FParentBlock) then FParentBlock.UpdateSize; end; constructor TBlock.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FType := ''; end; function TBlock.GetChild(ID: Integer): TTreeElement; begin Result := FDataFields[ID]; end; function TBlock.GetChildCount: Integer; begin Result := Length(FDataFields); end; function TBlock.GetFieldByOffset(Offset: Integer): TDataField; begin Exit; end; procedure TBlock.Update(Offset, Length: Integer); var i: Integer; field: TDataField; begin if System.Length(FDataFields) > 0 then begin if Length > 0 then begin for i := 0 to High(FDataFields) do begin field := FDataFields[i]; if ((field.Offset < Offset) and (field.Offset + field.DataLength > Offset + Length)) or ((field.Offset > Offset) and (field.Offset < Offset + Length)) or ((field.Offset + field.DataLength > Offset) and (field.Offset+field.DataLength < Offset + Length)) then field.Update(Offset, Length); end; end else begin for i := 0 to High(FDataFields) do begin FDataFields[i].Update(Offset, Length); end; end; end; end; procedure TBlock.UpdateSize; var i: Integer; begin FDataLength := 0; if Length(FDataFields) > 0 then for i := 0 to High(FDataFields) do FDataLength := FDataLength + FDataFields[i].FDataLength; if Assigned(FParentBlock) then FParentBlock.UpdateSize; end; procedure TBlock.WriteData(stream: TStream); var i: Integer; begin if Length(FDataFields) > 0 then for i := 0 to High(FDataFields) do FDataFields[i].WriteData(stream); end; { TLevelID } constructor TLevelID.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := 4; FType := 'LevelID'; FLevelID := 0; end; function TLevelID.GetValueAsString: String; begin Result := IntToStr(FLevelID); end; procedure TLevelID.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FLevelID, 4); FLevelID := FLevelID div 256 div 256 div 256 div 2; end; procedure TLevelID.WriteData(stream: TStream); var tempi: Integer; begin tempi := FLevelID * 256 * 256 * 256 * 2 + 1; stream.Write(tempi, 4); end; { TFileID } constructor TResourceID.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := 4; FType := 'FileID'; FFileID := -1; end; function TResourceID.GetValueAsString: String; begin Result := IntToStr(FFileID); end; procedure TResourceID.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FFileID, 4); if FFileID > 0 then FFileID := FFileID div 256 else FFileID := -1; end; procedure TResourceID.WriteData(stream: TStream); var tempi: Integer; begin if FFileID >= 0 then tempi := FFileID * 256 + 1 else tempi := 0; stream.Write(tempi, 4); end; { TLinkByID } constructor TLinkByID.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := 4; case ExtraArgs[0].VType of vtChar: FPosExts := ExtraArgs[0].VChar; vtAnsiString: FPosExts := String(ExtraArgs[0].VAnsiString); end; FType := 'LinkByID(' + FPosExts + ')'; FFileID := -1; end; function TLinkByID.GetChild(ID: Integer): TTreeElement; begin if FFileID > 0 then Result := ConManager.Connection[FConnectionID].MetaData.FileById[FFileID].Child[ID] else Result := nil; end; function TLinkByID.GetChildCount: Integer; begin if FFileID > 0 then Result := ConManager.Connection[FConnectionID].MetaData.FileById[FFileID].ChildCount else Result := 0; end; function TLinkByID.GetTarget: TObject; begin if FFileID > 0 then Result := ConManager.Connection[FConnectionID].MetaData.FileById[FFileID] else Result := nil; end; function TLinkByID.GetValueAsString: String; begin if FFileID >= 0 then Result := IntToStr(FFileID) else Result := 'unused'; end; procedure TLinkByID.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FFileID, 4); if FFileID > 0 then FFileID := FFileID div 256 else FFileID := -1; end; procedure TLinkByID.WriteData(stream: TStream); var tempi: Integer; begin if FFileID >= 0 then tempi := FFileID * 256 + 1 else tempi := 0; stream.Write(tempi, 4); end; { TRawLink } constructor TRawLink.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); case ExtraArgs[0].VType of vtChar: FRawType := ExtraArgs[0].VChar; vtAnsiString: FRawType := String(ExtraArgs[0].VAnsiString); end; if Length(ExtraArgs) > 1 then FSep := ExtraArgs[1].VBoolean; FType := 'RawLink(' + FRawType + ')'; FDataLength := 4; end; function TRawLink.GetValueAsString: String; begin if FRawAddress > 0 then Result := '0x' + IntToHex(FRawAddress, 8) else Result := 'unused'; end; procedure TRawLink.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FRawAddress, 4); end; procedure TRawLink.WriteData(stream: TStream); begin stream.Write(FRawAddress, 4); end; { TUnused } constructor TUnused.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := ExtraArgs[0].VInteger; FType := 'Unused'; end; function TUnused.GetValueAsString: String; begin Result := ''; end; procedure TUnused.Update(Offset, Length: Integer); begin Exit; end; procedure TUnused.WriteData(stream: TStream); var i: Integer; tempb: Byte; begin tempb := 0; for i := 1 to FDataLength do stream.Write(tempb, 1); end; { TBitSet } constructor TBitSet.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); var i: Integer; begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FNames := TStringList.Create; for i := 0 to High(ExtraArgs) do begin case ExtraArgs[i].VType of vtChar: FNames.Add(ExtraArgs[i].VChar); vtAnsiString: FNames.Add(String(ExtraArgs[i].VAnsiString)); end; if Length(FDescription) > 0 then FDescription := FDescription + #13#10; FDescription := FDescription + '$' + IntToHex(1 shl i,2) + ': ' + FNames.Strings[FNames.Count - 1]; end; FDataLength := 1; FType := 'BitSet'; FBits := 0; end; function TBitSet.GetValueAsString: String; function IntToBits(Int: Integer): String; var i: Integer; begin Result := ''; for i := 0 to 7 do begin Result := IntToStr(FBits and (1 shl i) shr i) + Result; end; end; begin Result := IntToBits(FBits); end; procedure TBitSet.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FBits, FDataLength); end; procedure TBitSet.WriteData(stream: TStream); begin stream.Write(FBits, FDataLength); end; { TFloat } constructor TFloat.Create(ParentFile: TObject; ParentBlock: TContainer; Name, Description: String; ExtraArgs: array of const); begin inherited Create(ParentFile, ParentBlock, Name, Description, ExtraArgs); FDataLength := 4; FType := 'Float'; FFloat := 0; end; function TFloat.GetValueAsString: String; begin Result := FloatToStr(FFloat); end; procedure TFloat.Update(Offset, Length: Integer); var fstream: TMemoryStream; begin fstream := TResource(FParentFile).FileStream; fstream.Seek(FOffset, soFromBeginning); fstream.Read(FFloat, FDataLength); end; procedure TFloat.WriteData(stream: TStream); begin stream.Write(FFloat, 4); end; end.