开发者

Hex view of a file

开发者 https://www.devze.com 2023-03-12 03:57 出处:网络
I am using Delphi 2009. 开发者_JAVA百科 I want to view the contents of a file (in hexadecimal) inside a memo.

I am using Delphi 2009.

开发者_JAVA百科

I want to view the contents of a file (in hexadecimal) inside a memo.

I'm using this code :

var
  Buffer:String;
begin
  Buffer := '';
  AssignFile(sF,Source); //Assign file
  Reset(sF); 
  repeat
    Readln(sF,Buffer); //Load every line to a string.
    TempChar:=StrToHex(Buffer); //Convert to Hex using the function
    ...
  until EOF(sF);
end;

function StrToHex(AStr: string): string;
var
I ,Len: Integer;
s: chr (0)..255;
//s:byte;
//s: char;
begin
  len:=length(AStr);
  Result:='';
  for i:=1 to len  do
  begin
    s:=AStr[i];

    //The problem is here. Ord(s) is giving false values (251 instead of 255)
    //And in general the output differs from a professional hex editor.

    Result:=Result +' '+IntToHex(Ord(s),2)+'('+IntToStr(Ord(s))+')';
  end;
  Delete(Result,1,1);
end; 

When I declare variable "s" as char (i know that char goes up to 255) I get results hex values up to 65535!

When i declare variable "s" as byte or chr (0)..255, it outputs different hex values, comparing to any Hexadecimal Editor!

Why is that? How can I see the correct values?

Check images for the differences.

1st image: Professional Hex Editor.

Hex view of a file

2nd image: Function output to Memo.

Hex view of a file

Thank you.


Your Delphi 2009 is unicode-enabled, so Char is actually WideChar and that's a 2 byte, 16 bit unsigned value, that can have values from 0 to 65535.

You could change all your Char declarations to AnsiChar and all your String declarations to AnsiString, but that's not the way to do it. You should drop Pascal I/O in favor of modern stream-based I/O, use a TFileStream, and don't treat binary data as Char.

Console demo:

program Project26;

{$APPTYPE CONSOLE}

uses SysUtils, Classes;

var F: TFileStream;
    Buff: array[0..15] of Byte;
    CountRead: Integer;
    HexText: array[0..31] of Char;

begin
  F := TFileStream.Create('C:\Temp\test', fmOpenRead or fmShareDenyWrite);
  try
    CountRead := F.Read(Buff, SizeOf(Buff));
    while CountRead <> 0 do
    begin
      BinToHex(Buff, HexText, CountRead);
      WriteLn(HexText); // You could add this to the Memo

      CountRead := F.Read(Buff, SizeOf(Buff));
    end;
  finally F.Free;
  end;
end.


In Delphi 2009, a Char is the same thing as a WideChar, that is, a Unicode character. A wide character occupies two bytes. You want to use AnsiChar. Prior to Delphi 2009 (that is, prior to Unicode Delphi), Char was the same thing as AnsiChar.

Also, you shouldn't use ReadLn. You are treating the file as a text file with text-file line endings! This is a general file! It might not have any text-file line endings at all!


For an easier to read output, and looking better too, you might want to use this simple hex dump formatter.

The HexDump procedure dumps an area of memory into a TStrings in lines of two chunks of 8 bytes in hex, and 16 ascii chars

example

406563686F206F66 660D0A6966206578 @echo off..if ex
69737420257E7331 5C6E756C20280D0A ist %~s1\nul (..
0D0A290D0A                        ..)..

Here is the code for the dump format function

function HexB (b: Byte): String;
 const HexChar: Array[0..15] of Char = '0123456789ABCDEF';
 begin
  result:= HexChar[b shr 4]+HexChar[b and $0f];
 end;

procedure HexDump(var data; size: Integer; s: TStrings);
 const
  sepHex=' ';
  sepAsc=' ';
  nonAsc='.';
 var
  i : Integer;
  hexDat, ascDat : String;
  buff : Array[0..1] of Byte Absolute data;

 begin
  hexDat:='';
  ascDat:='';
  for i:=0 to size-1 do 
   begin
    hexDat:=hexDat+HexB(buff[i]);
    if ((buff[i]>31) and (buff[i]<>255)) then
      ascDat:=ascDat+Char(buff[i])
    else
      ascDat:=ascDat+nonAsc;
    if (((i+1) mod 16)<>0) and (((i+1) mod 8)=0) then 
      hexDat:=hexDat+sepHex;
    if ((i+1) mod 16)=0 then 
     begin
      s.Add(hexdat+sepAsc+ascdat);
      hexdat:='';
      ascdat:='';
     end;
   end;
  if (size mod 16)<>0 then
   begin
    if (size mod 16)<8 then 
      hexDat:=hexDat+StringOfChar(' ',(8-(size mod 8))*2)
              +sepHex+StringOfChar(' ',16)
    else
      hexDat:=hexDat+StringOfChar(' ',(16-(size mod 16))*2);
    s.Add(hexDat + sepAsc  + ascDat);
   end;
 end;

And here is a complete code example for dumping the contents of a file into a Memo field.

procedure TForm1.Button1Click(Sender: TObject);
 var
  FStream: TFileStream;
  buff: array[0..$fff] of Byte;
  nRead: Integer;
 begin
  FStream := TFileStream.Create(edit1.text, fmOpenRead or fmShareDenyWrite);
  try
    repeat
      nRead := FStream.Read(Buff, SizeOf(Buff));
      if nRead<>0 then
        hexdump(buff,nRead,memo1.lines);
    until nRead=0;
  finally
    F.Free;
  end;
 end;


string is UnicodeString in Delphi 2009. If you want to use single-byte strings use AnsiString or RawByteString.

See String types.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号