Jump to content

Any clever way to convert hex to uint64 (and beyond)? (Any UDF that does it?) [SOLVED]


Irios
 Share

Recommended Posts

Searching and searching but I'm unable to find anyone with a proper solution. I see a lot of similar questions on this topic, but nothing that really provides what I'm looking for.

Basically, I just want to convert a 8 byte hex value to unsigned integer. I.e. "FFFFFFFFFFFFFFFF". I'm working on SNMP opaque data types, and UINT64 values end up as signed INT64 when I use the internal processing of AutoIt. (Yeah, I know, this is because AutoIt always uses signed)

 

Example ( I know you guys love example code snippets haha, so here's a two-liner):

 

$sUINT64 = "FFFFFFFFFFFFFFFF"

ConsoleWrite( Dec($sUINT64) )

-1 is not the result I want, of course.

 

And I don't want "1.84467440737096e+019" either by adding manually in AutoIt. I need the decimal value (as a string) of 264 = 18,446,744,073,709,551,616

 

Anyone got a clever UDF for this? Or will I have to write one myself, adding and multiplying each hex value, and generating a text string as a result? :) I know how it can be done, I just hoped someone already had done it so I could steal their code. :D

 

Edited by Irios
solved!

863nP4W.png discord.me/autoit  (unofficial)

Link to comment
Share on other sites

Thank you both :)

 

EDIT: Again, thanks @Tekk. It was horribly difficult to search for these things without really knowing what to look for. But with the DllCall example, it opened a whole new world to me, as I never realized you could do it that way. I even found ways to convert int to float now, and int64 to double. (

)

Edited by Irios

863nP4W.png discord.me/autoit  (unofficial)

Link to comment
Share on other sites

A little trick I discovered. I think the fastest way to convert Int64 to double is to concatenate and execute.

$iInt = 12345678901234567
$fFloat = Execute($iInt & '.0')
MsgBox(0, "", $fFloat)


Edit: Hmm division by 1 should be faster.

$iInt = 12345678901234567
MsgBox(0, "", $iInt/1)

 

Edited by czardas
Link to comment
Share on other sites

18 minutes ago, czardas said:

Hmm division by 1 should be faster

Hmmm, multiplication by 1.0 should be faster than division (in FPU assembly at least).^_^

$iInt = 12345678901234567
MsgBox(0, "", $iInt*1.0)

 

Edited by RTFC
Link to comment
Share on other sites

Interesting thing is that AutoIt returns always an signed value. Is this a bug?

 

Global $s1 = "FFFFFFFFFFFFFFFF"
Global $s2 = "FFFFFFFFFFFFFFF0"

ConsoleWrite(_HexString2Uint64($s1) & @CRLF)
ConsoleWrite(_HexString2Uint64($s2) & @CRLF)

Func _HexString2Uint64($sHex)
    Local $b = Binary("0x" & $sHex)
    Local $tStruct =  DllStructCreate("UINT64")
    Local $tStruct2 = DllStructCreate("byte[8]", DllStructGetPtr($tStruct))
    DllStructSetData($tStruct2, 1, $b)
    Return DllStructGetData($tStruct, 1)
EndFunc

 

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

@RTFC Now I know why I went the root I did. Compare:

MsgBox(0, "", '123456789012345678901234567890'*1.0)
MsgBox(0, "", Execute('123456789012345678901234567890' & '.0'))

The second method works for a few hundred digits and the first method quickly hits a brick wall.

Edited by czardas
Link to comment
Share on other sites

Compare like with like:

MsgBox(0, "", '123456789012345678901234567890.0'*1.0)
MsgBox(0, "", Execute('123456789012345678901234567890' & '.0'))

 

Link to comment
Share on other sites

On 29/09/2016 at 0:27 PM, funkey said:

Interesting thing is that AutoIt returns always an signed value. Is this a bug?

No, it's not a bug. AutoIt always uses signed int 64. That's what my original post was about: how to get around this limitation.

I could not figure out a way to use DllCall, DllStructCreate, DllStructSetData, DllStructGetData. All the solutions/examples I found uses integers as paramteres, and won't work because AutoIt uses signed integers.

Maybe someone has a way to do it?

 

This is the solution I ended up using in my script as of today... Not very elegant, but it works. Can easily be extended beyond 64 bit if you need to.

; v1.0  2016.09.29  Handles hex strings up to 16 characters in length i.e. "FFFFFFFFFFFFFFFF". Outputs a string representing the integer.
; Example: HexToUnsigned64("FFFFFFFFFFFFFFFF")
Func HexToUnsigned64($_HexString)   
    
    ; quick check to make sure it's a string, and 16 characters or shorter
    If (VarGetType($_HexString)<>"String") Or (StringLen($_HexString)>16) Then Return -1        

    ; Check to see if the value is within signed 64 bit. If so we just return the value immediately... 
    ; We pad with zeros to get the correct length of 8 bytes (total 16 characters). 
    ; Then we check to see if the the value is higher than 7FFFFFFFFFFFFFFFh (max positive value for signed 64 bit)
    If (StringLen($_HexString)<=16) Then                                    
        $_HexString = StringFormat("%016s", $_HexString)                    
        If (Dec(StringLeft($_HexString,1))<8) Then Return Dec($_HexString)
    EndIf

    ; this is value of the leftmost 64th bit in an unsigned int 64. It must be a string, of course,
    ; as AutoIt only uses signed 64 bit integers.
    Local Const $_UINT64 = "9223372036854775808"        

    ; we remove the highest bit so we can convert the other 63 bits internally
    $_iTmp = Dec(StringLeft($_HexString,1)) - 8         
    
    ; build a new 63bit integer string (without the highest bit)
    $_HexString = $_iTmp & StringRight($_HexString,15)  
    $_HexString = String(Dec($_HexString))
    
    ; padding input string with zeros so both become the same length (19 digits)
    $_HexString = StringFormat("%019s", $_HexString)    

    Local $co = 0, $addReturn = ""
    ; starting at the far right side, max ops is 19 digits (number of digits in $_UINT64)
    For $A = 19  To 1 Step -1                                                                                   
        ; building the return string, from the right-most side
        $addReturn = Mod( ( StringMid($_UINT64,$A,1) + StringMid($_HexString,$A,1) + $co), 10) & $addReturn     
        ; getting the carry-over for the next loop
        $co = Int(( StringMid($_UINT64,$A,1) + StringMid($_HexString,$A,1) + $co ) / 10)                        
    Next

    If $co = 0 Then $co = ""
    Return $co & $addReturn ; all done, and returns the final value as a string

EndFunc

 

Example use:

$sResult = HexToUnsigned64("FFFFFFFFFFFFFFFF")
ConsoleWrite($sResult & @CRLF)

...the output is "18446744073709551615"

 

Edited by Irios
words and letters

863nP4W.png discord.me/autoit  (unofficial)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...