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