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.
