⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 observerhexeditor.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
//                                                                  //
// observerHexEditor.pas: Memory viewer and editor                  //
//                                                                  //
// The contents of this file are subject to the Bottled Light       //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a     //
// copy of the License at http://www.bottledlight.com/BLPL/         //
//                                                                  //
// Software distributed under the License is distributed on an      //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   //
// implied. See the License for the specific language governing     //
// rights and limitations under the License.                        //
//                                                                  //
// The Original Code is the Mappy VM User Interface, released       //
// April 1st, 2003. The Initial Developer of the Original Code is   //
// Bottled Light, Inc. Portions created by Bottled Light, Inc. are  //
// Copyright (C) 2001-2003 Bottled Light, Inc. All Rights Reserved. //
//                                                                  //
// Author(s):                                                       //
//   Michael Noland (joat), michael@bottledlight.com                //
//                                                                  //
// Changelog:                                                       //
//   1.0: First public release (April 1st, 2003)                    //
//                                                                  //
// Notes:                                                           //
//   None at present.                                               //
//                                                                  //
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
unit observerHexEditor; //////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IniFiles, CpuObservers, Menus, debugFindPattern,
  Math, console, nexus, AddressSpace, ComCtrls, ToolWin;

//////////////////////////////////////////////////////////////////////

type
  THexEditorMode = (hemStream, hemByte, hemHalfword, hemWord);

  TjdevHexEditor = class(TCpuObserver)
    scrollbar: TScrollBar;
    popupMenu: TPopupMenu;
    mBrowseTo: TMenuItem;
    mReturntoPC: TMenuItem;
    N2: TMenuItem;
    mDisplayBIOS: TMenuItem;
    mDisplayExWRAM: TMenuItem;
    mDisplayWRAM: TMenuItem;
    mDisplayPalette: TMenuItem;
    mDisplayOAM: TMenuItem;
    mDisplayVRAM: TMenuItem;
    mDisplayROM: TMenuItem;
    editor: TEdit;
    mViewStack: TMenuItem;
    mDisplaySRAM: TMenuItem;
    saveDialog: TSaveDialog;
    openDialog: TOpenDialog;
    toolbar: TToolBar;
    Spacer1: TToolButton;
    rbByte: TRadioButton;
    rbHalfword: TRadioButton;
    rbWord: TRadioButton;
    Spacer2: TToolButton;
    eAddress: TComboBox;
    bGoto: TToolButton;
    rbStream: TRadioButton;
    bTools: TToolButton;
    mFindPattern: TMenuItem;
    mFindAgain: TMenuItem;
    N1: TMenuItem;
    mLoadIntoMemory: TMenuItem;
    mSaveMemory: TMenuItem;
    N3: TMenuItem;
    bHelp: TToolButton;
    bFind: TToolButton;
    fontDialog: TFontDialog;
    N4: TMenuItem;
    mChangeFont: TMenuItem;

    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);

    procedure scrollbarChange(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure editorKeyPress(Sender: TObject; var Key: Char);

    procedure ChangeDisplayMode(Sender: TObject);
    procedure ChangeCurrentBank(Sender: TObject);
    procedure GotoAddress(Sender: TObject);
    procedure addressKeyPress(Sender: TObject; var Key: Char);

    procedure BrowseTo(Sender: TObject);
    procedure ReturnToPC(Sender: TObject);
    procedure ReturnToSP(Sender: TObject);
    procedure DisplayBIOS(Sender: TObject);
    procedure DisplayExWRAM(Sender: TObject);
    procedure DisplayWRAM(Sender: TObject);
    procedure DisplayPalette(Sender: TObject);
    procedure DisplayVRAM(Sender: TObject);
    procedure DisplayOAM(Sender: TObject);
    procedure DisplayROM(Sender: TObject);
    procedure DisplaySRAM(Sender: TObject);
    procedure LoadRawMemory(Sender: TObject);
    procedure SaveRawMemory(Sender: TObject);
    procedure FindPattern(Sender: TObject);
    procedure FindPatternAgain(Sender: TObject);
    procedure ShowMenu(Sender: TObject);
    procedure ShowHelp(Sender: TObject);
    procedure ChangeFont(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  protected
    FEditingAt: uint32;
    findingAgain: boolean;
    baseAddress: uint32;

    fontString: string;
    displayMode: THexEditorMode;

    procedure FinishEditing;
    procedure SetAddress(addr: uint32);
  public
    procedure UpdateObserver; override;
    class function OCaption: string; override;
    procedure LoadSettings(ini: TIniFile); override;
    procedure SaveSettings(ini: TIniFile); override;
  end;

//////////////////////////////////////////////////////////////////////

var
  jdevHexEditor: TjdevHexEditor;

//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

{$R *.DFM}

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormCreate(Sender: TObject);
begin
  HelpContext := LinkHelp('memory_editor.html');
  editor.visible := false;
  findingAgain := false;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormShow(Sender: TObject);
begin
  eAddress.Text := '$' + IntToHex(vmCurrentPC, 8);
  SetAddress(vmCurrentPC);
  if fontString <> '' then StringToFont(fontString, Font);

  // Load the translation
  LoadTranslation(self, translation);
end;

//////////////////////////////////////////////////////////////////////

class function TjdevHexEditor.OCaption: string;
begin
  Result := 'Memory Editor';
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.UpdateObserver;
var
  addr: uint32;
  i, y: integer;
  data: array[0..16] of byte;
  st: string;
  mirror: boolean;
  numLines: integer;
  cartSize1, cartSize2: uint32;
  banks: TvmMemoryLock1;
begin
  Constraints.MinWidth := 0;
  Constraints.MaxWidth := 0;
  case displayMode of
    hemStream: ClientWidth := canvas.TextWidth('@')*(28 + 32) + scrollbar.width;
    hemByte: ClientWidth := canvas.TextWidth('@')*(28 + 47) + scrollbar.width;
    hemHalfword: ClientWidth := canvas.TextWidth('@')*(28 + 39) + scrollbar.width;
    hemWord: ClientWidth := canvas.TextWidth('@')*(28 + 35) + scrollbar.width;
  end;
  Constraints.MinWidth := Width;
  Constraints.MaxWidth := Width;

  numLines := 0;
  y := toolbar.height;
  addr := baseAddress;
  while (y < clientHeight) and (addr < $10000000) do begin
    st := IntToHex(addr, 8) + ' ';
    // addr := addr and $0FFFFFFF;

    vmLockMemory(banks);
    cartSize1 := Min(banks.romsize, 1 shl 24);
    cartSize2 := banks.romsize - cartSize1;
    vmUnlockMemory(banks);

    case (addr shr 24) and $F of
      $0,$1: mirror := addr >= $00000000 + SYSTEM_ROM_MASK;
      $2: mirror := addr > $02000000 + EX_WRAM_MASK;
      $3: mirror := addr > $03000000 + WRAM_MASK;
      $5: mirror := addr > $05000000 + PALETTE_MASK;
      $6: mirror := addr >= $06014000;
      $7: mirror := addr > $07000000 + OAM_MASK;
      $8: mirror := addr >= $08000000 + cartSize1;
      $A: mirror := addr >= $0A000000 + cartSize1;
      $C: mirror := addr >= $0C000000 + cartSize1;
      $9: mirror := addr >= $09000000 + cartSize2;
      $B: mirror := addr >= $0B000000 + cartSize2;
      $D: mirror := addr >= $0D000000 + cartSize2;
      $E: mirror := addr > $0E000000 + SRAM_MASK;
      $F: mirror := addr > $0F000000 + SRAM_MASK;
    else
      mirror := false;
    end;

    canvas.brush.Color := clBtnFace;
    if mirror then
      canvas.Font.Color := clGrayText
    else
      canvas.Font.Color := clBtnText;

    // Get the data
    case displayMode of
      hemStream: begin
        st := st + ' ';
        for i := 0 to 15 do begin
          data[i] := vmReadByte(addr);
          Inc(addr);
          st := st + IntToHex(data[i], 2);
        end;
      end;

      hemByte: for i := 0 to 15 do begin
        data[i] := vmReadByte(addr);
        Inc(addr);
        st := st + ' ' + IntToHex(data[i], 2);
      end;

      hemHalfword: for i := 0 to 15 do begin
        data[i] := vmReadByte(addr);
        Inc(addr);
        if i and 1 = 1 then st := st + ' ' + IntToHex(Puint16(@(data[i and not 1]))^, 4);
      end;

      hemWord: for i := 0 to 15 do begin
        data[i] := vmReadByte(addr);
        Inc(addr);
        if i and 3 = 3 then st := st + ' ' + IntToHex(Puint32(@(data[i and not 3]))^, 8);
      end;
    end;

    // Add the ASCII dump on the right
    for i := 0 to 15 do if data[i] < 32 then data[i] := Ord('.');
    data[16] := 0;
    st := st + '  ' + Pchar(@(data[0]));

    // Draw it
    canvas.TextOut(0, y, st);
    y := y + canvas.TextHeight(st);
    Inc(numLines);
  end;
  scrollbar.LargeChange := Max(numLines-1, 1)*16;

  if (addr > $10000000) and (st <> '') then begin
    numLines := Height div canvas.TextHeight(st)-1;
    baseAddress := $10000000 - uint32(Max(numLines, 1)*16);
    Repaint;
  end;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormPaint(Sender: TObject);
begin
//  Font.Assign(hexEditorFont);
//  editor.Font.Assign(hexEditorFont);
  if not editor.visible then editor.Top := -editor.height;
  editor.Width := canvas.TextWidth('@')*2;
  editor.Height := canvas.TextHeight('@');
  UpdateObserver;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormResize(Sender: TObject);
begin
  UpdateObserver;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  SetAddress(Min(scrollbar.Position + 16, scrollbar.Max));
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  SetAddress(Max(scrollbar.Position - 16, scrollbar.Min));
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.SetAddress(addr: uint32);
begin
  scrollbar.Position := addr and $0FFFFFF0;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.scrollbarChange(Sender: TObject);
begin
  if uint32(scrollbar.Position) <> baseAddress then FinishEditing;
  baseAddress := scrollbar.Position;
  UpdateObserver;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  w, h: integer;
begin
  if editor.visible then
    FinishEditing
  else if Button = mbLeft then begin
    w := canvas.TextWidth('@');
    h := canvas.TextHeight('@');

    Y := (Y-toolbar.height) div h;
    X := X div w - 10;
    case displayMode of
      hemStream: begin
        X := X div 2;

        if (X >= 0) and (X < 16) then begin
          FEditingAt := baseAddress + uint32(Y*16 + X);
          editor.text := '';
          editor.Left := (X*2+10)*w;
          editor.Top := h*Y + toolbar.height;
          editor.Visible := true;
        end;
      end;

      hemByte: if X and 3 <> 3 then begin
        X := X div 3;
        if (X >= 0) and (X < 16) then begin
          FEditingAt := baseAddress + uint32(Y*16 + X);
          editor.text := '';
          editor.Left := (X*3+10)*w;
          editor.Top := h*Y + toolbar.height;
          editor.Visible := true;
        end;
      end;

      hemHalfword: if X mod 5 <> 4 then begin
        X := (X-((X+1) div 5)) div 2;
        if (X >= 0) and (X < 16) then begin
          FEditingAt := baseAddress + uint32(Y*16 + X xor 1);
          editor.text := '';
          editor.Left := ((X shr 1)*5 + (X and 1)*2 + 10)*w;
          editor.Top := h*Y + toolbar.height;
          editor.Visible := true;
        end;
      end;

      hemWord: if X mod 9 <> 8 then begin
        X := (X-((X+1) div 9)) div 2;
        if (X >= 0) and (X < 16) then begin
          FEditingAt := baseAddress + uint32(Y*16 + X xor 3);
          editor.text := '';
          editor.Left := ((X shr 2)*9 + (X and 3)*2 + 10)*w;
          editor.Top := h*Y + toolbar.height;
          editor.Visible := true;
        end;
      end;
    end;

  end;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.editorKeyPress(Sender: TObject; var Key: Char);
begin
  if (key = #10) or (key = #13) then begin
    FinishEditing;
    Key := #0;
  end;
end;

//////////////////////////////////////////////////////////////////////

procedure TjdevHexEditor.FinishEditing;
var
  st: string;
begin
  if editor.visible then begin
    st := Trim(editor.Text);
    if (Length(st) > 0) and (st[1] <> '$') then st := '$' + st;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -