HexVal: conversion from a string in hexadecimal format, e.g. 123abc, to eax/xmm0

Started by jj2007, February 12, 2024, 11:01:46 PM

Previous topic - Next topic

jj2007

The new HexVal macro accepts hexadecimal strings with or without a trailing h:
"123Abc"
"123ABCh"

Strings can be up to 32 characters long (or 33 with a trailing h).
- HexVal(string) returns a DWORD in eax
- HexVal(string, 64) returns a QWORD in xmm0
- HexVal(string, 128) returns QWORDs in xmm0 and xmm1

The algo is almost twice as fast as the Masm32 SDK hex2bin ("A high speed algorithm that will convert formated hex from the same format as bin2hex procedure output back to binary", \Masm32\help\masmlib.chm), and beats CRT sscanf by roughly a factor 17 :cool:

Example:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Let esi="D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"    ; IID_IWebBrowser2
  PrintLine "The GUID: ", esi
  void HexVal(Replace$(esi, "-", 0), 128)
  PrintLine "The GUID: ", Mid$(Hex$(xmm1), 19), "  ", Mid$(Hex$(xmm0), 19)
  PrintLine "HexVal(1234)=  ", Tb$, Hex$(HexVal("1234"))
  PrintLine "HexVal(1234AbCd)=", Tb$, Hex$(HexVal("1234AbCdh"))
  PrintLine "HexVal(1234AbCdef987654)=", Hex$(HexVal("1234AbCdef987654", 64))
EndOfCode

Output:
The GUID: D30C1661-CDAF-11D0-8A3E-00C04FC9E26E
The GUID: D30C1661 CDAF11D0  8A3E00C0 4FC9E26E
HexVal(1234)=           00001234
HexVal(1234AbCd)=       1234ABCD
HexVal(1234AbCdef987654)=00000000 00000000 1234ABCD EF987654

Building the attached project requires MasmBasic version 12 Feb 2024

NoCforMe

Quote from: jj2007 on February 12, 2024, 11:01:46 PMThe new HexVal macro accepts hexadecimal strings with or without a trailing h:
"123Abc"
"123ABCh"
Hate to nitpick, Jochen, but what if you pass "1234"?

Oh, I guess a little ambiguity never hurts ...
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on February 12, 2024, 11:04:29 PMHate to nitpick, Jochen, but what if you pass "1234"?

See above, it's in the example posted. In contrast to Val(), which is an allrounder that recognises most numeric formats - see below, HexVal expects a hexadecimal string of length 0 to 33 (if there is a trailing "h").

    mov eax, Val(Chr$("123"))    ; eax=123, edx=3
    mov eax, Val("123")    ; eax=123, edx=3
    mov esi, Chr$(9, "    12345")    ; eax=12345, edx=9 (5 plus a tab and three spaces)
    mov ebx, Val(esi)
    mov ebx, Val("12345h")    ; hex
    mov ebx, Val("0x12345")    ; hex, C notation
    mov ebx, Val("$12345")    ; hex, leading $ notation
    mov ebx, Val("10101b")    ; binary
    mov ebx, Val("12:34:56", 3)    ; take the third value, e.g. 56 seconds

TimoVJL

Quote from: jj2007 on February 12, 2024, 11:01:46 PMThe algo is almost twice as fast as the Masm32 SDK hex2bin ("A high speed algorithm that will convert formated hex from the same format as bin2hex procedure output back to binary", \Masm32\help\masmlib.chm), and beats CRT sscanf by roughly a factor 17 :cool:
sscanf is versatile function, old beast, like a your Val, but it have far more users.
May the source be with you

jj2007

Quote from: TimoVJL on February 13, 2024, 12:59:43 AMsscanf is versatile function

include \masm32\include\masm32rt.inc

.data
v1 db "12345", 0
v2 db "12345h", 0
v3 db "0x12345", 0
v4 db "$12345", 0
dest dd 0

.code
start:
  invoke crt_sscanf, addr v1, chr$("%x"), addr dest
  print hex$(dest), 9, "v1", 13, 10
  invoke crt_sscanf, addr v2, chr$("%x"), addr dest
  print hex$(dest), 9, "v2", 13, 10
  invoke crt_sscanf, addr v3, chr$("%x"), addr dest
  print hex$(dest), 9, "v3", 13, 10
  invoke crt_sscanf, addr v4, chr$("%x"), addr dest
  print hex$(dest), 9, "v4", 13, 10
  inkey " "
  exit
end start

In contrast to Val/MovVal, sscanf needs to be told what format to convert. So it's on par with the new HexVal macro, only a factor 17 slower.

TimoVJL

OK.
C++ / C# functions can also do those type specific conversion.
Sadly i just don't know, what they are.
May the source be with you

jj2007

This snippet shows the conversion from a string in hexadecimal format to a number:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Print "Source$ (bytes)"
  PrintLine At(61) "Result in xmm0"
  Let edi="11aBeF1122aBeF2233aBeF3344aBeF44h"    ; 32+h=33 bytes
  .Repeat
        Print Str$("(%_i) ", Len(edi)), edi
        PrintLine At(40) Hex$(HexVal(edi, 128))    ; use full 128 bits
        Let edi=Mid$(edi, 2)
  .Until Len(edi)<1
EndOfCode

The output:

Source$ (bytes)                                              Result in xmm0
(32) 11aBeF1122aBeF2233aBeF3344aBeF44   11ABEF11 22ABEF22 33ABEF33 44ABEF44
(31) 1aBeF1122aBeF2233aBeF3344aBeF44     1ABEF11 22ABEF22 33ABEF33 44ABEF44
(30) aBeF1122aBeF2233aBeF3344aBeF44       ABEF11 22ABEF22 33ABEF33 44ABEF44
(29) BeF1122aBeF2233aBeF3344aBeF44         BEF11 22ABEF22 33ABEF33 44ABEF44
(28) eF1122aBeF2233aBeF3344aBeF44           EF11 22ABEF22 33ABEF33 44ABEF44
(27) F1122aBeF2233aBeF3344aBeF44             F11 22ABEF22 33ABEF33 44ABEF44
(26) 1122aBeF2233aBeF3344aBeF44               11 22ABEF22 33ABEF33 44ABEF44
(25) 122aBeF2233aBeF3344aBeF44                 1 22ABEF22 33ABEF33 44ABEF44
(24) 22aBeF2233aBeF3344aBeF44                    22ABEF22 33ABEF33 44ABEF44
(23) 2aBeF2233aBeF3344aBeF44                      2ABEF22 33ABEF33 44ABEF44
(22) aBeF2233aBeF3344aBeF44                        ABEF22 33ABEF33 44ABEF44
(21) BeF2233aBeF3344aBeF44                          BEF22 33ABEF33 44ABEF44
(20) eF2233aBeF3344aBeF44                            EF22 33ABEF33 44ABEF44
(19) F2233aBeF3344aBeF44                              F22 33ABEF33 44ABEF44
(18) 2233aBeF3344aBeF44                                22 33ABEF33 44ABEF44
(17) 233aBeF3344aBeF44                                  2 33ABEF33 44ABEF44
(16) 33aBeF3344aBeF44                                     33ABEF33 44ABEF44
(15) 3aBeF3344aBeF44                                       3ABEF33 44ABEF44
(14) aBeF3344aBeF44                                         ABEF33 44ABEF44
(13) BeF3344aBeF44                                           BEF33 44ABEF44
(12) eF3344aBeF44                                             EF33 44ABEF44
(11) F3344aBeF44                                               F33 44ABEF44
(10) 3344aBeF44                                                 33 44ABEF44
( 9) 344aBeF44                                                   3 44ABEF44
( 8) 44aBeF44                                                      44ABEF44
( 7) 4aBeF44                                                        4ABEF44
( 6) aBeF44                                                          ABEF44
( 5) BeF44                                                            BEF44
( 4) eF44                                                              EF44
( 3) F44                                                                F44
( 2) 44                                                                  44
( 1) 4                                                                    4

The new HexVal macro comes in three flavours:

  PrintLine " 32 bits: ", Hex$(HexVal("123abc"))  ; HexVal returns the number in eax
  PrintLine " 64 bits: ", Hex$(HexVal("12345678abcdef", 64))  ; HexVal returns the number in xmm0
  PrintLine "128 bits: ", Hex$(HexVal("1111aBeF2222aBeF3333aBeF4444aBeF", 128))  ; HexVal returns xmm0

As demonstrated in The Lab, HexVal is almost twice as fast as the Masm32 SDK hex2bin function, and it beats CRT sscanf (i.e. the Masm32 SDK a2ud macro) by a factor 17.

Source & exe attached, requires MasmBasic 14 Feb 2024