Link to home
Start Free TrialLog in
Avatar of khilles
khilles

asked on

Dword and Qword in PHP

I'm working on an application to decode a BigEndian transmission used for GPS tracking. The problem is that I need to convert a Hex string to a Dword Decimal.

For instance, the following is received in Hex: "CD 26 BC A7" and I need to create a PHP function to convert it to "-853099353".

You can do this in Windows Calculator by:
- Click on View -> Programmer
- Click on Hex
- Enter "CD26BCA7"
- Click on Dec
- Click on Dword

I can get PHP to convert to the Decimal part (3441867943) using HEXDEC but can't do the last step to convert it to Dword.

The calculator implies that I could do it by prepending 8 "F"s in the front but that doesn't seem to work.

Any ideas?

Thanks so much!!
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

This illustrates what you're up against.  When the number overflows the maximum integer values, PHP uses float numbers.

I'll see if I can figure something out.
<?php // RAY_temp_khilles.php
error_reporting(E_ALL);

// TEST DATA
$hex = 'CD 26 BC A7';

// FIX THE TEST DATA
$hex = str_replace(' ', NULL, $hex);

// CONVERT THE DATA
$num = hexdec($hex);
var_dump($num);

// TRY A DIFFERENT WAY
$hex = 'FFFFFFFF' . $hex;

// CONVERT THE DATA
$num = hexdec($hex);
var_dump($num);

Open in new window

This gets closer.
<?php // RAY_temp_khilles.php
error_reporting(E_ALL);

// TEST DATA
$hex = 'CD26BCA7';
$dwo = '-853099353';

// TRY A DIFFERENT WAY
$hex = 'FFFFFFFF' . $hex;

// CONVERT THE DATA USING INTVAL
$num = intval(hexdec($hex));
var_dump($num); // PRINTS -853098496

// THIS DOES NOT PRINT
if ($num == $dwo) echo "SUCCESS";

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of khilles
khilles

ASKER

Very Awesome, works great. Thanks so much!!!
You're welcome and thanks for the points.  Here is the generalized teaching example.  All the best, ~Ray
<?php // RAY_twos_complement.php
error_reporting(E_ALL);
echo "<pre>";


// A FUNCTION TO GET THE TWO'S COMPLEMENT INTEGER DECIMAL VALUE FROM A HEX STRING
// THE ZERO-POSITION BIT IN THE HEX STRING IS USED AS THE SIGN BIT


function hexDword($hex, $len=8)
{
    // ENSURE WE HAVE A USABLE INPUT
    $num = hexdec($hex);
    $int = intval($num);
    if ($num !== $int) return "ERROR: VALUES OUT OF RANGE";
    if (strlen($hex) > $len) return "ERROR: INCOMPATIBLE LENGTH";
    if ($len > 16) return "ERROR: LENGTH MUST BE 16 OR LESS";

    // COMPUTE THE MAX VALUE FOR A HEX STRING OF THIS LENGTH
    $str = str_pad('7', $len, 'F', STR_PAD_RIGHT);
    $max = hexdec($str);

    // PAD TO THE CORRECT NUMBER OF HEX DIGITS
    $hex = str_pad($hex, $len, '0', STR_PAD_LEFT);

    // DETERMINE THE SIGN BIT
    $bin = base_convert($hex, 16, 2);
    $bin = str_pad($bin, $len*4, '0', STR_PAD_LEFT);
    $arr = str_split($bin);
    $neg = FALSE;
	if ($arr[0] == '1') $neg = TRUE;

    // RESET THE SIGN BIT TO ZERO
    unset($arr[0]);
    $bin = '0' . implode(NULL, $arr);

    // CONVERT TO DECIMAL
    $ans = base_convert($bin, 2, 10);

    // IF NEGATIVE, USE TWOS-COMPLEMENT
    if ($neg)
    {
        $ans = $ans - $max - 1;
    }
    return $ans;
}



// GENERALIZED TEST CASES
$hexs
= array
( '7FFFFFFF'
, '9'
, '10'
, '111'
, 'C'
, 'FFFFFFFD'
, 'FFFFFFFF'
, '0'
)
;

foreach ($hexs as $hex)
{
    $new = hexDword($hex);
    echo PHP_EOL . "$hex = $new";
}

// ANOTHER TEST WITH SHORT HEX STRINGS
$hexs
= array
( '7F'
, 'FF'
, 'FE'
, 'FD'
, '80'
, '10'
, 'C'
, '0'
)
;

foreach ($hexs as $hex)
{
    $new = hexDword($hex, 2);
    echo PHP_EOL . "$hex = $new";
}


// ANOTHER TEST WITH MEDIUM HEX STRINGS
$hexs
= array
( '7FFF'
, 'FFFF'
, 'FFFE'
, 'FFFD'
, '8000'
, '10'
, 'C'
, '0'
)
;

foreach ($hexs as $hex)
{
    $new = hexDword($hex, 4);
    echo PHP_EOL . "$hex = $new";
}

Open in new window