zydis/assets/InstructionEditor/Forms/formGenerator.pas

396 lines
12 KiB
Plaintext

unit formGenerator;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, System.ImageList, Vcl.ImgList, cxGraphics,
Vcl.StdCtrls, untInstructionEditor;
type
TfrmGenerator = class(TForm)
GroupBox: TGroupBox;
btnClose: TButton;
btnGenerate: TButton;
imgIcons16: TcxImageList;
TreeView: TVirtualStringTree;
imgTreeView: TcxImageList;
procedure FormCreate(Sender: TObject);
procedure TreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode;
var Allowed: Boolean);
procedure TreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure TreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
procedure TreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: string);
procedure btnCloseClick(Sender: TObject);
procedure btnGenerateClick(Sender: TObject);
procedure TreeViewBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect;
var ContentRect: TRect);
strict private
FEditor: TInstructionEditor;
FProgressNodeTotal: PVirtualNode;
FProgressNode: array[TGeneratorWorkOperation] of PVirtualNode;
FInfoNode: array[0..6] of PVirtualNode;
FCurrentOperation: TGeneratorWorkOperation;
strict private
procedure GeneratorWorkStart(Sender: TObject; Operation: TGeneratorWorkOperation; MinWorkCount,
MaxWorkCount: Integer);
procedure GeneratorWork(Sender: TObject; WorkCount: Integer);
procedure GeneratorWorkEnd(Sender: TObject);
public
property Editor: TInstructionEditor read FEditor write FEditor;
end;
var
frmGenerator: TfrmGenerator;
implementation
uses
untHelperClasses;
{$R *.dfm}
type
TGeneratorNodeType = (ntCategory, ntSpacer, ntOperation, ntValue);
PGeneratorNodeData = ^TGeneratorNodeData;
TGeneratorNodeData = record
public
NodeType: TGeneratorNodeType;
Text: String;
ProgressActive: Boolean;
ProgressMax: Integer;
ProgressUpdateStep: Integer;
Progress: Double;
Value: String;
public
procedure ProgressInit(MaxWorkCount: Integer; MinWorkCount: Integer); inline;
procedure ProgressUpdate(NewProgress: Double); inline;
procedure WorkCountUpdate(WorkCount: Integer); inline;
function IsProgressUpdateStep(WorkCount: Integer): Boolean; inline;
end;
{ TGeneratorNodeData }
function TGeneratorNodeData.IsProgressUpdateStep(WorkCount: Integer): Boolean;
begin
Assert(NodeType = ntOperation);
Result := ((WorkCount mod ProgressUpdateStep) = 0);
end;
procedure TGeneratorNodeData.ProgressInit(MaxWorkCount, MinWorkCount: Integer);
begin
Assert(NodeType = ntOperation);
ProgressMax := (MaxWorkCount - MinWorkCount);
ProgressUpdateStep := Round(ProgressMax / 100) + 1;
end;
procedure TGeneratorNodeData.ProgressUpdate(NewProgress: Double);
var
Format: TFormatSettings;
begin
Assert(NodeType = ntOperation);
Progress := NewProgress;
Format.DecimalSeparator := '.';
Value := FormatFloat('0.00', Progress * 100, Format) + '%';
end;
procedure TGeneratorNodeData.WorkCountUpdate(WorkCount: Integer);
begin
Assert(NodeType = ntOperation);
if (ProgressMax = 0) then
begin
ProgressUpdate(1.0);
end else
begin
ProgressUpdate(WorkCount / ProgressMax);
end;
end;
{ TfrmGenerator }
procedure TfrmGenerator.btnCloseClick(Sender: TObject);
begin
Close;
end;
procedure TfrmGenerator.btnGenerateClick(Sender: TObject);
procedure SetInfoNodeValue(Node: PVirtualNode; const Value: String);
var
NodeData: PGeneratorNodeData;
begin
NodeData := TreeView.GetNodeData(Node);
NodeData^.Value := Value;
end;
var
Generator: TTableGenerator;
Node: PVirtualNode;
NodeData: PGeneratorNodeData;
I: Integer;
begin
TreeView.BeginUpdate;
try
for Node in FProgressNode do
begin
NodeData := TreeView.GetNodeData(Node);
NodeData^.ProgressActive := false;
NodeData^.ProgressUpdate(0);
end;
NodeData := TreeView.GetNodeData(FProgressNodeTotal);
NodeData^.ProgressActive := false;
NodeData^.ProgressUpdate(0);
finally
TreeView.EndUpdate;
end;
Generator := TTableGenerator.Create;
try
Generator.OnWorkStart := GeneratorWorkStart;
Generator.OnWork := GeneratorWork;
Generator.OnWorkEnd := GeneratorWorkEnd;
Generator.GenerateFiles(FEditor,
'D:\Verteron Development\GitHub\zyan-disassembler-engine old\include\Zydis\Internal\');
TreeView.BeginUpdate;
try
for I := Low(FInfoNode) to High(FInfoNode) do
begin
case I of
0: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.FilterCount));
1: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.DefinitionCount));
2: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.MnemonicCount));
3: SetInfoNodeValue(FInfoNode[I], TSizeFormatter.Format(Generator.Statistics.FilterSize));
4: SetInfoNodeValue(FInfoNode[I],
TSizeFormatter.Format(Generator.Statistics.DefinitionSize));
5: SetInfoNodeValue(FInfoNode[I],
TSizeFormatter.Format(Generator.Statistics.MnemonicSize));
6: SetInfoNodeValue(FInfoNode[I], TSizeFormatter.Format(Generator.Statistics.FilterSize
+ Generator.Statistics.DefinitionSize + Generator.Statistics.MnemonicSize));
end;
end;
finally
TreeView.EndUpdate;
end;
Application.ProcessMessages;
finally
Generator.Free;
end;
end;
procedure TfrmGenerator.FormCreate(Sender: TObject);
function AddNodeData(Parent: PVirtualNode; NodeType: TGeneratorNodeType; const Text: String;
const Value: String = ''): PVirtualNode;
var
NodeData: PGeneratorNodeData;
begin
Result := TreeView.AddChild(Parent);
NodeData := TreeView.GetNodeData(Result);
if (Assigned(NodeData)) then
begin
NodeData^.NodeType := NodeType;
NodeData^.Text := Text;
case NodeType of
ntOperation:
begin
NodeData^.ProgressActive := false;
NodeData^.ProgressUpdate(0);
end;
ntValue:
NodeData^.Value := Value;
end;
end;
end;
var
Category: PVirtualNode;
begin
TreeView.NodeDataSize := SizeOf(TGeneratorNodeData);
TreeView.BeginUpdate;
try
Category := AddNodeData(nil, ntCategory, 'Progress');
FProgressNode[woIndexingDefinitions] :=
AddNodeData(Category, ntOperation, 'Indexing definitions');
FProgressNode[woIndexingFilters] :=
AddNodeData(Category, ntOperation, 'Indexing filters');
FProgressNode[woGeneratingFilterFiles] :=
AddNodeData(Category, ntOperation, 'Generating filter files');
FProgressNode[woGeneratingDefinitionFiles] :=
AddNodeData(Category, ntOperation, 'Generating definition files');
FProgressNode[woGeneratingMnemonicFiles] :=
AddNodeData(Category, ntOperation, 'Generating mnemonic files');
FProgressNodeTotal :=
AddNodeData(Category, ntOperation, 'Total progress');
TreeView.Expanded[Category] := true;
AddNodeData(nil, ntSpacer, '');
Category := AddNodeData(nil, ntCategory, 'Statistics');
FInfoNode[0] := AddNodeData(Category, ntValue, 'Filter Count', '-');
FInfoNode[1] := AddNodeData(Category, ntValue, 'Definition Count', '-');
FInfoNode[2] := AddNodeData(Category, ntValue, 'Mnemonic Count', '-');
FInfoNode[3] := AddNodeData(Category, ntValue, 'Filter Size', '-');
FInfoNode[4] := AddNodeData(Category, ntValue, 'Definition Size', '-');
FInfoNode[5] := AddNodeData(Category, ntValue, 'MnemonicSize', '-');
FInfoNode[6] := AddNodeData(Category, ntValue, 'TotalSize', '-');
TreeView.Expanded[Category] := true;
finally
TreeView.EndUpdate;
end;
end;
procedure TfrmGenerator.GeneratorWork(Sender: TObject; WorkCount: Integer);
var
Node: PVirtualNode;
NodeData: PGeneratorNodeData;
ProgressTotal: Double;
begin
NodeData := TreeView.GetNodeData(FProgressNode[FCurrentOperation]);
NodeData^.WorkCountUpdate(WorkCount);
if (NodeData^.IsProgressUpdateStep(WorkCount)) then
begin
TreeView.RepaintNode(FProgressNode[FCurrentOperation]);
ProgressTotal := 0;
for Node in FProgressNode do
begin
NodeData := TreeView.GetNodeData(Node);
ProgressTotal := ProgressTotal + NodeData^.Progress;
end;
NodeData := TreeView.GetNodeData(FProgressNodeTotal);
NodeData^.ProgressUpdate(ProgressTotal / Length(FProgressNode));
TreeView.RepaintNode(FProgressNodeTotal);
Application.ProcessMessages;
end;
end;
procedure TfrmGenerator.GeneratorWorkEnd(Sender: TObject);
var
NodeData: PGeneratorNodeData;
begin
NodeData := TreeView.GetNodeData(FProgressNode[FCurrentOperation]);
NodeData^.ProgressActive := false;
NodeData^.ProgressUpdate(1);
TreeView.RepaintNode(FProgressNode[FCurrentOperation]);
NodeData := TreeView.GetNodeData(FProgressNodeTotal);
if (FCurrentOperation = High(TGeneratorWorkOperation)) then
begin
NodeData^.ProgressActive := false;
end;
NodeData^.ProgressUpdate((Integer(FCurrentOperation) + 1) / Length(FProgressNode));
TreeView.RepaintNode(FProgressNodeTotal);
end;
procedure TfrmGenerator.GeneratorWorkStart(Sender: TObject; Operation: TGeneratorWorkOperation;
MinWorkCount, MaxWorkCount: Integer);
var
NodeData: PGeneratorNodeData;
begin
FCurrentOperation := Operation;
NodeData := TreeView.GetNodeData(FProgressNode[Operation]);
NodeData^.ProgressInit(MaxWorkCount, MinWorkCount);
NodeData^.ProgressActive := true;
TreeView.RepaintNode(FProgressNode[FCurrentOperation]);
NodeData := TreeView.GetNodeData(FProgressNodeTotal);
if (FCurrentOperation = Low(TGeneratorWorkOperation)) then
begin
NodeData^.ProgressActive := true;
TreeView.RepaintNode(FProgressNodeTotal);
end;
end;
procedure TfrmGenerator.TreeViewBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect;
var ContentRect: TRect);
var
NodeData: PGeneratorNodeData;
ProgressWidth: Integer;
begin
if (Column = 1) then
begin
NodeData := Sender.GetNodeData(Node);
if (Assigned(NodeData) and (NodeData^.NodeType = ntOperation) and
(NodeData^.Progress <> 1) and (NodeData^.Progress <> 0)) then
begin
TargetCanvas.Pen.Color := $0000A162;
TargetCanvas.Brush.Color := $0055F2B5;
TargetCanvas.Rectangle(CellRect.Left, CellRect.Top, CellRect.Right,
CellRect.Bottom - CellRect.Top);
TargetCanvas.Pen.Color := $0000A162;
TargetCanvas.Brush.Color := $000FE18E;
ProgressWidth := Round(NodeData^.Progress * (CellRect.Right - CellRect.Left));
TargetCanvas.Rectangle(CellRect.Left, CellRect.Top, CellRect.Left + ProgressWidth,
CellRect.Bottom - CellRect.Top);
end;
end;
end;
procedure TfrmGenerator.TreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode;
var Allowed: Boolean);
begin
Allowed := false;
end;
procedure TfrmGenerator.TreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
NodeData: PGeneratorNodeData;
begin
NodeData := Sender.GetNodeData(Node);
if (Assigned(NodeData)) then
begin
Finalize(NodeData^);
end;
end;
procedure TfrmGenerator.TreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
var
NodeData: PGeneratorNodeData;
begin
ImageIndex := -1;
if (Column = 0) and (Kind in [ikNormal, ikSelected]) then
begin
NodeData := Sender.GetNodeData(Node);
if (Assigned(NodeData)) then
begin
case NodeData^.NodeType of
ntCategory:
ImageIndex := 0;
ntOperation:
begin
if (NodeData^.ProgressActive) then
begin
ImageIndex := 2;
end else
begin
ImageIndex := 1;
end;
end;
ntValue:
ImageIndex := 3;
end;
end;
end;
end;
procedure TfrmGenerator.TreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
NodeData: PGeneratorNodeData;
begin
CellText := '';
NodeData := Sender.GetNodeData(Node);
if (Assigned(NodeData)) then
begin
if (NodeData^.NodeType in [ntCategory, ntOperation, ntValue]) then
begin
case Column of
0: CellText := NodeData^.Text;
1: CellText := NodeData^.Value;
end;
end;
end;
end;
end.