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); procedure panel_contentResize(Sender: TObject); 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: LongWord; 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 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 := OniDataConnection.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; 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 OniDataConnection.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); OniDataConnection.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); var i: LongWord; raw_info: TRawInfo; begin ClearValues; dat_offset := StrToInt('$' + MidStr( list_offset.Items.Strings[list_offset.ItemIndex], 3, 8)); LoadRaw(OniDataConnection.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; begin 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)); 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: Byte; Data: Tdata; str: String; Value: LongWord; begin 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)); 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.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] := 100; // 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 ' + OniDataConnection.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; OniDataConnection.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.panel_contentResize(Sender: TObject); begin // value_viewer.ColWidths[1] := value_viewer.Width - value_viewer.ColWidths[0] - 28; 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)=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 (*.' + OniDataConnection.GetFileInfo( fileid).Extension + ')|*.' + OniDataConnection.GetFileInfo(fileid).Extension + '|All files|*.*'; saved.DefaultExt := OniDataConnection.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 (*.' + OniDataConnection.GetFileInfo( fileid).Extension + ')|*.' + OniDataConnection.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.