I can't find a matching function in Godot.
Anyway, we are going to build an PoolByteArray from the hex input (so we are not doing a bunch of String concatenations). We could get an String from it, but… Well, we will get to that.
The plan would be to take two by two of characters of the input string, interpret them as hexadecimal, and write them to the result in the appropriate position.
We are going to need to have two lengths:
- The length of the the input
String, which I'll call hex_length.
- The length of the result
PoolByteArray, which I'll call byte_length.
We can get hex_length like this:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
So we will compute byte_length from it by dividing by two:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
var byte_length := hex_length / 2
Oh, a warning! This is an integer division and we could be losing precision… Well, if hex_length is not even, we are in trouble. I don't know how you want to handle that case, I'll just push an error and suppress the warning:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
Note: You can also check is_valid_hex_number.
And we can go ahead and allocate the result:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
Similarly to the two lengths, we will have two position:
- The position on the input
String, which I'll call hex_index.
- The position on the result
PoolByteArray, which I'll call byte_index.
Now, I have a choice about what do I want to iterate over… If I iterate over the input String I need skip each other number (I only want the even numbers). So it is easier for me to iterate over the result PoolByteArray.
Thus, I will iterate with byte_index and compute hex_index from it like this: hex_index = byte_index * 2.
Well, actually like this: hex_index = ìnt(byte_index) * 2. Because sadly the variable on the loop does not have an static type, and I like static types.
That looks like this:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
for byte_index in byte_length:
var hex_index := int(byte_index) * 2
Now we get the two hex characters with substr:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
for byte_index in byte_length:
var hex_index := int(byte_index) * 2
var hex_couple := hex.substr(hex_index, 2)
And, a bit inconvenient, the function to convert hex to integer requires a "0x" prefix, so let us do that:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
for byte_index in byte_length:
var hex_index := int(byte_index) * 2
var hex_couple := hex.substr(hex_index, 2)
var hex_value := ("0x" + hex_couple).hex_to_int()
And that is what we need to write in the result:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
for byte_index in byte_length:
var hex_index := int(byte_index) * 2
var hex_couple := hex.substr(hex_index, 2)
result[byte_index] = ("0x" + hex_couple).hex_to_int()
Oh, right, and return:
func hex_to_byte_array(hex:String) -> PoolByteArray:
var hex_length := hex.length()
if hex_length % 2 == 1:
push_error("Not even length hex input")
return PoolByteArray()
# warning-ignore:integer_division
var byte_length := hex_length / 2
var result := PoolByteArray()
result.resize(byte_length)
for byte_index in byte_length:
var hex_index := int(byte_index) * 2
var hex_couple := hex.substr(hex_index, 2)
result[byte_index] = ("0x" + hex_couple).hex_to_int()
return result
And if want an String, you could do this:
func hex_to_string(hex:String) -> String:
return hex_to_byte_array(hex).get_string_from_ascii()
Except that is not good. For, you see, the example input you have provided starts with 00, so a null terminated String ends there. So I hope you are OK working with the PoolByteArray instead.
By the way, for testing I made a method that iterates over the PoolByteArray and build an escaped String:
func hex_test(hex:String) -> String:
var result := ""
for code in hex_to_byte_array(hex):
var tmp := PoolByteArray([code])
if code >= 32 and code <= 126:
var s := tmp.get_string_from_ascii()
result += s
else:
result += "\\x" + tmp.hex_encode()
return result
So this:
print (hex_test("000100007AD59C7918B839F02C8483CFEA1ECBDA"))
Outputs this:
\x00\x01\x00\x00z\xd5\x9cy\x18\xb89\xf0,\x84\x83\xcf\xea\x1e\xcb\xda
Which matches the example in the question.