unit RawEdit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Template, StdCtrls, ExtCtrls, Menus, Grids, Wrapgrid, MPHexEditor, Clipbrd, StrUtils, TypeDefs, Data, Functions, DatStructureLoader, ConnectionManager, 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: TRawDataInfo); 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: Integer): String; procedure ClearValues; procedure WriteValues; procedure SetNewValue(datatype: Word; offset: Integer; 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, datoffset: Integer; public end; var Form_RawEdit: TForm_RawEdit; implementation {$R *.dfm} uses Main, ValueEdit, RawList; procedure TForm_RawEdit.NewFile(fileinfo: TFileInfo); var offsets: TRawDataList; 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 := ConManager.Connection[ConnectionID].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].SrcOffset, 8) + ', ' + IntToStr(offsets[i].RawSize) + ' 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: TRawDataInfo); var i: Integer; begin if hex.Modified then begin if not Save then begin Exit; end; end; for i := 0 to filelist.Count - 1 do begin if ConManager.Connection[ConnectionID].ExtractFileIDOfName(filelist.Items.Strings[i]) = Raw_Info.SrcID 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.SrcOffset, 8) then begin list_offset.ItemIndex := i; list_offsetClick(Self); Break; end; end; end; procedure TForm_RawEdit.list_offsetClick(Sender: TObject); var mem: TMemoryStream; rawinfo: TRawDataInfo; begin datoffset := StrToInt('$' + MidStr( list_offset.Items.Strings[list_offset.ItemIndex], 3, 8)); rawinfo := ConManager.Connection[ConnectionID].GetRawInfo(fileid, datoffset); mem := nil; ConManager.Connection[ConnectionID].LoadRawFile(rawinfo.SrcID, rawinfo.SrcOffset, TStream(mem)); hex.LoadFromStream(mem); ClearValues; hexSelectionChanged(Self); end; function TForm_RawEdit.GetValue(datatype: Word; offset: Integer): String; var Data: TByteData; 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 value_viewer.Cells[1, i] := ''; end; procedure TForm_RawEdit.WriteValues; var i, j: Integer; Data: TByteData; str: String; Value: Integer; 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.SelStart + j) < hex.DataSize do begin if hex.Data[hex.SelStart + j] = 0 then Break; 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: Integer; exts: String; begin inherited; Self.OnNewFileSelected := Self.NewFile; exts := ''; if Length(RawLists.RawListHandlers) > 0 then begin for i := 0 to High(RawLists.RawListHandlers) do if Length(exts) > 0 then exts := exts + ',' + RawLists.RawListHandlers[i].Ext else exts := RawLists.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; i: Integer; begin case MessageBox(Self.Handle, PChar('Save changes to .raw-part of file ' + ConManager.Connection[ConnectionID].GetFileInfo(fileid).Name + '?'), PChar('Data changed...'), MB_YESNOCANCEL) of idYes: begin mem := TMemoryStream.Create; hex.SaveToStream(mem); mem.Seek(0, soFromBeginning); ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, mem); mem.Free; hex.Modified := False; for i := 0 to hex.Datasize - 1 do hex.ByteChanged[i] := False; Result := True; end; idNo: Result := True; idCancel: Result := False; end; end; procedure TForm_RawEdit.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if hex.Modified then if not Save then CanClose := False; 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 (*.' + ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + ')|*.' + ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + '|All files|*.*'; saved.DefaultExt := ConManager.Connection[ConnectionID].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; i: Integer; rawinfo: TRawDataInfo; begin opend.Filter := 'Files of matching extension (*.' + ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + ')|*.' + ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + '|All files|*.*'; if opend.Execute then begin fs := TFileStream.Create(opend.FileName, fmOpenRead); if fs.Size <> hex.DataSize then begin if (not (CR_ResizeRaw in ConManager.Connection[ConnectionID].ChangeRights)) and (not (CR_AppendRaw in ConManager.Connection[ConnectionID].ChangeRights)) then begin ShowMessage('Can''t import ' + ExtractFilename(importd.FileName) + ', file has to have same size as file in .raw with this backend.' + CrLf + 'Size of file in .raw: ' + FormatFileSize(hex.DataSize) + CrLf + 'Size of chosen file: ' + FormatFileSize(fs.Size)); Exit; end else begin if MessageBox(Self.Handle, PChar('File has different size from the file in the .raw.' + CrLf + 'Size of file in .dat: ' + FormatFileSize(hex.DataSize) + CrLf + 'Size of chosen file: ' + FormatFileSize(fs.Size) + CrLf + 'Replace anyway?' + CrLf + 'WARNING: This only replaces the raw-data. It doesn''t' + CrLf + 'do the according changes in the .dat. Oni probably' + CrLf + 'won''t be able to use the data correctly!'), PChar('Different size'), MB_YESNO + MB_ICONWARNING) = ID_NO then begin Exit; end; end; rawinfo := ConManager.Connection[ConnectionID].GetRawInfo(fileid, datoffset); if CR_ResizeRaw in ConManager.Connection[ConnectionID].ChangeRights then ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, fs) else if CR_AppendRaw in ConManager.Connection[ConnectionID].ChangeRights then i := ConManager.Connection[ConnectionID].AppendRawFile(rawinfo.LocSep, fs); ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, datoffset, 4, @i); end else begin ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, fs); end; fs.Seek(0, soFromBeginning); hex.LoadFromStream(fs); hex.Modified := False; for i := 0 to hex.Datasize - 1 do hex.ByteChanged[i] := False; 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: Integer; 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: Integer; Value: String); var Data: TByteData; 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: Integer; 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.