Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 74. - Prohlížeč binárních souborů; Jak zobrazit soubor jako ASCII data

Jan Šindelář - 22.1.2003

Prohlížeč binárních souborů; Jak zobrazit soubor jako ASCII data

Jistě dobře víte, že běžný binární soubor obsahuje řadu netisknutelných (nezobrazitelných) znaků. Bereme-li v úvahu pouze obyčejnou ASCII tabulku a odečteme alfanumerické znaky plus některé speciální znaky, pořád nám zbývá poměrně dost "znaků", které nemají žádnou grafickou reprezentaci (např. ESC, CR, TAB atd..). Chceme-li pak binární soubor zobrazit jako text, musíme si s touto drobnou překážkou poradit. Tento problém se řeší tak (stejně jako je tomu např. u integrovaného prohlížeče známého Windows Commanderu), že se zkrátka místo netisknutelných znaků zobrazí nějaký znak zástupný. Zvolený soubor si navíc můžete zobrazit též v jeho hexadecimální podobě, kdy v levé části okna prohlížeče vidíte jednotlivé znaky přepočítané na hexadecimální hodnoty a v pravém úzkém sloupci pak vidíte textovou reprezentaci dat s náhradou netisknutelných znaků. A právě takový malý a jednoduchý prohlížeč si dnes vytvoříme.

Co tedy přijde na formulář? Vlastně pouze tři věci. Nejprve komponenta Memo, do které budeme soubor zobrazovat, dále pak tlačítko, kterým aktivujeme výběr souboru a pak samotný OpenDialog. Jako náhradní znak je vybrána tečka, ale ve zdrojovém kódů si pochopitelně můžete změnit tento znak na vašeho favorita. Do připravené komponenty Memo se tedy po stisknutí tlačítka a výběru souboru začne řádek po řádku zobrazovat daný soubor. Zobrazena je adresa daného řádku, poté hexadecimální reprezentace a v posledním sloupci pak jeho textová podoba. Celý zdrojový kód tedy následuje:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Display(const s: string);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TDisplayProc = procedure(const s: string) of object;
  procedure ShowBinary(var Data; Count: Cardinal; DispProc: TDisplayProc);

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure ShowBinary(var Data; Count: Cardinal; DispProc: TDisplayProc);
const
  posStart = 1;
  binStart = 7;
  ascStart = 57;
  HexChars: PChar = `0123456789ABCDEF`;

var
  line: string[80];
  i: Cardinal;
  p: PChar;
  nStr: string[4];

begin
  p := @Data;
  line := ``;
  for i := 0 to Count - 1 do
  begin
    if (i mod 16) = 0 then
    begin
      if Length(line) > 0 then DispProc(line);
      FillChar(line, SizeOf(line), ` `);
      line[0] := Chr(72);
      nStr := Format(`%4.4X`, [i]);
      Move(nStr[1], line[posStart], Length(nStr));
      line[posStart + 4] := `:`;
    end;
    if p[i] >= ` ` then line[i mod 16 + ascStart] := p[i]
                    else line[i mod 16 + ascStart] := `.`;
    line[binStart + 3 * (i mod 16)] := HexChars[(Ord(p[i]) shr 4) and $F];
    line[binStart + 3 * (i mod 16) + 1] := HexChars[Ord(p[i]) and $F];
  end;
  DispProc(line);
end;

procedure TForm1.Display(const S: string);
begin
  Memo1.Lines.Add(S);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ms: TMemoryStream;
begin
  if Opendialog1.Execute then
  begin
    ms := TMemoryStream.Create;
    try
      ms.LoadFromfile(OpenDialog1.FileName);
      ShowBinary(ms.Memory^, ms.Size, Display);
    finally
      ms.Free
    end;
  end;
end;

end.

Než se vrhnete na psaní kritiky do diskuse, tak musím připomenout, že tento kód není zrovna optimalizovaný a slouží víceméně pro ukázku toho, jak pracovat se samotným textem. Proceduru na jeho zobrazení si pak můžete klidně přeprogramovat sami podle vlastních potřeb. Rovněž musím upozornit, že ani komponenta Memo není zrovna ideální pro uchovávání velkých objemů dat a pod Windows 9x je dokonce omezena na 64k textu. Program sice nezkolabuje, ale více dat vám prostě nezobrazí. Novější Windows sice toto omezení nemají, ale přesto je potřeba si na tuto věc dát pozor. A úplně poslední poznámka se týká zvoleného písma pro náš příklad. Po spuštění programu jistě sami pochopíte, co mám na mysli. Zvolte si tedy nějaké neproporcionální písmo, protože jinak nebudete mít sloupce pod sebou.