Browse Source

* Hex2Bin Delphi-compatible overloads. Fixes issue #38712

Michaël Van Canneyt 2 years ago
parent
commit
56a906a421

+ 151 - 26
packages/rtl-objpas/src/inc/strutils.pp

@@ -247,7 +247,14 @@ procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer
 procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer); overload;
 procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer); overload;
 procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer); overload;
 procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer); overload;
 procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer); overload;
 procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer); overload;
-function HexToBin(HexValue, BinValue: PAnsiChar; BinBufSize: Integer): Integer;
+function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
+function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
+function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
+function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
+function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
+function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
+function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
+function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
 
 
 const
 const
   DigitChars = ['0'..'9'];
   DigitChars = ['0'..'9'];
@@ -3362,38 +3369,156 @@ begin
 end;
 end;
 
 
 
 
-function HexToBin(HexValue, BinValue: PAnsiChar; BinBufSize: Integer): Integer;
-// more complex, have to accept more than bintohex
-// A..F    1000001
-// a..f    1100001
-// 0..9     110000
+function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
+var
+  i : Integer;
+  PText : PWideChar;
+  PBinBuf : PAnsiChar;
+begin
+  PText:=HexText+HexTextOffset;
+  PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
+  i:=Count;
+  Result:=HexToBin(PText, PBinBuf, i);
+end;
+
+function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
+var
+  i : Integer;
+  PText : PAnsiChar;
+  PBinBuf : PAnsiChar;
+begin
+  PText:=PAnsiChar(HexText)+HexTextOffset;
+  PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
+  i:=Count;
+  Result:=HexToBin(PText, PBinBuf, i);
+end;
 
 
-var i,j,h,l : integer;
+function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
+begin
+  Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
+end;
 
 
+function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer;
 begin
 begin
-  i:=binbufsize;
+  Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
+end;
+
+function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
+
+const
+  LookUpTable1 : array ['0' .. '9'] of UInt8 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  LookUpTable2 : array ['a' .. 'f'] of UInt8 = (10, 11, 12, 13, 14, 15);
+  LookUpTable3 : array ['A' .. 'F'] of UInt8 = (10, 11, 12, 13, 14, 15);
+  
+var
+  i : integer;
+  num1,num2 : UInt8;
+  res : UInt8;
+  
+begin
+  i:=BinBufSize;
   while (i>0) do
   while (i>0) do
     begin
     begin
-    if hexvalue^ IN ['A'..'F','a'..'f'] then
-      h:=((ord(hexvalue^)+9) and 15)
-    else if hexvalue^ IN ['0'..'9'] then
-      h:=((ord(hexvalue^)) and 15)
-    else
-      break;
-    inc(hexvalue);
-    if hexvalue^ IN ['A'..'F','a'..'f'] then
-      l:=(ord(hexvalue^)+9) and 15
-    else if hexvalue^ IN ['0'..'9'] then
-      l:=(ord(hexvalue^)) and 15
-    else
-      break;
-    j := l + (h shl 4);
-    inc(hexvalue);
-    binvalue^:=chr(j);
-    inc(binvalue);
+    // get value of first character (1-byte)
+    case HexText^ of
+      '0'..'9':
+        num1:=LookUpTable1[HexText^];
+      'a'..'f':
+        num1:=LookUpTable2[HexText^];
+      'A'..'F':
+        num1:=LookUpTable3[HexText^];
+      else
+        break;
+    end;
+
+    inc(HexText);
+
+    // get value of second character (1-byte)
+    case HexText^ of
+      '0'..'9':
+        num2:=LookUpTable1[HexText^];
+      'a'..'f':
+        num2:=LookUpTable2[HexText^];
+      'A'..'F':
+        num2:=LookUpTable3[HexText^];
+      else
+        break;
+    end;
+
+    // map two byte values into one byte
+    res:=num2+(num1 shl 4);
+    BinBuffer^:=AnsiChar(res);
+    inc(BinBuffer);
+
+    inc(HexText);
     dec(i);
     dec(i);
     end;
     end;
-  result:=binbufsize-i;
+  Result:=BinBufSize-i;
+end;
+
+function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
+const
+  LookUpTable1 : array ['0' .. '9'] of UInt8 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  LookUpTable2 : array ['a' .. 'f'] of UInt8 = (10, 11, 12, 13, 14, 15);
+  LookUpTable3 : array ['A' .. 'F'] of UInt8 = (10, 11, 12, 13, 14, 15);
+var
+  i : integer;
+  num1,num2 : UInt8;
+  res : UInt8;
+begin
+  i:=BinBufSize;
+  while (i>0) do
+  begin
+    // 2-byte chars could use lower bits for another character
+    if (HexText^ > #255) then break;
+    // get value of first character (2-byte)
+    case HexText^ of
+      '0'..'9':
+        num1:=LookUpTable1[HexText^];
+      'a'..'f':
+        num1:=LookUpTable2[HexText^];
+      'A'..'F':
+        num1:=LookUpTable3[HexText^];
+      else
+        break;
+     end;
+
+    inc(HexText);
+
+    // 2-byte chars could use lower bits for another character
+    if (HexText^ > #255) then break;
+    // get value of second character (2-byte)
+    case HexText^ of
+      '0'..'9':
+        num2:=LookUpTable1[HexText^];
+      'a'..'f':
+        num2:=LookUpTable2[HexText^];
+      'A'..'F':
+        num2:=LookUpTable3[HexText^];
+      else
+        break;
+    end;
+
+    // map four byte values into one byte
+    res:=num2+(num1 shl 4);
+    BinBuffer^:=AnsiChar(res);
+    inc(BinBuffer);
+
+    inc(HexText);
+    dec(i);
+  end;
+
+  Result:=BinBufSize-i;
+end;
+
+function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer;
+begin
+  Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
+end;
+
+function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
+begin
+  Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
 end;
 end;
 
 
 function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;
 function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;

+ 232 - 0
tests/test/units/strutils/struth2b.pp

@@ -0,0 +1,232 @@
+program HexToBin_tests_non_unicode;
+
+{$IFDEF FPC}
+  // PChar in Delphi < 2009 is PAnsiChar so make sure the tests behave the same but actually almost none of the functions are available...
+  {$mode Delphi}
+{$ENDIF}
+
+uses
+  SysUtils,
+  {$IFDEF FPC}
+    StrUtils
+  {$ELSE}
+    Classes
+  {$ENDIF};
+
+var
+  BinValueBytes: TBytes;
+  HexValueBytes: TBytes;
+  HexInLen, BinBufLen: Integer;
+  ret: Integer;
+
+const
+  HexInputA: AnsiString = '1decaf';
+  HexInputW: WideString = '1decaf';
+  HexCorruptInputW: WideString = '9abcdefg';
+  HexOffsetInputW: WideString = '608da975';
+
+begin
+  writeln('start testing of HexToBin methods');
+
+  {* test simple methods *}
+  // ansistring
+  // write 2 bytes into 1 byte
+  HexInLen := Length(HexInputA) * SizeOf(AnsiChar) div 2;
+
+(*
+  // Delphi: E2251 Ambiguous overloaded call to 'HexToBin'
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(@HexInputA[1], @BinValueBytes[0], BinBufLen);
+  if ret <> 3 then halt(1);
+  if BinValueBytes[0] <> 29 then halt(1);
+  if BinValueBytes[1] <> 236 then halt(1);
+  if BinValueBytes[2] <> 175 then halt(1);
+*)
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputA), PChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(2);
+  if BinValueBytes[0] <> 29 then halt(2);
+  if BinValueBytes[1] <> 236 then halt(2);
+  if BinValueBytes[2] <> 175 then halt(2);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(3);
+  if BinValueBytes[0] <> 29 then halt(3);
+  if BinValueBytes[1] <> 236 then halt(3);
+  if BinValueBytes[2] <> 175 then halt(3);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(4);
+  if BinValueBytes[0] <> 29 then halt(4);
+  if BinValueBytes[1] <> 236 then halt(4);
+  if BinValueBytes[2] <> 175 then halt(4);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(5);
+  if BinValueBytes[0] <> 29 then halt(5);
+  if BinValueBytes[1] <> 236 then halt(5);
+  if BinValueBytes[2] <> 175 then halt(5);
+
+  // widestring
+  // write 4 bytes into 1 byte
+  HexInLen := Length(HexInputW) * SizeOf(WideChar) div 4;
+
+(*
+  // Delphi: E2251 Ambiguous overloaded call to 'HexToBin'
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(@HexInputW[1], @BinValueBytes[0], BinBufLen);
+  if ret <> 3 then halt(6);
+  if BinValueBytes[0] <> 29 then halt(6);
+  if BinValueBytes[1] <> 236 then halt(6);
+  if BinValueBytes[2] <> 175 then halt(6);
+*)
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(7);
+  if BinValueBytes[0] <> 29 then halt(7);
+  if BinValueBytes[1] <> 236 then halt(7);
+  if BinValueBytes[2] <> 175 then halt(7);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(8);
+  if BinValueBytes[0] <> 29 then halt(8);
+  if BinValueBytes[1] <> 236 then halt(8);
+  if BinValueBytes[2] <> 175 then halt(8);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(9);
+  if BinValueBytes[0] <> 29 then halt(9);
+  if BinValueBytes[1] <> 236 then halt(9);
+  if BinValueBytes[2] <> 175 then halt(9);
+
+  // not fully valid widestring input
+  HexInLen := Length(HexCorruptInputW) * SizeOf(WideChar) div 4;
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(10);
+  if BinValueBytes[0] <> 154 then halt(10);
+  if BinValueBytes[1] <> 188 then halt(10);
+  if BinValueBytes[2] <> 222 then halt(10);
+  if BinValueBytes[4] <> 0 then halt(10);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(11);
+  if BinValueBytes[0] <> 154 then halt(11);
+  if BinValueBytes[1] <> 188 then halt(11);
+  if BinValueBytes[2] <> 222 then halt(11);
+  if BinValueBytes[4] <> 0 then halt(11);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(12);
+  if BinValueBytes[0] <> 154 then halt(12);
+  if BinValueBytes[1] <> 188 then halt(12);
+  if BinValueBytes[2] <> 222 then halt(12);
+  if BinValueBytes[4] <> 0 then halt(12);
+
+  {* test complex offset methods *}
+  // ansistring
+  HexInLen := Length(HexInputA) div 2;
+(*
+  // only available as PWideChar in newer Delphi
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputA), 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 0 then halt(13);
+  if BinValueBytes[0] <> 0 then halt(13);
+  if BinValueBytes[1] <> 0 then halt(13);
+  if BinValueBytes[2] <> 0 then halt(13);
+*)
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexInputA);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(14);
+  if BinValueBytes[0] <> 0 then halt(14);
+  if BinValueBytes[1] <> 0 then halt(14);
+  if BinValueBytes[2] <> 236 then halt(14);
+
+  // widestring
+  HexInLen := Length(HexInputW) div 2;
+(*
+  // only available as PWideChar in newer Delphi
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputW), 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(15);
+  if BinValueBytes[0] <> 0 then halt(15);
+  if BinValueBytes[1] <> 0 then halt(15);
+  if BinValueBytes[2] <> 236 then halt(15);
+*)
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexInputW);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(16);
+  if BinValueBytes[0] <> 0 then halt(16);
+  if BinValueBytes[1] <> 0 then halt(16);
+  if BinValueBytes[2] <> 236 then halt(16);
+
+  // documentation offset example
+  HexInLen := Length(HexOffsetInputW) * SizeOf(WideChar) div 4;
+(*
+  // only available as PWideChar in newer Delphi
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexOffsetInputW), 4, BinValueBytes, 0, BinBufLen);
+  if ret <> 2 then halt(17);
+  if BinValueBytes[0] <> 169 then halt(17);
+  if BinValueBytes[1] <> 117 then halt(17);
+  if BinValueBytes[2] <> 0 then halt(17);
+  if BinValueBytes[3] <> 0 then halt(17);
+*)
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexOffsetInputW);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 4, BinValueBytes, 0, BinBufLen);
+  if ret <> 2 then halt(18);
+  if BinValueBytes[0] <> 169 then halt(18);
+  if BinValueBytes[1] <> 117 then halt(18);
+  if BinValueBytes[2] <> 0 then halt(18);
+  if BinValueBytes[3] <> 0 then halt(18);
+
+  writeln('testing of HexToBin methods ended');
+end.

+ 229 - 0
tests/test/units/strutils/struth2bu.pp

@@ -0,0 +1,229 @@
+program HexToBin_tests;
+
+{$IFDEF FPC}
+  // PChar in Delphi is PWideChar so make sure the tests behave the same
+  {$mode DelphiUnicode}
+{$ENDIF}
+
+uses
+  SysUtils,
+  {$IFDEF FPC}
+    StrUtils
+  {$ELSE}
+    Classes
+  {$ENDIF};
+
+var
+  BinValueBytes: TBytes;
+  HexValueBytes: TBytes;
+  HexInLen, BinBufLen: Integer;
+  ret: Integer;
+
+const
+  HexInputA: AnsiString = '1decaf';
+  HexInputW: WideString = '1decaf';
+  HexCorruptInputW: WideString = '9abcdefg';
+  HexOffsetInputW: WideString = '608da975';
+
+begin
+  writeln('start testing of HexToBin methods');
+
+  {* test simple methods *}
+  // ansistring
+  // write 2 bytes into 1 byte
+  HexInLen := Length(HexInputA) * SizeOf(AnsiChar) div 2;
+
+(*
+  // Delphi: E2251 Ambiguous overloaded call to 'HexToBin'
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(@HexInputA[1], @BinValueBytes[0], BinBufLen);
+  if ret <> 3 then halt(1);
+  if BinValueBytes[0] <> 29 then halt(1);
+  if BinValueBytes[1] <> 236 then halt(1);
+  if BinValueBytes[2] <> 175 then halt(1);
+*)
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputA), PChar(BinValueBytes), BinBufLen);
+  if ret <> 0 then halt(2);
+  if BinValueBytes[0] <> 0 then halt(2);
+  if BinValueBytes[1] <> 0 then halt(2);
+  if BinValueBytes[2] <> 0 then halt(2);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(3);
+  if BinValueBytes[0] <> 29 then halt(3);
+  if BinValueBytes[1] <> 236 then halt(3);
+  if BinValueBytes[2] <> 175 then halt(3);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(4);
+  if BinValueBytes[0] <> 29 then halt(4);
+  if BinValueBytes[1] <> 236 then halt(4);
+  if BinValueBytes[2] <> 175 then halt(4);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PAnsiChar(HexInputA), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(5);
+  if BinValueBytes[0] <> 29 then halt(5);
+  if BinValueBytes[1] <> 236 then halt(5);
+  if BinValueBytes[2] <> 175 then halt(5);
+
+  // widestring
+  // write 4 bytes into 1 byte
+  HexInLen := Length(HexInputW) * SizeOf(WideChar) div 4;
+
+(*
+  // Delphi: E2251 Ambiguous overloaded call to 'HexToBin'
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(@HexInputW[1], @BinValueBytes[0], BinBufLen);
+  if ret <> 3 then halt(6);
+  if BinValueBytes[0] <> 29 then halt(6);
+  if BinValueBytes[1] <> 236 then halt(6);
+  if BinValueBytes[2] <> 175 then halt(6);
+*)
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(7);
+  if BinValueBytes[0] <> 29 then halt(7);
+  if BinValueBytes[1] <> 236 then halt(7);
+  if BinValueBytes[2] <> 175 then halt(7);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(8);
+  if BinValueBytes[0] <> 29 then halt(8);
+  if BinValueBytes[1] <> 236 then halt(8);
+  if BinValueBytes[2] <> 175 then halt(8);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexInputW), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(9);
+  if BinValueBytes[0] <> 29 then halt(9);
+  if BinValueBytes[1] <> 236 then halt(9);
+  if BinValueBytes[2] <> 175 then halt(9);
+
+  // not fully valid widestring input
+  HexInLen := Length(HexCorruptInputW) * SizeOf(WideChar) div 4;
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), PAnsiChar(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(10);
+  if BinValueBytes[0] <> 154 then halt(10);
+  if BinValueBytes[1] <> 188 then halt(10);
+  if BinValueBytes[2] <> 222 then halt(10);
+  if BinValueBytes[4] <> 0 then halt(10);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), Pointer(BinValueBytes), BinBufLen);
+  if ret <> 3 then halt(11);
+  if BinValueBytes[0] <> 154 then halt(11);
+  if BinValueBytes[1] <> 188 then halt(11);
+  if BinValueBytes[2] <> 222 then halt(11);
+  if BinValueBytes[4] <> 0 then halt(11);
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PWideChar(HexCorruptInputW), BinValueBytes, BinBufLen);
+  if ret <> 3 then halt(12);
+  if BinValueBytes[0] <> 154 then halt(12);
+  if BinValueBytes[1] <> 188 then halt(12);
+  if BinValueBytes[2] <> 222 then halt(12);
+  if BinValueBytes[4] <> 0 then halt(12);
+
+  {* test complex offset methods *}
+  // ansistring
+  HexInLen := Length(HexInputA) div 2;
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputA), 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 0 then halt(13);
+  if BinValueBytes[0] <> 0 then halt(13);
+  if BinValueBytes[1] <> 0 then halt(13);
+  if BinValueBytes[2] <> 0 then halt(13);
+
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexInputA);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(14);
+  if BinValueBytes[0] <> 0 then halt(14);
+  if BinValueBytes[1] <> 0 then halt(14);
+  if BinValueBytes[2] <> 236 then halt(14);
+
+  // widestring
+  HexInLen := Length(HexInputW) div 2;
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexInputW), 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(15);
+  if BinValueBytes[0] <> 0 then halt(15);
+  if BinValueBytes[1] <> 0 then halt(15);
+  if BinValueBytes[2] <> 236 then halt(15);
+
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexInputW);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 2, BinValueBytes, 2, BinBufLen);
+  if ret <> 2 then halt(16);
+  if BinValueBytes[0] <> 0 then halt(16);
+  if BinValueBytes[1] <> 0 then halt(16);
+  if BinValueBytes[2] <> 236 then halt(16);
+
+  // documentation offset example
+  HexInLen := Length(HexOffsetInputW) * SizeOf(WideChar) div 4;
+
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(PChar(HexOffsetInputW), 4, BinValueBytes, 0, BinBufLen);
+  if ret <> 2 then halt(17);
+  if BinValueBytes[0] <> 169 then halt(17);
+  if BinValueBytes[1] <> 117 then halt(17);
+  if BinValueBytes[2] <> 0 then halt(17);
+  if BinValueBytes[3] <> 0 then halt(17);
+
+  HexValueBytes := TEncoding.ASCII.GetBytes(HexOffsetInputW);
+  SetLength(BinValueBytes, HexInLen);
+  FillChar(BinValueBytes[0], Length(BinValueBytes), 0);
+  BinBufLen := Length(BinValueBytes);
+  ret := HexToBin(HexValueBytes, 4, BinValueBytes, 0, BinBufLen);
+  if ret <> 2 then halt(18);
+  if BinValueBytes[0] <> 169 then halt(18);
+  if BinValueBytes[1] <> 117 then halt(18);
+  if BinValueBytes[2] <> 0 then halt(18);
+  if BinValueBytes[3] <> 0 then halt(18);
+
+  writeln('testing of HexToBin methods ended');
+end.