unit RawEdit;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Template, StdCtrls, ExtCtrls, Menus, Grids, Wrapgrid,
  MPHexEditor, Clipbrd, StrUtils,
  Data, Functions, DataStructures, Exporters, OniDataClass, Buttons;

type
  TForm_RawEdit = class(TForm_ToolTemplate)
    Splitter4: TSplitter;
    panel_imexport: TPanel;
    btn_export: TButton;
    btn_import: TButton;
    GroupBox1: TGroupBox;
    list_offset: TListBox;
    hex: TMPHexEditor;
    Splitter2: TSplitter;
    value_viewer: TWrapGrid;
    value_viewer_context: TPopupMenu;
    value_viewer_context_copy: TMenuItem;
    value_viewer_context_copyasdec: TMenuItem;
    value_viewer_context_copyasfloat: TMenuItem;
    value_viewer_context_copyasbitset: TMenuItem;
    value_viewer_context_copyasstring: TMenuItem;
    value_viewer_context_copyashex: TMenuItem;
    opend: TOpenDialog;
    saved: TSaveDialog;
    procedure list_offsetClick(Sender: TObject);
    procedure NewFile(fileinfo: TFileInfo);
    procedure LoadRaw(raw_info: TRawInfo);
    function Save: Boolean;

    procedure btn_importClick(Sender: TObject);
    procedure btn_exportClick(Sender: TObject);

    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);

    function GetValue(datatype: Word; offset: LongWord): String;
    procedure ClearValues;
    procedure WriteValues;
    procedure SetNewValue(datatype: Word; offset: LongWord; Value: String);

    procedure value_viewerDblClick(Sender: TObject);
    procedure value_viewer_context_copyClick(Sender: TObject);
    procedure value_viewerMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure value_viewer_contextPopup(Sender: TObject);

    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure hexSelectionChanged(Sender: TObject);
    procedure hexChange(Sender: TObject);
  private
    fileid:     Integer;
    dat_offset: LongWord;
    fileid_opened, dat_offset_opened: Integer;
  public
  end;

var
  Form_RawEdit: TForm_RawEdit;

implementation
{$R *.dfm}
uses Main, Helper_ValueEdit;

procedure TForm_RawEdit.NewFile(fileinfo: TFileInfo);
var
  offsets: TRawList;
  i: Integer;
begin
  if fileinfo.ID >= 0 then
  begin
    if hex.Modified then
      if not Save then
        Exit;
    ClearValues;
    hex.DataSize := 0;
    fileid := fileinfo.ID;
    list_offset.Enabled := False;
    if fileinfo.size > 0 then
    begin
      offsets := Connection.GetRawList(fileid);
      list_offset.Items.Clear;
      if Length(offsets) > 0 then
        for i := 0 to High(offsets) do
          list_offset.Items.Add('0x' + IntToHex(offsets[i].src_offset, 8) +
                ', ' + IntToStr(offsets[i].raw_size) + ' bytes');
      list_offset.Enabled := True;
    end;
  end
  else
  begin
    ClearValues;
    hex.DataSize := 0;
    fileid := -1;
    list_offset.Items.Clear;
  end;
end;

procedure TForm_RawEdit.LoadRaw(raw_info: TRawInfo);
var
  i:    LongWord;
  Data: Tdata;
begin
  if hex.Modified then
  begin
    if not Save then
    begin
      Exit;
    end;
  end;
  if list_offset.Count = 0 then
  begin
    for i := 0 to filelist.Count - 1 do
    begin
      if Connection.ExtractFileID(filelist.Items.Strings[i]) = raw_info.src_id then
      begin
        filelist.ItemIndex := i;
        listClick(Self);
        Break;
      end;
    end;
    for i := 0 to list_offset.Count - 1 do
    begin
      if MidStr(list_offset.Items.Strings[i], 3, 8) = IntToHex(raw_info.src_offset, 8) then
      begin
        list_offset.ItemIndex := i;
        Break;
      end;
    end;
  end;
  SetLength(Data, raw_info.raw_size);
  Connection.LoadRawFile(raw_info.src_id, raw_info.src_offset, @Data[0]);
  if Length(Data) > 0 then
  begin
    hex.DataSize := 0;
    hex.DataSize := raw_info.raw_size;
    for i := 0 to High(Data) do
      hex.Data[i] := Data[i];
    //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
    //      structs.Height:=structs.RowCount*20;
    //      IF structs.Height>120 THEN structs.Height:=120;
    hexSelectionChanged(Self);
    fileid_opened     := raw_info.src_id;
    dat_offset_opened := raw_info.src_offset;
    hex.Modified      := False;
  end
  else
  begin
    ClearValues;
    hex.DataSize := 0;
  end;
end;






procedure TForm_RawEdit.list_offsetClick(Sender: TObject);
begin
  ClearValues;
  dat_offset := StrToInt('$' + MidStr(
    list_offset.Items.Strings[list_offset.ItemIndex], 3, 8));
  LoadRaw(Connection.GetRawInfo(fileid, dat_offset));
end;




function IntToBin(Value: Byte): String;
var
  i: Byte;
begin
  Result := '';
  for i := 7 downto 0 do
  begin
    Result := Result + IntToStr((Value shr i) and $01);
  end;
end;




function TForm_RawEdit.GetValue(datatype: Word; offset: LongWord): String;
var
  Data: Tdata;
  i:    Word;
  floatformat: TFormatSettings;
begin
  floatformat.DecimalSeparator := '.';
  case datatype of
    1:
      Result := IntToStr(hex.Data[offset]);
    2:
      Result := IntToStr(hex.Data[offset] + hex.Data[offset + 1] * 256);
    3:
      Result := IntToStr(hex.Data[offset] + hex.Data[offset + 1] * 256 + hex.Data[offset + 2] * 256 * 256);
    4:
      Result := IntToStr(hex.Data[offset] + hex.Data[offset + 1] * 256 + hex.Data[offset + 2] *
        256 * 256 + hex.Data[offset + 3] * 256 * 256 * 256);
    5:
      Result := '0x' + IntToHex(hex.Data[offset], 2);
    6:
      Result := '0x' + IntToHex(hex.Data[offset] + hex.Data[offset + 1] * 256, 4);
    7:
      Result := '0x' + IntToHex(hex.Data[offset] + hex.Data[offset + 1] * 256 +
        hex.Data[offset + 2] * 256 * 256, 6);
    8:
      Result := '0x' + IntToHex(hex.Data[offset] + hex.Data[offset + 1] * 256 +
        hex.Data[offset + 2] * 256 * 256 + hex.Data[offset + 3] * 256 * 256 * 256, 8);
    9:
    begin
      SetLength(Data, 4);
      Data[0] := hex.Data[offset];
      Data[1] := hex.Data[offset + 1];
      Data[2] := hex.Data[offset + 2];
      Data[3] := hex.Data[offset + 3];
      Result  := FloatToStr(Decode_Float(Data), floatformat);
    end;
    10:
      Result := IntToBin(hex.Data[offset]);
    11:
      Result := '0x' + IntToHex(hex.Data[offset] + hex.Data[offset + 1] * 256 +
        hex.Data[offset + 2] * 256 * 256 + hex.Data[offset + 3] * 256 * 256 * 256, 8);
    10000..65535:
    begin
      Result := '';
      for i := 1 to datatype - 10000 do
      begin
        if hex.Data[offset + i - 1] >= 32 then
          Result := Result + Chr(hex.Data[offset + i - 1])
        else
          Result := Result + '.';
      end;
    end;
  end;
end;




procedure TForm_RawEdit.ClearValues;
var
  i: Byte;
begin
  for i := 1 to value_viewer.RowCount - 1 do
  begin
    value_viewer.Cells[1, i] := '';
  end;
end;




procedure TForm_RawEdit.WriteValues;
var
  i, j:  Integer;
  Data:  Tdata;
  str:   String;
  Value: LongWord;
  floatformat: TFormatSettings;
begin
  floatformat.DecimalSeparator := '.';
  for i := 1 to value_viewer.RowCount - 1 do
  begin
    if value_viewer.Cells[0, i] = '1 byte, unsigned' then
    begin
      if ((hex.SelCount = 1) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 1) > hex.DataSize) then
      begin
        Value := hex.Data[hex.SelStart];
        value_viewer.Cells[1, i] := IntToStr(Value) + ' / 0x' + IntToHex(Value, 2);
      end
      else
        value_viewer.Cells[1, i] := '';
    end;
    if value_viewer.Cells[0, i] = '2 bytes, unsigned' then
    begin
      if ((hex.SelCount = 2) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 2) > hex.DataSize) then
      begin
        Value := hex.Data[hex.SelStart] + hex.Data[hex.SelStart + 1] * 256;
        value_viewer.Cells[1, i] := IntToStr(Value) + ' / 0x' + IntToHex(Value, 4);
      end
      else
        value_viewer.Cells[1, i] := '';
    end;
    if value_viewer.Cells[0, i] = '4 bytes, unsigned' then
    begin
      if ((hex.SelCount = 4) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 4) > hex.DataSize) then
      begin
        Value := hex.Data[hex.SelStart] + hex.Data[hex.SelStart + 1] * 256 +
          hex.Data[hex.SelStart + 2] * 256 * 256 + hex.Data[hex.SelStart + 3] * 256 * 256 * 256;
        value_viewer.Cells[1, i] := IntToStr(Value) + ' / 0x' + IntToHex(Value, 8);
      end
      else
        value_viewer.Cells[1, i] := '';
    end;
    if value_viewer.Cells[0, i] = 'Bitset' then
    begin
      if (hex.SelCount <= 8) then
      begin
        if hex.SelCount = 0 then
        begin
          SetLength(Data, 1);
          Data[0] := hex.Data[hex.SelStart];
        end
        else
        begin
          SetLength(Data, hex.SelCount);
          for j := 0 to hex.SelCount - 1 do
            Data[j] := hex.Data[hex.SelStart + j];
        end;
        value_viewer.Cells[1, i] := DataToBin(Data);
      end
      else
        value_viewer.Cells[1, i] := '';
    end;
    if value_viewer.Cells[0, i] = 'Float' then
    begin
      if ((hex.SelCount = 4) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 4) > hex.DataSize) then
      begin
        SetLength(Data, 4);
        for j := 0 to 3 do
          Data[j] := hex.Data[hex.SelStart + j];
        value_viewer.Cells[1, i] := FloatToStr(Decode_Float(Data), floatformat);
      end
      else
        value_viewer.Cells[1, i] := '';
    end;
    if value_viewer.Cells[0, i] = 'Selected length' then
    begin
      value_viewer.Cells[1, i] := IntToStr(hex.SelCount) + ' bytes';
    end;
    if value_viewer.Cells[0, i] = 'String' then
    begin
      j   := 0;
      str := '';
      if hex.SelCount = 0 then
      begin
        while (hex.Data[hex.SelStart + j] > 0) and ((hex.SelStart + j) < hex.DataSize) do
        begin
          if hex.Data[hex.selstart + j] >= 32 then
            str := str + Char(hex.Data[hex.SelStart + j])
          else
            str := str + '.';
          Inc(j);
        end;
      end
      else
      begin
        for j := 0 to hex.SelCount - 1 do
          if hex.Data[hex.selstart + j] >= 32 then
            str := str + Char(hex.Data[hex.SelStart + j])
          else if hex.Data[hex.selstart + j] > 0 then
            str := str + '.'
          else
            Break;
      end;
      value_viewer.Cells[1, i] := str;
    end;
  end;
end;




procedure TForm_RawEdit.FormCreate(Sender: TObject);
var
  i:     LongWord;
  exts: String;
begin
  inherited;
  Self.OnNewFileSelected := Self.NewFile;

  exts := '';
  if Length(RawListHandlers) > 0 then
  begin
    for i := 0 to High(RawListHandlers) do
      if Length(exts) > 0 then
        exts := exts + ',' + RawListHandlers[i].Ext
      else
        exts := RawListHandlers[i].Ext;
  end;
  Self.AllowedExts := exts;

  Self.Caption := '';
  fileid     := -1;

{
  value_viewer.ColCount := 2;
  value_viewer.RowCount := 8;
}
  value_viewer.FixedRows := 1;
  value_viewer.FixedCols := 1;
  value_viewer.Cells[0, 0] := 'Type';
  value_viewer.Cells[1, 0] := 'Value';
  value_viewer.Cells[0, 1] := '1 byte, unsigned';
  value_viewer.Cells[0, 2] := '2 bytes, unsigned';
  value_viewer.Cells[0, 3] := '4 bytes, unsigned';
  value_viewer.Cells[0, 4] := 'Bitset';
  value_viewer.Cells[0, 5] := 'Float';
  value_viewer.Cells[0, 6] := 'String';
  value_viewer.Cells[0, 7] := 'Selected length';
  value_viewer.ColWidths[0] := 125;
  value_viewer.ColWidths[1] := 1000;
  //
  value_viewer.Font.Charset := AppSettings.CharSet;
  //
end;




function TForm_RawEdit.Save: Boolean;
var
  mem:  TMemoryStream;
  Data: Tdata;
  i:    LongWord;
begin
  case MessageBox(Self.Handle, PChar('Save changes to .raw-part of file ' +
      Connection.GetFileInfo(fileid).FileName + '?'), PChar('Data changed...'),
      MB_YESNOCANCEL) of
    idYes:
    begin
      mem := TMemoryStream.Create;
      hex.SaveToStream(mem);
      mem.Seek(0, soFromBeginning);
      SetLength(Data, mem.Size);
      mem.Read(Data[0], mem.Size);
      mem.Free;
      Connection.UpdateRawFile(fileid_opened, dat_offset_opened,
        Length(Data), @Data[0]);
      hex.Modified := False;
      for i := 0 to hex.Datasize - 1 do
        hex.ByteChanged[i] := False;
      Result := True;
    end;
    idNo:
      Result := True;
    idCancel:
    begin
      Result := False;
    end;
  end;
end;




procedure TForm_RawEdit.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if hex.Modified then
  begin
    if not Save then
      CanClose := False;
  end;
end;




procedure TForm_RawEdit.hexChange(Sender: TObject);
begin
  ClearValues;
  if hex.DataSize > 0 then
  begin
{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
      WriteValues;
}    end;
end;




procedure TForm_RawEdit.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
//var
//  temps: String;
begin
  if (Shift = [ssCtrl]) and (Key = Ord('C')) then
  begin
    if hex.SelCount > 0 then
    begin
      if hex.InCharField then
        Clipboard.AsText := hex.SelectionAsText
      else
        Clipboard.AsText := hex.SelectionAsHex;
    end;
  end;
  if (Shift = [ssCtrl]) and (Key = Ord('V')) then
  begin
{      temps:=Clipboard.AsText;
      IF hex.SelStart+Length(temps)>hex.DataSize THEN
        SetLength(temps, hex.DataSize-hex.SelStart);
      hex.Sel
      hex.SelCount:=Length(temps);
      hex.ReplaceSelection(temps,Length(temps));
}    end;
end;




procedure TForm_RawEdit.hexSelectionChanged(Sender: TObject);
//var
//  selstart: Integer;
//  i, j:     Word;
begin
{    FOR i:=1 TO structs.RowCount-1 DO BEGIN
      FOR j:=0 TO structs.ColCount-1 DO BEGIN
        structs.CellColors[j,i]:=clWhite;
        structs.CellFontColors[j,i]:=clBlack;
      END;
    END;
}    if hex.DataSize > 0 then
  begin
{      selstart:=hex.SelStart;
      IF GetStructureInfoId(GetFileInfo(fileid).Extension)>=0 THEN BEGIN
        WITH structure_infos[GetStructureInfoId(GetFileInfo(fileid).Extension)] DO BEGIN
          FOR i:=0 TO High(entries) DO BEGIN
            IF ((selstart-entries[i].offset)<GetTypeDataLength(entries[i].datatype)) AND ((selstart-entries[i].offset)>=0) THEN BEGIN
              FOR j:=0 TO structs.ColCount-1 DO BEGIN
                structs.CellColors[j,i+1]:=clBlue;
                structs.CellFontColors[j,i+1]:=clWhite;
              END;
              structs.Row:=i+1;
            END;
          END;
        END;
      END;
}      WriteValues;
  end;
end;





procedure TForm_RawEdit.btn_exportClick(Sender: TObject);
var
  fs: TFileStream;
begin
  saved.Filter     := 'Files of matching extension (*.' + Connection.GetFileInfo(
    fileid).Extension + ')|*.' + Connection.GetFileInfo(fileid).Extension +
    '|All files|*.*';
  saved.DefaultExt := Connection.GetFileInfo(fileid).Extension;
  if saved.Execute then
  begin
    fs := TFileStream.Create(saved.FileName, fmCreate);
    hex.SaveToStream(fs);
    fs.Free;
  end;
end;




procedure TForm_RawEdit.btn_importClick(Sender: TObject);
var
//  Data: Tdata;
  fs:   TFileStream;
begin
  opend.Filter := 'Files of matching extension (*.' + Connection.GetFileInfo(
    fileid).Extension + ')|*.' + Connection.GetFileInfo(fileid).Extension +
    '|All files|*.*';
  if opend.Execute then
  begin
    fs := TFileStream.Create(opend.FileName, fmOpenRead);
    if fs.Size <> hex.DataSize then
    begin
      ShowMessage('Can''t import ' + ExtractFilename(opend.FileName) +
        ', file has to have same size as file in .dat.' + CrLf +
        'Size of file in .dat: ' + FormatFileSize(hex.datasize) + CrLf +
        'Size of chosen file: ' + FormatFileSize(fs.Size));
    end
    else
    begin
      hex.LoadFromStream(fs);
      hex.Modified := True;
    end;
    fs.Free;
  end;
end;




procedure TForm_RawEdit.value_viewer_contextPopup(Sender: TObject);
var
  i: Byte;
begin
  for i := 0 to value_viewer_context.Items.Count - 1 do
    value_viewer_context.Items.Items[i].Visible := False;
  with value_viewer do
  begin
    if (Col = 1) and (Row > 0) and (Length(Cells[Col, Row]) > 0) then
    begin
      if Pos(' byte', Cells[0, Row]) = 2 then
      begin
        value_viewer_context.Items.Find('Copy to &clipboard').Visible := True;
        value_viewer_context.Items.Find('Copy to clipboard (as &dec)').Visible := True;
        value_viewer_context.Items.Find('Copy to clipboard (as &hex)').Visible := True;
      end;
      if Pos('Float', Cells[0, Row]) = 1 then
        value_viewer_context.Items.Find('Copy to clipboard (as &float)').Visible := True;
      if Pos('Bitset', Cells[0, Row]) = 1 then
        value_viewer_context.Items.Find(
          'Copy to clipboard (as &bitset)').Visible := True;
      if Pos('String', Cells[0, Row]) = 1 then
        value_viewer_context.Items.Find(
          'Copy to clipboard (as &string)').Visible := True;
      if Pos('Selected length', Cells[0, Row]) = 1 then
        value_viewer_context.Items.Find('Copy to &clipboard').Visible := True;
    end;
  end;
end;




procedure TForm_RawEdit.value_viewerMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  ACol, ARow: Integer;
begin
  if Button = mbRight then
  begin
    value_viewer.MouseToCell(x, y, ACol, ARow);
    if ARow > 0 then
    begin
      value_viewer.Col := ACol;
      value_viewer.Row := ARow;
    end;
  end;
end;




procedure TForm_RawEdit.value_viewer_context_copyClick(Sender: TObject);
var
//  i:     Byte;
  Name:  String;
  Value: LongWord;
begin
  Name := TMenuItem(Sender).Name;
  if Pos('asstring', Name) > 0 then
  begin
    Clipboard.AsText := value_viewer.Cells[value_viewer.Col, value_viewer.Row];
  end
  else if Pos('asfloat', Name) > 0 then
  begin
    Clipboard.AsText := value_viewer.Cells[value_viewer.Col, value_viewer.Row];
  end
  else if Pos('asbitset', Name) > 0 then
  begin
    Clipboard.AsText := value_viewer.Cells[value_viewer.Col, value_viewer.Row];
  end
  else if (Pos('ashex', Name) > 0) or (Pos('asdec', Name) > 0) then
  begin
    if value_viewer.Cells[0, value_viewer.Row] = '1 byte, unsigned' then
    begin
      if ((hex.SelCount = 1) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 1) > hex.DataSize) then
        Value := hex.Data[hex.SelStart];
    end;
    if value_viewer.Cells[0, value_viewer.Row] = '2 bytes, unsigned' then
    begin
      if ((hex.SelCount = 2) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 2) > hex.DataSize) then
        Value := hex.Data[hex.SelStart] + hex.Data[hex.SelStart + 1] * 256;
    end;
    if value_viewer.Cells[0, value_viewer.Row] = '4 bytes, unsigned' then
    begin
      if ((hex.SelCount = 4) or (hex.SelCount = 0)) and not
        ((hex.SelStart + 4) > hex.DataSize) then
        Value := hex.Data[hex.SelStart] + hex.Data[hex.SelStart + 1] * 256 +
          hex.Data[hex.SelStart + 2] * 256 * 256 + hex.Data[hex.SelStart + 3] * 256 * 256 * 256;
    end;
    if Pos('asdec', Name) > 0 then
    begin
      Clipboard.AsText := IntToStr(Value);
    end
    else
    begin
      if value_viewer.Cells[0, value_viewer.Row] = '1 byte, unsigned' then
        Clipboard.AsText := '0x' + IntToHex(Value, 2);
      if value_viewer.Cells[0, value_viewer.Row] = '2 bytes, unsigned' then
        Clipboard.AsText := '0x' + IntToHex(Value, 4);
      if value_viewer.Cells[0, value_viewer.Row] = '4 bytes, unsigned' then
        Clipboard.AsText := '0x' + IntToHex(Value, 8);
    end;
  end
  else
  begin
    Clipboard.AsText := value_viewer.Cells[value_viewer.Col, value_viewer.Row];
  end;
end;




procedure TForm_RawEdit.SetNewValue(datatype: Word; offset: LongWord; Value: String);
var
  Data: Tdata;
  value_int: LongWord;
  value_float: Single;
  i: Word;
begin
  case datatype of
    1..4:
    begin
      value_int := StrToInt(Value);
      SetLength(Data, datatype);
      for i := 0 to datatype - 1 do
      begin
        Data[i]   := value_int mod 256;
        value_int := value_int div 256;
      end;
    end;
    5..8:
    begin
      value_int := StrToInt('$' + Value);
      SetLength(Data, datatype - 4);
      for i := 0 to datatype - 5 do
      begin
        Data[i]   := value_int mod 256;
        value_int := value_int div 256;
      end;
    end;
    9:
    begin
      value_float := StrToFloat(Value);
      Data := Encode_Float(value_float);
    end;
    10:
    begin
      value_int := BinToInt(Value);
      SetLength(Data, 1);
      Data[0] := value_int;
    end;
    10000..65535:
    begin
      SetLength(Data, datatype - 10000);
      for i := 1 to datatype - 10000 do
      begin
        if i <= Length(Value) then
          Data[i - 1] := Ord(Value[i])
        else
          Data[i - 1] := 0;
      end;
    end;
  end;
  for i := 0 to High(Data) do
  begin
    if hex.Data[offset + i] <> Data[i] then
      hex.ByteChanged[offset + i] := True;
    hex.Data[offset + i] := Data[i];
  end;
  hex.Modified := True;
  hexChange(Self);
  hex.Repaint;
end;




procedure TForm_RawEdit.value_viewerDblClick(Sender: TObject);
var
  offset:     LongWord;
  datatype:   Word;
  objectname: String;
  Value:      String;
begin
  if (value_viewer.Col = 1) and (Length(value_viewer.Cells[1, value_viewer.Row]) > 0) then
  begin
    offset := hex.SelStart;
    if value_viewer.Cells[0, value_viewer.Row] = '1 byte, unsigned' then
      datatype := 1;
    if value_viewer.Cells[0, value_viewer.Row] = '2 bytes, unsigned' then
      datatype := 2;
    if value_viewer.Cells[0, value_viewer.Row] = '4 bytes, unsigned' then
      datatype := 4;
    if value_viewer.Cells[0, value_viewer.Row] = 'Bitset' then
      datatype := 10;
    if value_viewer.Cells[0, value_viewer.Row] = 'Float' then
      datatype := 9;
    if value_viewer.Cells[0, value_viewer.Row] = 'Selected length' then
      Exit;
    if value_viewer.Cells[0, value_viewer.Row] = 'String' then
    begin
      if hex.SelCount > 0 then
        datatype := 10000 + hex.SelCount
      else
        datatype := 10000 + Length(value_viewer.Cells[1, value_viewer.Row]);
    end;
    objectname := '';
    Value      := GetValue(datatype, offset);
    Form_ValueEdit.MakeVarInput(objectname, offset, datatype, Value, Self);
  end;
end;




procedure TForm_RawEdit.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if (Shift = [ssCtrl]) and (Key = 83) then
    if hex.Modified then
      if not Save then
        Exit;
end;

begin
  AddToolListEntry('rawedit', 'Binary .raw-Editor', '');
end.