Search code examples
delphidelphi-xe2

Get a hex substring & convert to binary Delphi XE2


My program reads from a device via a serial port and returns this string. 'IC'#$0088#$0080'Ô'#$0080#$0080 I need to get the 5 hex values and convert to binary. #$0088 = 10001000, #$0080 = 10000000, Ô = 11010100.

I can convert the 80 & 88, but am having difficulty extracting them from the whole string. The Ô(xD4) I can neither extract or convert. An extended character like the Ô could be at any or all locations.

The read methods in my serial component are:

function Read(var Buffer; Count: Integer): Integer;
function ReadStr(var Str: string; Count: Integer): Integer;
function ReadAsync(var Buffer; Count: Integer;   var AsyncPtr: PAsync): Integer;
function ReadStrAsync(var Str: Ansistring; Count: Integer;  var AsyncPtr: PAsync): Integer;

Can you give me an example of reading binary?


Solution

  • As I wrote earlier in the comments, the problem with the message in your question is that it consists partly of non-ASCII characters. The ASCII range is from $00 to $7F and have the same characters as Unicode U+0000 to U+007F. Therefore no conversion (except for the leading 0). AnsiCharacters ($80 to $FF) on the other hand are subject to conversion according to the code page in use, in order to keep the same glyph for both. F.Ex. AnsiChar $80 (Euro sign in CP1252) is therefore converted to Unicode U+02C6. Bit patten for the lower byte doesn't match anymore.

    Ref: https://msdn.microsoft.com/en-us/library/cc195054.aspx

    Following code shows the result of two tests, Using Char vs. AnsiChar

    procedure TMainForm.Button2Click(Sender: TObject);
    const
      Buffer: array[0..7] of AnsiChar = ('I','C', #$88, #$80, #$D4, #$80, #$80, ';');
    //  Buffer: array[0..7] of Char = ('I','C', #$88, #$80, #$D4, #$80, #$80, ';');
      BinChars: array[0..1] of Char = ('0','1');
    var
      i, k: integer;
      c: AnsiChar;
    //  c: Char;
      s: string;
    begin
      for k := 2 to 6 do
      begin
        c := Buffer[k];
        SetLength(s, 8);
        for i := 0 to 7 do
          s[8-i] := BinChars[(ord(c) shr i) and 1];
        Memo1.Lines.Add(format('Character %d in binary format: %s',[k, s]));
      end;
    end;
    

    Using Char (UTF-16 WideChar)

    AnsiChar #$88 is converted to U+02C6 
    AnsiChar #$80 is converted to U+20AC 
    AnsiChar #$D4 is converted to U+00D4 !
    

    Lower byte gives

    Character 2 in binary format: 11000110 
    Character 3 in binary format: 10101100 
    Character 4 in binary format: 11010100
    Character 5 in binary format: 10101100 
    Character 6 in binary format: 10101100
    

    Using AnsiChar

    Character 2 in binary format: 10001000
    Character 3 in binary format: 10000000
    Character 4 in binary format: 11010100
    Character 5 in binary format: 10000000
    Character 6 in binary format: 10000000
    

    Unfortunately a conversion from Unicode to Ansi (even if originally converted from Ansi to Unicode) is lossy and will fail.

    I really don't see any easy solution with the information available.