home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1996 August / VPR9608A.BIN / del20try / install / data.z / HEXDUMP.PAS < prev    next >
Pascal/Delphi Source File  |  1996-05-08  |  14KB  |  521 lines

  1. unit HexDump;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. const
  10.   MAXDIGITS = 16;
  11.  
  12. { THexDump }
  13.  
  14. type
  15.  
  16.   THexStr = array[0..2] of Char;
  17.   THexStrArray = array[0..MAXDIGITS-1] of THexStr;
  18.  
  19.   THexDump = class(TCustomControl)
  20.   private
  21.     FActive: Boolean;
  22.     FAddress: Pointer;
  23.     FDataSize: Integer;
  24.     FTopLine: Integer;
  25.     FCurrentLine: Integer;
  26.     FVisibleLines: Integer;
  27.     FLineCount: Integer;
  28.     FBytesPerLine: Integer;
  29.     FItemHeight: Integer;
  30.     FItemWidth: Integer;
  31.     FFileColors: array[0..2] of TColor;
  32.     FShowCharacters: Boolean;
  33.     FShowAddress: Boolean;
  34.     FBorder: TBorderStyle;
  35.     FHexData: THexStrArray;
  36.     FLineAddr: array[0..15] of char;
  37.     FCharData: array[0..MAXDIGITS] of char;
  38.  
  39.     procedure CheckActive;
  40.     procedure CalcPaintParams;
  41.     procedure SetTopLine(Value: Integer);
  42.     procedure SetCurrentLine(Value: Integer);
  43.     procedure SetFileColor(Index: Integer; Value: TColor);
  44.     function GetFileColor(Index: Integer): TColor;
  45.     procedure SetShowCharacters(Value: Boolean);
  46.     procedure SetShowAddress(Value: Boolean);
  47.     procedure SetBorder(Value: TBorderStyle);
  48.     procedure SetAddress(Value: Pointer);
  49.     procedure SetDataSize(Value: Integer);
  50.     procedure AdjustScrollBars;
  51.     function LineAddr(Index: Integer): PChar;
  52.     function LineData(Index: Integer): PChar;
  53.     function LineChars(Index: Integer): PChar;
  54.     function ScrollIntoView: Boolean;
  55.     procedure InvalidateLine(Index: Integer);
  56.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  57.     procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
  58.     procedure CMExit(var Message: TCMLostFocus); message CM_EXIT;
  59.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  60.     procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  61.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  62.   protected
  63.     procedure CreateParams(var Params: TCreateParams); override;
  64.     procedure Paint; override;
  65.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  66.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  67.   public
  68.     constructor Create(AOwner: TComponent); override;
  69.     destructor Destroy; override;
  70.     property CurrentLine: Integer read FCurrentLine write SetCurrentLine;
  71.     property Address: Pointer read FAddress write SetAddress;
  72.     property DataSize: Integer read FDataSize write SetDataSize;
  73.   published
  74.     property Align;
  75.     property Border: TBorderStyle read FBorder write SetBorder;
  76.     property Color default clWhite;
  77.     property Ctl3D;
  78.     property Font;
  79.     property TabOrder;
  80.     property TabStop;
  81.     property ShowAddress: Boolean read FShowAddress write SetShowAddress default True;
  82.     property ShowCharacters: Boolean read FShowCharacters write SetShowCharacters default True;
  83.     property AddressColor: TColor index 0 read GetFileColor write SetFileColor default clBlack;
  84.     property HexDataColor: TColor index 1 read GetFileColor write SetFileColor default clBlack;
  85.     property AnsiCharColor: TColor index 2 read GetFileColor write SetFileColor default clBlack;
  86.   end;
  87.  
  88. function CreateHexDump(AOwner: TWinControl): THexDump;
  89.  
  90. implementation
  91.  
  92. { Form Methods }
  93.  
  94. function CreateHexDump(AOwner: TWinControl): THexDump;
  95. begin
  96.   Result := THexDump.Create(AOwner);
  97.   with Result do
  98.   begin
  99.     Parent := AOwner;
  100.     Font.Name := 'FixedSys';
  101.     ShowCharacters := True;
  102.     Align := alClient;
  103.   end;
  104. end;
  105.  
  106. { THexDump }
  107.  
  108. constructor THexDump.Create(AOwner: TComponent);
  109. begin
  110.   inherited Create(AOwner);
  111.   ControlStyle := [csFramed];
  112.   FBorder := bsSingle;
  113.   Color := clWhite;
  114.   FShowAddress := True;
  115.   FShowCharacters := True;
  116.   Width := 300;
  117.   Height := 200;
  118.   FillChar(FHexData, SizeOf(FHexData), #9);
  119. end;
  120.  
  121. destructor THexDump.Destroy;
  122. begin
  123.   inherited Destroy;
  124. end;
  125.  
  126. procedure THexDump.CheckActive;
  127. begin
  128.   if not FActive then
  129.     raise Exception.Create('Operation not allowed unless viewing data');
  130. end;
  131.  
  132. procedure THexDump.CreateParams(var Params: TCreateParams);
  133. begin
  134.   inherited CreateParams(Params);
  135.   with Params do
  136.   begin
  137.     if FBorder = bsSingle then
  138.       Style := Style or WS_BORDER;
  139.     Style := Style or WS_VSCROLL;
  140.   end;
  141. end;
  142.  
  143. { VCL Command Messages }
  144.  
  145. procedure THexDump.CMFontChanged(var Message: TMessage);
  146. begin
  147.   inherited;
  148.   Canvas.Font := Self.Font;
  149.   FItemHeight := Canvas.TextHeight('A') + 2;
  150.   FItemWidth := Canvas.TextWidth('D') + 1;
  151.   CalcPaintParams;
  152.   AdjustScrollBars;
  153. end;
  154.  
  155. procedure THexDump.CMEnter;
  156. begin
  157.   inherited;
  158. {  InvalidateLineMarker; }
  159. end;
  160.  
  161. procedure THexDump.CMExit;
  162. begin
  163.   inherited;
  164. {  InvalidateLineMarker; }
  165. end;
  166.  
  167. { Windows Messages }
  168.  
  169. procedure THexDump.WMSize(var Message: TWMSize);
  170. begin
  171.   inherited;
  172.   CalcPaintParams;
  173.   AdjustScrollBars;
  174. end;
  175.  
  176. procedure THexDump.WMGetDlgCode(var Message: TWMGetDlgCode);
  177. begin
  178.   Message.Result := DLGC_WANTARROWS;
  179. end;
  180.  
  181. procedure THexDump.WMVScroll(var Message: TWMVScroll);
  182. var
  183.   NewTopLine: Integer;
  184.   LinesMoved: Integer;
  185.   R: TRect;
  186. begin
  187.   inherited;
  188.   NewTopLine := FTopLine;
  189.   case Message.ScrollCode of
  190.     SB_LINEDOWN: Inc(NewTopLine);
  191.     SB_LINEUP: Dec(NewTopLine);
  192.     SB_PAGEDOWN: Inc(NewTopLine, FVisibleLines - 1);
  193.     SB_PAGEUP: Dec(NewTopLine, FVisibleLines - 1);
  194.     SB_THUMBPOSITION, SB_THUMBTRACK: NewTopLine := Message.Pos;
  195.   end;
  196.  
  197.   if NewTopLine < 0 then NewTopLine := 0;
  198.   if NewTopLine >= FLineCount then
  199.     NewTopLine := FLineCount - 1;
  200.  
  201.   if NewTopLine <> FTopLine then
  202.   begin
  203.     LinesMoved := FTopLine - NewTopLine;
  204.     FTopLine := NewTopLine;
  205.     SetScrollPos(Handle, SB_VERT, FTopLine, True);
  206.  
  207.     if Abs(LinesMoved) = 1 then
  208.     begin
  209.       R := Bounds(0, 0, ClientWidth, ClientHeight - FItemHeight);
  210.       if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);
  211.  
  212.       ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
  213.  
  214.       if LinesMoved = -1 then
  215.       begin
  216.         R.Top := ClientHeight - FItemHeight;
  217.         R.Bottom := ClientHeight;
  218.       end
  219.       else
  220.       begin
  221.         R.Top := 0;
  222.         R.Bottom := FItemHeight;
  223.       end;
  224.  
  225.       Windows.InvalidateRect(Handle, @R, False);
  226.  
  227.     end
  228.     else Invalidate;
  229.   end;
  230. end;
  231.  
  232. { Painting Related }
  233.  
  234. procedure THexDump.CalcPaintParams;
  235. const
  236.   Divisor: array[boolean] of Integer = (3,4);
  237. var
  238.   CharsPerLine: Integer;
  239.  
  240. begin
  241.   if FItemHeight < 1 then Exit;
  242.   FVisibleLines := (ClientHeight div FItemHeight) + 1;
  243.   CharsPerLine := ClientWidth div FItemWidth;
  244.   if FShowAddress then Dec(CharsPerLine, 10);
  245.   FBytesPerLine := CharsPerLine div Divisor[FShowCharacters];
  246.   if FBytesPerLine < 1 then
  247.     FBytesPerLine := 1
  248.   else if FBytesPerLine > MAXDIGITS then
  249.     FBytesPerLine := MAXDIGITS;
  250.   FLineCount := (DataSize div FBytesPerLine);
  251.   if Boolean(DataSize mod FBytesPerLine) then Inc(FLineCount);
  252. end;
  253.  
  254. procedure THexDump.InvalidateLine(Index: Integer);
  255. var
  256.   R: TRect;
  257. begin
  258.   if (Index >= FTopLine) and (Index <= FTopLine + FVisibleLines - 1) then
  259.   begin
  260.     R := Rect(0, 0, ClientWidth, FItemHeight);
  261.     OffsetRect(R, 0, (Index - FTopLine) * FItemHeight);
  262.     Windows.InvalidateRect(Handle, @R, False);
  263.   end;
  264. end;
  265.  
  266. procedure THexDump.AdjustScrollBars;
  267. begin
  268.   SetScrollRange(Handle, SB_VERT, 0, FLineCount - 1, True);
  269. end;
  270.  
  271. function THexDump.ScrollIntoView: Boolean;
  272. begin
  273.   Result := False;
  274.   if FCurrentLine < FTopLine then
  275.   begin
  276.     Result := True;
  277.     SetTopLine(FCurrentLine);
  278.   end
  279.   else if FCurrentLine >= (FTopLine + FVisibleLines) - 1 then
  280.   begin
  281.     SetTopLine(FCurrentLine - (FVisibleLines - 2));
  282.     Result := True;
  283.   end;
  284. end;
  285.  
  286. procedure THexDump.SetTopLine(Value: Integer);
  287. var
  288.   LinesMoved: Integer;
  289.   R: TRect;
  290. begin
  291.   if Value <> FTopLine then
  292.   begin
  293.     if Value < 0 then Value := 0;
  294.     if Value >= FLineCount then Value := FLineCount - 1;
  295.  
  296.     LinesMoved := FTopLine - Value;
  297.     FTopLine := Value;
  298.     SetScrollPos(Handle, SB_VERT, FTopLine, True);
  299.  
  300.     if Abs(LinesMoved) = 1 then
  301.     begin
  302.       R := Bounds(1, 0, ClientWidth, ClientHeight - FItemHeight);
  303.       if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);
  304.  
  305.       ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);
  306.  
  307.       if LinesMoved = -1 then
  308.       begin
  309.         R.Top := ClientHeight - FItemHeight;
  310.         R.Bottom := ClientHeight;
  311.       end
  312.       else
  313.       begin
  314.         R.Top := 0;
  315.         R.Bottom := FItemHeight;
  316.       end;
  317.  
  318.       InvalidateRect(Handle, @R, False);
  319.  
  320.     end
  321.     else Invalidate;
  322.   end;
  323. end;
  324.  
  325. procedure THexDump.SetCurrentLine(Value: Integer);
  326. var
  327.   R: TRect;
  328. begin
  329.   if Value <> FCurrentLine then
  330.   begin
  331.     if Value < 0 then Value := 0;
  332.     if Value >= FLineCount then Value := FLineCount - 1;
  333.  
  334.     if (FCurrentLine >= FTopLine) and (FCurrentLine < FTopLine + FVisibleLines - 1) then
  335.     begin
  336.       R := Bounds(0, 0, 1, FItemHeight);
  337.       OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight);
  338.       Windows.InvalidateRect(Handle, @R, True);
  339.     end;
  340.     FCurrentLine := Value;
  341.  
  342.     R := Bounds(0, 0, 1, FItemHeight);
  343.     OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight);
  344.     Windows.InvalidateRect(Handle, @R, True);
  345.     ScrollIntoView;
  346.   end;
  347. end;
  348.  
  349. procedure THexDump.Paint;
  350. var
  351.   R: TRect;
  352.   I: Integer;
  353.   AddressWidth: Integer;
  354.   TabStop: Integer;
  355.   ByteCnt: Integer;
  356. begin
  357.   inherited Paint;
  358.   Canvas.Brush.Color := Self.Color;
  359.   if FShowAddress then
  360.     AddressWidth := FItemWidth*10
  361.   else
  362.     AddressWidth := 0;
  363.   R := Bounds(1, 0, ClientWidth, FItemHeight);
  364.   TabStop := FItemWidth*3;
  365.   Canvas.Font.Color := FFileColors[1];
  366.   ByteCnt := FBytesPerLine;
  367.   for I := 0 to FVisibleLines - 1 do
  368.   begin
  369.     R.Left := 1;
  370.     if I + FTopLine < FLineCount then
  371.     begin
  372.       if FShowAddress then
  373.       begin
  374.         Canvas.Font.Color := FFileColors[0];
  375.         R.Right := R.Left + AddressWidth;
  376.         ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineAddr(I+FTopLine), 9, nil);
  377.         R.Left := R.Right;
  378.         R.Right := ClientWidth;
  379.         Canvas.Font.Color := FFileColors[1];
  380.       end;
  381.       if (I+FTopLine = FLineCount-1) and ((DataSize mod FBytesPerLine) > 0) then
  382.         ByteCnt := DataSize mod FBytesPerLine;
  383.       TabbedTextOut(Canvas.Handle, R.Left, R.Top, LineData(I+FTopLine),
  384.         (ByteCnt*3)-1, 1, TabStop, R.Left);
  385.       if FShowCharacters then
  386.       begin
  387.         R.Left := AddressWidth+(FItemWidth*(FBytesPerLine*3));
  388.         Canvas.Font.Color := FFileColors[2];
  389.         ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineChars(I+FTopLine), ByteCnt, nil);
  390.       end;
  391.     end
  392.     else ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED,
  393.       @R, nil, 0, nil);
  394.     OffsetRect(R, 0, FItemHeight);
  395.   end;
  396. end;
  397.  
  398. { Event Overrides }
  399.  
  400. procedure THexDump.KeyDown(var Key: Word; Shift: TShiftState);
  401. begin
  402.   inherited KeyDown(Key, Shift);
  403.   if not FActive then Exit;
  404.  
  405.   case Key of
  406.     VK_DOWN: CurrentLine := CurrentLine + 1;
  407.     VK_UP: CurrentLine := CurrentLine - 1;
  408.     VK_NEXT: CurrentLine := CurrentLine + FVisibleLines;
  409.     VK_PRIOR: CurrentLine := CurrentLine - FVisibleLines;
  410.     VK_HOME: CurrentLine := 0;
  411.     VK_END: CurrentLine := FLineCount - 1;
  412.   end;
  413. end;
  414.  
  415. procedure THexDump.MouseDown(Button: TMouseButton; Shift: TShiftState;
  416.   X, Y: Integer);
  417. begin
  418.   inherited MouseDown(Button, Shift, X, Y);
  419.   if not Focused then SetFocus;
  420.   if (Button = mbLeft) and FActive then
  421.     CurrentLine := FTopLine + (Y div FItemHeight);
  422. end;
  423.  
  424. { Property Set/Get Routines }
  425.  
  426. procedure THexDump.SetBorder(Value: TBorderStyle);
  427. begin
  428.   if Value <> FBorder then
  429.   begin
  430.     FBorder := Value;
  431.     RecreateWnd;
  432.   end;
  433. end;
  434.  
  435. procedure THexDump.SetShowAddress(Value: Boolean);
  436. begin
  437.   if FShowAddress <> Value then
  438.   begin
  439.     FShowAddress := Value;
  440.     Invalidate;
  441.   end;
  442. end;
  443.  
  444. procedure THexDump.SetShowCharacters(Value: Boolean);
  445. begin
  446.   if Value <> FShowCharacters then
  447.   begin
  448.     FShowCharacters := Value;
  449.     Invalidate;
  450.   end;
  451. end;
  452.  
  453. procedure THexDump.SetFileColor(Index: Integer; Value: TColor);
  454. begin
  455.   if FFileColors[Index] <> Value then
  456.   begin
  457.     FFileColors[Index] := Value;
  458.     Invalidate;
  459.   end;
  460. end;
  461.  
  462. function THexDump.GetFileColor(Index: Integer): TColor;
  463. begin
  464.   Result := FFileColors[Index];
  465. end;
  466.  
  467. procedure THexDump.SetAddress(Value: Pointer);
  468. begin
  469.   FActive := Value <> nil;
  470.   FAddress := Value;
  471.   Invalidate;
  472. end;
  473.  
  474. procedure THexDump.SetDataSize(Value: Integer);
  475. begin
  476.   FDataSize := Value;
  477.   CalcPaintParams;
  478.   Invalidate;
  479.   AdjustScrollBars;
  480. end;
  481.  
  482. function THexDump.LineAddr(Index: Integer): PChar;
  483. begin
  484.   Result := StrFmt(FLineAddr, '%p:', [Pointer(PChar(Address)+Index*FBytesPerLine)]);
  485. end;
  486.  
  487. function THexDump.LineData(Index: Integer): PChar;
  488.  
  489.   procedure SetData(P: PChar);
  490.   const
  491.     HexDigits : array[0..15] of Char = '0123456789ABCDEF';
  492.   var
  493.     I: Integer;
  494.     B: Byte;
  495.   begin
  496.     for I := 0 to FBytesPerLine-1 do
  497.     begin
  498.       try 
  499.         B := Byte(P[I]);
  500.         FHexData[I][0] := HexDigits[B SHR $04];
  501.         FHexData[I][1] := HexDigits[B AND $0F];
  502.       except
  503.         FHexData[I][0] := '?';
  504.         FHexData[I][1] := '?';
  505.       end;
  506.  
  507.     end;
  508.   end;
  509.  
  510. begin
  511.   SetData(PChar(FAddress) + Index*FBytesPerLine);
  512.   Result := FHexData[0];
  513. end;
  514.  
  515. function THexDump.LineChars(Index: Integer): PChar;
  516. begin
  517.   Result := PChar(FAddress) + Index*FBytesPerLine;
  518. end;
  519.  
  520. end.
  521.