powershelltype-conversionhexpowershell-4.0

Convert byte array (hex) to signed Int


I am trying to convert a (variable length) Hex String to Signed Integer (I need either positive or negative values).

[Int16] [int 32] and [int64] seem to work fine with 2,4+ byte length Hex Strings but I'm stuck with 3 byte strings [int24] (no such command in powershell).

Here's what I have now (snippet):

$start = $mftdatarnbh.Substring($DataRunStringsOffset+$LengthBytes*2+2,$StartBytes*2) -split "(..)"
[array]::reverse($start)
$start = -join $start

if($StartBytes*8 -le 16){$startd =[int16]"0x$($start)"}
elseif($StartBytes*8 -in (17..48)){$startd =[int32]"0x$($start)"}
else{$startd =[int64]"0x$($start)"}

With the above code, a $start value of "D35A71" gives '13851249' instead of '-2925967'. I tried to figure out a way to implement two's complement but got lost. Any easy way to do this right?

Thank you in advance

Edit: Basically, I think I need to implement something like this:
int num = (sbyte)array[0] << 16 | array[1] << 8 | array[2];
as seen here.

Just tried this:

$start = "D35A71"
[sbyte]"0x$($start.Substring(0,2))" -shl 16 -bor "0x$($start.Substring(2,2))" -shl 8 -bor "0x$($start.Substring(4,2))"

but doesn't seem to get the correct result :-/


Solution

  • To parse your hex.-number string as a negative number you can use [bigint] (System.Numerics.BigInteger):

    # Since the most significant hex digit has a 1 as its most significant bit
    # (is >= 0x8), it is parsed as a NEGATIVE number.
    # To force unconditional interpretation as a positive number, prepend '0'
    # to the input hex string.
    PS> [bigint]::Parse('D35A71', 'AllowHexSpecifier')
    -2925967
    

    You can cast the resulting [bigint] instance back to an [int] (System.Int32).

    Note:

    See the docs for details about the parsing logic.


    Examples:

    # First digit (7) is < 8 (high bit NOT set) -> positive number
    [bigint]::Parse('7FF', 'AllowHexSpecifier') # -> 2047
    
    # First digit (8) is >= 8 (high bit IS SET) -> negative number
    [bigint]::Parse('800', 'AllowHexSpecifier') # -> -2048
    
    # Prepending additional 'F's to a number that parses as 
    # a negative number yields the *same* result
    [bigint]::Parse('F800', 'AllowHexSpecifier') # -> -2048
    [bigint]::Parse('FF800', 'AllowHexSpecifier') # -> -2048
    # ...
    
    # Starting the hex-number string with '0' 
    # *unconditionally* makes the result a *positive* number
    [bigint]::Parse('0800', 'AllowHexSpecifier') # -> 2048