home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 August
/
VPR9708A.ISO
/
D3TRIAL
/
INSTALL
/
DATA.Z
/
HEXDUMP.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1997-04-24
|
13KB
|
500 lines
unit HexDump;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
const
MAXDIGITS = 16;
{ THexDump }
type
THexStr = array[0..2] of Char;
THexStrArray = array[0..MAXDIGITS-1] of THexStr;
THexDump = class(TCustomControl)
private
FActive: Boolean;
FAddress: Pointer;
FDataSize: Integer;
FTopLine: Integer;
FCurrentLine: Integer;
FVisibleLines: Integer;
FLineCount: Integer;
FBytesPerLine: Integer;
FItemHeight: Integer;
FItemWidth: Integer;
FFileColors: array[0..2] of TColor;
FShowCharacters: Boolean;
FShowAddress: Boolean;
FBorder: TBorderStyle;
FHexData: THexStrArray;
FLineAddr: array[0..15] of char;
procedure CalcPaintParams;
procedure SetTopLine(Value: Integer);
procedure SetCurrentLine(Value: Integer);
procedure SetFileColor(Index: Integer; Value: TColor);
function GetFileColor(Index: Integer): TColor;
procedure SetShowCharacters(Value: Boolean);
procedure SetShowAddress(Value: Boolean);
procedure SetBorder(Value: TBorderStyle);
procedure SetAddress(Value: Pointer);
procedure SetDataSize(Value: Integer);
procedure AdjustScrollBars;
function LineAddr(Index: Integer): PChar;
function LineData(Index: Integer): PChar;
function LineChars(Index: Integer): PChar;
function ScrollIntoView: Boolean;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
procedure CMExit(var Message: TCMLostFocus); message CM_EXIT;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure Paint; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property CurrentLine: Integer read FCurrentLine write SetCurrentLine;
property Address: Pointer read FAddress write SetAddress;
property DataSize: Integer read FDataSize write SetDataSize;
published
property Align;
property Border: TBorderStyle read FBorder write SetBorder;
property Color default clWhite;
property Ctl3D;
property Font;
property TabOrder;
property TabStop;
property ShowAddress: Boolean read FShowAddress write SetShowAddress default True;
property ShowCharacters: Boolean read FShowCharacters write SetShowCharacters default True;
property AddressColor: TColor index 0 read GetFileColor write SetFileColor default clBlack;
property HexDataColor: TColor index 1 read GetFileColor write SetFileColor default clBlack;
property AnsiCharColor: TColor index 2 read GetFileColor write SetFileColor default clBlack;
end;
function CreateHexDump(AOwner: TWinControl): THexDump;
implementation
{ Form Methods }
function CreateHexDump(AOwner: TWinControl): THexDump;
begin
Result := THexDump.Create(AOwner);
with Result do
begin
Parent := AOwner;
Font.Name := 'FixedSys';
ShowCharacters := True;
Align := alClient;
end;
end;
{ THexDump }
constructor THexDump.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csFramed];
FBorder := bsSingle;
Color := clWhite;
FShowAddress := True;
FShowCharacters := True;
Width := 300;
Height := 200;
FillChar(FHexData, SizeOf(FHexData), #9);
end;
destructor THexDump.Destroy;
begin
inherited Destroy;
end;
procedure THexDump.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
if FBorder = bsSingle then
Style := Style or WS_BORDER;
Style := Style or WS_VSCROLL;
end;
end;
{ VCL Command Messages }
procedure THexDump.CMFontChanged(var Message: TMessage);
begin
inherited;
Canvas.Font := Self.Font;
FItemHeight := Canvas.TextHeight('A') + 2;
FItemWidth := Canvas.TextWidth('D') + 1;
CalcPaintParams;
AdjustScrollBars;
end;
procedure THexDump.CMEnter;
begin
inherited;
{ InvalidateLineMarker; }
end;
procedure THexDump.CMExit;
begin
inherited;
{ InvalidateLineMarker; }
end;
{ Windows Messages }
procedure THexDump.WMSize(var Message: TWMSize);
begin
inherited;
CalcPaintParams;
AdjustScrollBars;
end;
procedure THexDump.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
Message.Result := DLGC_WANTARROWS;
end;
procedure THexDump.WMVScroll(var Message: TWMVScroll);
var
NewTopLine: Integer;
LinesMoved: Integer;
R: TRect;
begin
inherited;
NewTopLine := FTopLine;
case Message.ScrollCode of
SB_LINEDOWN: Inc(NewTopLine);
SB_LINEUP: Dec(NewTopLine);
SB_PAGEDOWN: Inc(NewTopLine, FVisibleLines - 1);
SB_PAGEUP: Dec(NewTopLine, FVisibleLines - 1);
SB_THUMBPOSITION, SB_THUMBTRACK: NewTopLine := Message.Pos;
end;
if NewTopLine < 0 then NewTopLine := 0;
if NewTopLine >= FLineCount then
NewTopLine := FLineCount - 1;
if NewTopLine <> FTopLine then
begin
LinesMoved := FTopLine - NewTopLine;
FTopLine := NewTopLine;
SetScrollPos(Handle, SB_VERT, FTopLine, True);
if Abs(LinesMoved) = 1 then
begin
R := Bounds(0, 0, ClientWidth, ClientHeight - FItemHeight);
if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);
ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
if LinesMoved = -1 then
begin
R.Top := ClientHeight - FItemHeight;
R.Bottom := ClientHeight;
end
else
begin
R.Top := 0;
R.Bottom := FItemHeight;
end;
Windows.InvalidateRect(Handle, @R, False);
end
else Invalidate;
end;
end;
{ Painting Related }
procedure THexDump.CalcPaintParams;
const
Divisor: array[boolean] of Integer = (3,4);
var
CharsPerLine: Integer;
begin
if FItemHeight < 1 then Exit;
FVisibleLines := (ClientHeight div FItemHeight) + 1;
CharsPerLine := ClientWidth div FItemWidth;
if FShowAddress then Dec(CharsPerLine, 10);
FBytesPerLine := CharsPerLine div Divisor[FShowCharacters];
if FBytesPerLine < 1 then
FBytesPerLine := 1
else if FBytesPerLine > MAXDIGITS then
FBytesPerLine := MAXDIGITS;
FLineCount := (DataSize div FBytesPerLine);
if Boolean(DataSize mod FBytesPerLine) then Inc(FLineCount);
end;
procedure THexDump.AdjustScrollBars;
begin
SetScrollRange(Handle, SB_VERT, 0, FLineCount - 1, True);
end;
function THexDump.ScrollIntoView: Boolean;
begin
Result := False;
if FCurrentLine < FTopLine then
begin
Result := True;
SetTopLine(FCurrentLine);
end
else if FCurrentLine >= (FTopLine + FVisibleLines) - 1 then
begin
SetTopLine(FCurrentLine - (FVisibleLines - 2));
Result := True;
end;
end;
procedure THexDump.SetTopLine(Value: Integer);
var
LinesMoved: Integer;
R: TRect;
begin
if Value <> FTopLine then
begin
if Value < 0 then Value := 0;
if Value >= FLineCount then Value := FLineCount - 1;
LinesMoved := FTopLine - Value;
FTopLine := Value;
SetScrollPos(Handle, SB_VERT, FTopLine, True);
if Abs(LinesMoved) = 1 then
begin
R := Bounds(1, 0, ClientWidth, ClientHeight - FItemHeight);
if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);
ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
if LinesMoved = -1 then
begin
R.Top := ClientHeight - FItemHeight;
R.Bottom := ClientHeight;
end
else
begin
R.Top := 0;
R.Bottom := FItemHeight;
end;
InvalidateRect(Handle, @R, False);
end
else Invalidate;
end;
end;
procedure THexDump.SetCurrentLine(Value: Integer);
var
R: TRect;
begin
if Value <> FCurrentLine then
begin
if Value < 0 then Value := 0;
if Value >= FLineCount then Value := FLineCount - 1;
if (FCurrentLine >= FTopLine) and (FCurrentLine < FTopLine + FVisibleLines - 1) then
begin
R := Bounds(0, 0, 1, FItemHeight);
OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight);
Windows.InvalidateRect(Handle, @R, True);
end;
FCurrentLine := Value;
R := Bounds(0, 0, 1, FItemHeight);
OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight);
Windows.InvalidateRect(Handle, @R, True);
ScrollIntoView;
end;
end;
procedure THexDump.Paint;
var
R: TRect;
I: Integer;
AddressWidth: Integer;
TabStop: Integer;
ByteCnt: Integer;
begin
inherited Paint;
Canvas.Brush.Color := Self.Color;
if FShowAddress then
AddressWidth := FItemWidth*10
else
AddressWidth := 0;
R := Bounds(1, 0, ClientWidth, FItemHeight);
TabStop := FItemWidth*3;
Canvas.Font.Color := FFileColors[1];
ByteCnt := FBytesPerLine;
for I := 0 to FVisibleLines - 1 do
begin
R.Left := 1;
if I + FTopLine < FLineCount then
begin
if FShowAddress then
begin
Canvas.Font.Color := FFileColors[0];
R.Right := R.Left + AddressWidth;
ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineAddr(I+FTopLine), 9, nil);
R.Left := R.Right;
R.Right := ClientWidth;
Canvas.Font.Color := FFileColors[1];
end;
if (I+FTopLine = FLineCount-1) and ((DataSize mod FBytesPerLine) > 0) then
ByteCnt := DataSize mod FBytesPerLine;
TabbedTextOut(Canvas.Handle, R.Left, R.Top, LineData(I+FTopLine),
(ByteCnt*3)-1, 1, TabStop, R.Left);
if FShowCharacters then
begin
R.Left := AddressWidth+(FItemWidth*(FBytesPerLine*3));
Canvas.Font.Color := FFileColors[2];
ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineChars(I+FTopLine), ByteCnt, nil);
end;
end
else ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED,
@R, nil, 0, nil);
OffsetRect(R, 0, FItemHeight);
end;
end;
{ Event Overrides }
procedure THexDump.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited KeyDown(Key, Shift);
if not FActive then Exit;
case Key of
VK_DOWN: CurrentLine := CurrentLine + 1;
VK_UP: CurrentLine := CurrentLine - 1;
VK_NEXT: CurrentLine := CurrentLine + FVisibleLines;
VK_PRIOR: CurrentLine := CurrentLine - FVisibleLines;
VK_HOME: CurrentLine := 0;
VK_END: CurrentLine := FLineCount - 1;
end;
end;
procedure THexDump.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
if not Focused then SetFocus;
if (Button = mbLeft) and FActive then
CurrentLine := FTopLine + (Y div FItemHeight);
end;
{ Property Set/Get Routines }
procedure THexDump.SetBorder(Value: TBorderStyle);
begin
if Value <> FBorder then
begin
FBorder := Value;
RecreateWnd;
end;
end;
procedure THexDump.SetShowAddress(Value: Boolean);
begin
if FShowAddress <> Value then
begin
FShowAddress := Value;
Invalidate;
end;
end;
procedure THexDump.SetShowCharacters(Value: Boolean);
begin
if Value <> FShowCharacters then
begin
FShowCharacters := Value;
Invalidate;
end;
end;
procedure THexDump.SetFileColor(Index: Integer; Value: TColor);
begin
if FFileColors[Index] <> Value then
begin
FFileColors[Index] := Value;
Invalidate;
end;
end;
function THexDump.GetFileColor(Index: Integer): TColor;
begin
Result := FFileColors[Index];
end;
procedure THexDump.SetAddress(Value: Pointer);
begin
FActive := Value <> nil;
FAddress := Value;
Invalidate;
end;
procedure THexDump.SetDataSize(Value: Integer);
begin
FDataSize := Value;
CalcPaintParams;
Invalidate;
AdjustScrollBars;
end;
function THexDump.LineAddr(Index: Integer): PChar;
begin
Result := StrFmt(FLineAddr, '%p:', [Pointer(PChar(Address)+Index*FBytesPerLine)]);
end;
function THexDump.LineData(Index: Integer): PChar;
procedure SetData(P: PChar);
const
HexDigits : array[0..15] of Char = '0123456789ABCDEF';
var
I: Integer;
B: Byte;
begin
for I := 0 to FBytesPerLine-1 do
begin
try
B := Byte(P[I]);
FHexData[I][0] := HexDigits[B SHR $04];
FHexData[I][1] := HexDigits[B AND $0F];
except
FHexData[I][0] := '?';
FHexData[I][1] := '?';
end;
end;
end;
begin
SetData(PChar(FAddress) + Index*FBytesPerLine);
Result := FHexData[0];
end;
function THexDump.LineChars(Index: Integer): PChar;
begin
Result := PChar(FAddress) + Index*FBytesPerLine;
end;
end.