Skip to content

Commit

Permalink
Fix ACE_HexTools.HexStrToInt to support any length hex strings
Browse files Browse the repository at this point in the history
EntityIDs are constructed from Low and high 32-bit IDs, the original code here didn't account for entities that have a high ID of zero, and values that were less then 8 characters long.

This new implementation removes the float math and uses bitwise operations to correctly convert to the expected array format in the correct byte order with no length limitations for the input.
  • Loading branch information
gnif authored Jan 18, 2025
1 parent 615fc57 commit 352c4de
Showing 1 changed file with 38 additions and 44 deletions.
82 changes: 38 additions & 44 deletions addons/core/scripts/Game/ACE_Core/Global/ACE_HexTools.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,58 @@ class ACE_HexTools
{
protected static int s_iAscii0 = "0".ToAscii();
protected static int s_iAscii9 = "9".ToAscii();
protected static int s_iAsciiA = "A".ToAscii();
protected static int s_iAsciiF = "F".ToAscii();
protected static int s_iAsciiLoA = "a".ToAscii();
protected static int s_iAsciiLoF = "f".ToAscii();

protected static int s_iAsciiA = "a".ToAscii();
protected static int s_iAsciiF = "f".ToAscii();

//------------------------------------------------------------------------------------------------
//! Gets int values of hexadecimal string. Expected to be prefixed with "0x"
//! Ordered by most significant bits
static array<int> HexStringToInt(string hexString)
{
if (hexString.Substring(0, 2) != "0x")
return {};

int numHexChars = hexString.Length() - 2;
if (!float.AlmostEqual(Math.Mod(numHexChars, 8), 0))
hexString.TrimInPlace();
hexString.ToLower();
if (!hexString.StartsWith("0x"))
return {};

hexString = hexString.Substring(2, numHexChars);

int numBit32 = (hexString.Length()) / 8;
array<int> result = {};
result.Reserve(numBit32);
int nibbles = hexString.Length() - 2;
int values = ((nibbles + 7) & ~7) / 8;
result.Reserve(values);

for (int i_bit32 = 0; i_bit32 < numBit32; i_bit32++)
int byte = 0;
int value = 0;
int count = 0;
while(nibbles > 0)
{
int bit32;
int nibble = hexString.Get(nibbles + 1).ToAscii();

if (nibble >= s_iAscii0 && nibble <= s_iAscii9)
nibble -= s_iAscii0;
else
if (nibble >= s_iAsciiA && nibble <= s_iAsciiF)
nibble -= s_iAsciiA - 10;
else
return {}; //invalid character in string

value <<= 4;
value |= nibble;
--nibbles;

for (int i_bit4 = 8 * i_bit32; i_bit4 < 8 * (i_bit32 + 1); i_bit4++)
if (++count == 8 || nibbles == 0)
{
int bit4 = HexCharToInt(hexString, index: i_bit4);
if (bit4 < 0)
return result;
int rev = 0;
for(int i = 0; i < count; ++i)
{
rev = (rev << 4) + (value & 0xf);
value >>= 4;
}

bit32 = 16 * bit32 + bit4;
}

result.Insert(bit32);
result.InsertAt(rev, --values);
value = 0;
count = 0;
}
}

return result;
}

//------------------------------------------------------------------------------------------------
//! Gets int value of a character in a hexadecimal string
//! Returns -1 if parsing failed
//! \param index Index of the character, 0 by default.
static int HexCharToInt(string hexString, int index = 0)
{
int value = hexString.ToAscii(index);
if (value >= s_iAscii0 && value <= s_iAscii9)
value -= s_iAscii0;
else if (value >= s_iAsciiA && value <= s_iAsciiF)
value -= s_iAsciiA - 10;
else if (value >= s_iAsciiLoA && value <= s_iAsciiLoF)
value -= s_iAsciiLoA - 10;
else
return -1;

return value;
}
}

0 comments on commit 352c4de

Please sign in to comment.